While working on the RoomKeeper app, we wanted to try out XCTestParametrizedMacro to parametrize a few test methods in unit tests. It was quite easy to build locally, but we encountered a small problem building it on Xcode Cloud.
Integrating any third-party macro in your projects requires confirmation that you trust and enable it. If you don’t do this, the project simply won’t build. It’s not a problem when you develop on your local machine because you simply click on the button, but a problem occurs when you want to build a project on a remote machine like Xcode Cloud, in our case.
Skip macro validation
I couldn’t find any official information in Apple’s documentation on how to enable Swift Macro on the Xcode Cloud. The only information I did find states that you can completely disable the macro validation mechanism. You can do this in two ways: by passing the flag -skipMacroValidation
to the xcodebuild
command, or by changing the macOS entry defaults (e.g., in post clone script).
defaults write com.apple.dt.Xcode IDESkipMacroFingerprintValidation -bool YES
I don’t think skipping fingerprint validation for all macros seems to be a good practice in terms of security. It would be a better option to have a whitelist – a list containing all macros that you explicitly allowed in the project.
Trust specific macro
When conducting additional research, you may observe that SPM maintains a list of permitted macros in a single JSON file.
Enabling a specific macro from Xcode results in its addition to this file, which is located at a given location. ~/Library/org.swift.swiftpm/security/macros.json
When you open this file with a text editor, you will notice that every macro entry has the given format.
{
"fingerprint": "5ac90d9265dc412789d277c006f4138457dd2d14",
"packageIdentity": "xctestparametrizedmacro",
"targetName": "XCTestParametrizedMacroMacros"
}
One note is that the fingerprint value is a git hash commit when you use a macro from the GitHub repository, and it can change when you update a macro to the latest version. For packages distributed through the package registry, the fingerprint value is a checksum from the source archive. more info
PackageIdentity is the last path component (lowercase) of the repository URL.
Having this information, we can prepare a list of trusted macros and copy this to the internal SPM location on the Xcode Cloud before the project build.
It can be done by creating a small post-clone script ci_post_clone.sh
in ci_scripts
directory. You should also add the macros.json
file to this directory, which contains a list of allowed macros. Now, the script file should contain only the cp
command, which copies the file to the internal SPM directory.
#!/bin/zsh
cp macros.json ~/Library/org.swift.swiftpm/security/
When you push the changes and trigger the build, Xcode recognizes the macro as trusted, and the project can be built successfully.
Summary
Although this solution for Swift macros works with the current version of Xcode, I can’t guarantee it will work with future versions. The same approach can be applied for Swift package plugins, but instead of macros.json
you need to modify plugins.json
.
Let’s remain hopeful that Apple will reveal a feature at the upcoming WWDC to make this process a bit smoother.