Blog

Using Swift Macros in CI/CD Without Compromising Security

22 Apr, 2024
Xebia Background Header Wave

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. 

Michał Kowalski
He is passionate about mobile technologies, with a focus on the iOS platform. Currently programming in Swift but possesses strong Objective-C skills. While his expertise primarily lies in native technologies, he has also successfully implemented a commercial project using Flutter.
Questions?

Get in touch with us to learn more about the subject and related solutions

Explore related posts