openbakery / gradle-xcodePlugin

gradle plugin for building Xcode Projects for iOS, watchOS, macOS or tvOS
Apache License 2.0
457 stars 129 forks source link

Issues signing with keychain file #352

Closed adil-hussain-84 closed 2 years ago

adil-hussain-84 commented 7 years ago

I can see from the recommendation here that signing with the certificateURI and certificatePassword parameters is preferred over signing with the keychain and keychainPassword parameters. I have an existing keychain file however which is shared and used across multiple projects and it would be great to sign by means of this keychain file rather than exporting the certificates contained within it out to separate p12 files (and thus duplicating my certificates).

I have tried specifying the identity, keychain (file location) and keychainPassword parameters in my signing block but I am finding that the gradle package commands only works if I manually add the keychain file to Keychain Access before running the gradle package command. Is this by design? It would be great if I did not have to add the keychain file to Keychain Access since I want this to run seamlessly on multiple development machines as well as on a build server.

I'm also finding that on adding the keychain file to Keychain Access, it is removed during the process of executing the gradle package command.

phatblat commented 7 years ago

I've had similar issues, but in my case the keychain was already added to Keychain Access. After the build I found that the pre-existing keychain had been removed from Keychain Access, but was still on the filesystem. The following builds had trouble with the keychain not being present in Keychain Access.

I suspect the keychain removal is happening because that is the desired behavior when using a certificate file since the plugin creates a temporary keychain for each build.

adil-hussain-84 commented 7 years ago

@phatblat: Did you continue using the keychain/keychainPassword parameters for your builds or did you move to using the certificateURI/certificatePassword parameters?

phatblat commented 7 years ago

@adil-hussain-84 The build using this plugin is still in development, so we've left it using the keychain parameter. We're debating over switching to using certificates as we may be using VM Jenkins nodes. If we don't I would like to see the keychain approach work better and may end up contributing a PR.

renep commented 7 years ago

The reason that the build does create a own keychain and adds the certificates and removes it at the end is a quite simple one: If you use only the login keychain and have several certificates in it, than it is not guaranteed that the correct certificate is used for signing. The build process picks the first one that matches. Another problem is that the codesign command needs access and the first time a popup is presented. That is very anoying on a CI Build node.

So the plugin is designed, so that every build generates it's own keychain for every build. Only the certificates that are needed are imported. After the build is done, the keychain then is removed, to avoid conflicts with other build. Also I only create the keychain only when this is really needed, so prio to the package task.

I have tried specifying the identity, keychain (file location) and keychainPassword parameters in my signing block but I am finding that the gradle package commands only works if I manually add the keychain file to Keychain Access before running the gradle package command. Is this by design? It would be great if I did not have to add the keychain file to Keychain Access since I want this to run seamlessly on multiple development machines as well as on a build server.

The build should add the the generated keychain to the keychain. Is is the intended behavior. You can try to run the keychainCreate task and see if the keychain is generated and added to the keychain. Running with "--debug" is also an option, because you see all the command line commands that are executed and maybe see whats wrong. Otherwise you can send me the log that I have a look.

BTW. I use the gradle plugin to build several iOS projects for quite some time now. (Not weeks or month, I mean years 😉 ) I use it to build the app on the developer machine, but also on a CI Server. The CI Server also creates the AppStore builds and uploads these to Apple.

adil-hussain-84 commented 7 years ago

Thanks for the responses @renep and @phatblat.

The ideal scenario for me would be the ability to use an existing keychain file which only contains certificates for app signing (i.e. not the login keychain), which lives local to the project (as a Git submodule or by some other such means) and which does not needed to be added to Keychain Access manually before running the gradle archive package command. This pre-existing keychain file would then be used instead of the one that is generated when specifying the certificateURI and certificatePassword parameters.

The above is how I was expecting the plugin to behave when specifying the keychain and keychainPassword parameters. In the absence of this, I will revert to using the certificateURI and certificatePassword parameters as preferred by the plugin.

renep commented 7 years ago

I'm wondering what the advantage would be using a keychain file, instead of the certificate+password.

adil-hussain-84 commented 7 years ago

The advantage for my workplace would be the ability to use an existing keychain file which contains multiple signing certificates and which is shared across multiple projects (only some of which uses this Gradle plugin). Would be great just to specify the identity + keychain (file location) + keychainPassword in the project's buld.gradle file and for this keychain file to be added/remove to/from Keychain Access rather than a new keychain file being created and added/removed to/from Keychain Access. If this is not straightforward to do or not the direction you want to go with this plugin then I will resort to exporting all of the certificates in my keychain file out to separate p12 files.

renep commented 7 years ago

Hmm, I had a quick look in the code, and I think could be an easy one to achieve. If the keychain value was already set with the value provided by xcodebuild.signing.keychain (that was set in line 101) then do not override it here: https://github.com/openbakery/gradle-xcodePlugin/blob/develop/plugin/src/main/groovy/org/openbakery/packaging/PackageTask.groovy#L103

AyalCiobotaru commented 7 years ago

I'm having some similar issues with keychain access and signing. My build.gradle looks like this:

xcodebuild {
    target = targetToRun
    scheme = schemeToRun

    type = "iOS"
    configuration = 'Release'
    simulator = false

    signing {
        certificateURI = "file:///$certFile"
        certificatePassword = certFilePass
        mobileProvisionURI = "file:///$provisionFile"

    }
}

When running from command line with build.gradle, archive and package work fine after allowing access to the keychain by hitting "always allow". However when building it from jenkins, I get the following error:

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':package'.
> Command failed to run (exit code 1): '/usr/bin/codesign --force --sign 63D66B0F2E893C10900892B5D6CEA2AC3868BAF2 --verbose /Developer/jenkinsJobs/Development/build/package/Payload/mProject.app/Frameworks/libswiftCore.dylib --keychain /Developer/jenkinsJobs/Development/build/codesign/gradle-1503340625237.keychain'
  Tail of output:
  /Developer/jenkinsJobs/Development/build/package/Payload/myProject.app/Frameworks/libswiftCore.dylib: replacing existing signature
  /Developer/jenkinsJobs/Development/build/package/Payload/myProject.app/Frameworks/libswiftCore.dylib: unknown error -1=ffffffffffffffff

Any ideas?

phatblat commented 7 years ago

@AyalCiobotaru I've seen this issue with using older (created on macOS El Capitan), existing keychains on Sierra. Not sure if it's related to the new .keychain-db files or the new security set-key-partition-list settings, but the solution to the latter only worked for me half the time.

I highly recommend using a .p12 file exported from your keychain and letting this plugin create a temporary keychain with its contents. It's much more dependable and works better with cloud/VM build servers.

See the Xcode plugin signing configuration for syntax (certificateURI & certificatePassword).

renep commented 7 years ago

Yes, exporting certificate to a .p12 is the recommended way. The plugin was designed this way to use the certificate from the specified .p12 and provisioning, and all other provisioning profiles and certificates from the keychain are ignored.

AyalCiobotaru commented 7 years ago

Hey guys, thanks for the response, however I am doing it the way you recommended.

I've exported the .p12 certificate, with a password and passed the URI and password to the plugin. When running this from the command line it works but from Jenkins it does not. It might be worth mentioning (although you might already know) that Jenkins is a separate User on my machine. However, running the Gradle tasks from the command line on the Jenkins user works as well.

renep commented 7 years ago

This looks more like a Jenkins issue. I have not used Jenkins for quite some time (I have ditched it 3 years ago) The last time I have used Jenkins, the agent that was executing the task was logged as user. Also I have used the webstart slave agent.

You could also enable --debug to see what the plugin does.