Signature on tuist prebuilt binaries

Binaries of tuist starting with 4.38.0 are codesigned. Is it an intended change or some coincidence?

Fundamentally, there is nothing wrong with this change; however, it broke our workflow. We are storing the tuist binary in our repository using macfuse. We have a homegrown VCS. And it seems that it can’t validates the signature on the binary.

~/Downloads/untitled folder/tuist-4.37.0
❯ codesign -d -vvv --entitlements :- tuist
Executable=tuist-4.37.0/tuist
Identifier=tuist_ext
Format=Mach-O universal (x86_64 arm64)
CodeDirectory v=20400 size=417282 flags=0x20002(adhoc,linker-signed) hashes=13037+0 location=embedded
Hash type=sha256 size=32
CandidateCDHash sha256=342188ae6872317b1d3378308e934a7e15d634d7
CandidateCDHashFull sha256=342188ae6872317b1d3378308e934a7e15d634d7972801091c47fd451a64274b
Hash choices=sha256
CMSDigest=342188ae6872317b1d3378308e934a7e15d634d7972801091c47fd451a64274b
CMSDigestType=2
CDHash=342188ae6872317b1d3378308e934a7e15d634d7
Signature=adhoc
Info.plist=not bound
TeamIdentifier=not set
Sealed Resources=none
Internal requirements=none
warning: Specifying ':' in the path is deprecated and will not work in a future release

❯ cd ../tuist-4.38.0

❯ codesign -d -vvv --entitlements :- tuist
Executable=tuist-4.38.0/tuist
Identifier=tuist
Format=Mach-O universal (x86_64 arm64)
CodeDirectory v=20500 size=420145 flags=0x10000(runtime) hashes=13124+2 location=embedded
Hash type=sha256 size=32
CandidateCDHash sha256=f15e6f14c901e1c433a73f9a2f2939523627e27c
CandidateCDHashFull sha256=f15e6f14c901e1c433a73f9a2f2939523627e27cf0beba12751d9dd3ba789f07
Hash choices=sha256
CMSDigest=f15e6f14c901e1c433a73f9a2f2939523627e27cf0beba12751d9dd3ba789f07
CMSDigestType=2
CDHash=f15e6f14c901e1c433a73f9a2f2939523627e27c
Signature size=9040
Authority=Developer ID Application: Tuist GmbH (U6LC622NKF)
Authority=Developer ID Certification Authority
Authority=Apple Root CA
Timestamp=17 Dec 2024 at 17:18:46
Info.plist=not bound
TeamIdentifier=U6LC622NKF
Runtime Version=14.4.0
Sealed Resources=none
Internal requirements count=1 size=168
warning: Specifying ':' in the path is deprecated and will not work in a future release

Hi @Gladkov-Art

You are right, we started signing the binaries from that version from 4.38.0. We didn’t expect that to result in a breaking workflows, so apologies for that.

Could you share more about how that manifests when running the CLI? Do you get an error from the system refusing to run it?

Yes, exactly. I can’t force it to run when binary is on the virtual file system (macfuse). I’m receiving zsk: killed and see this message from Kernel in Console.app:

mac_vnode_check_signature: /Users/art-gladkov/Documents/Yandex/arcadia/mobile/fintech/bank/ios/tuist-4.38.0/tuist: code signature validation failed fatally: When validating /Users/art-gladkov/Documents/Yandex/arcadia/mobile/fintech/bank/ios/tuist-4.38.0/tuist:
  The code contains a Team ID, but validating its signature failed.
Please check your system log.
<private>: Failure creating SecStaticCode, error -67068

I tried to drop the signature, it solves checking issue but brings the new one:

❯ codesign -f -s - tuist
tuist: replacing existing signature

~/tuist-4.38.1
❯ ./tuist version
Swift/ErrorType.swift:200: Fatal error: Error raised at top level: The 'swift' command exited with error code 255 and message:
JIT session error: Symbols not found: [ _$s18ProjectDescription23CompatibleXcodeVersionsOMa, _$s18ProjectDescription5TuistV17GenerationOptionsV31StaticSideEffectsWarningTargetsO3allyA2GmFWC, _$s18ProjectDescription5TuistV23compatibleXcodeVersions5cloud10fullHandle3url12swiftVersion7plugins17generationOptions07installO0AcA010CompatibleeF0O_AA5CloudVSgSSSgSSAA0L0VSgSayAA14PluginLocationVGAC010GenerationO0VAC07InstallO0VtcfC, _$s18ProjectDescription5CloudVMa, _$s18ProjectDescription5TuistV17GenerationOptionsV7options32resolveDependenciesWithSystemScm28disablePackageVersionLocking27clonedSourcePackagesDirPath31staticSideEffectsWarningTargets20defaultConfiguration22optionalAuthenticationAESb_SbAA0T0VSgAE06StaticvwxY0OSSSgSbtFZ, _$s18ProjectDescription4PathVMa, _$s18ProjectDescription23CompatibleXcodeVersionsO12arrayLiteralA2Cd_tcfC, _$s18ProjectDescription4PathV14relativeToRootyACSSFZ, _$s18ProjectDescription5TuistV17GenerationOptionsVMa, _$s18ProjectDescription14PluginLocationV5local4pathAcA4PathV_tFZ, _$s18ProjectDescription7VersionVMa, _$s18ProjectDescription5CloudVMn, _$s18ProjectDescription5TuistV17GenerationOptionsV31StaticSideEffectsWarningTargetsOMa, _$s18ProjectDescription5TuistVMa, _$s18ProjectDescription4PathVMn, _$s18ProjectDescription7VersionVMn, _$s18ProjectDescription5TuistV14InstallOptionsV7options39passthroughSwiftPackageManagerArgumentsAESaySSG_tFZ, _$s18ProjectDescription14PluginLocationVMa, _$s18ProjectDescription23CompatibleXcodeVersionsO13stringLiteralACSS_tcfC, _$s18ProjectDescription5TuistV14InstallOptionsVMa ]
Failed to materialize symbols: { (main, { _$sSa12_endMutationyyF, _main, _$s18ProjectDescription5TuistV23compatibleXcodeVersions5cloud10fullHandle3url12swiftVersion7plugins17generationOptions07installO0AcA010CompatibleeF0O_AA5CloudVSgSSSgSSAA0L0VSgSayAA14PluginLocationVGAC010GenerationO0VAC07InstallO0VtcfcfA6_, __swift_FORCE_LOAD_$_swiftObjectiveC_$_Config, ___swift_instantiateConcreteTypeFromMangledName, __swift_FORCE_LOAD_$_swiftFoundation_$_Config, _$ss27_finalizeUninitializedArrayySayxGABnlF, _$s18ProjectDescription5CloudVSgMD, __swift_FORCE_LOAD_$_swiftDispatch_$_Config, _$s18ProjectDescription5TuistV23compatibleXcodeVersions5cloud10fullHandle3url12swiftVersion7plugins17generationOptions07installO0AcA010CompatibleeF0O_AA5CloudVSgSSSgSSAA0L0VSgSayAA14PluginLocationVGAC010GenerationO0VAC07InstallO0VtcfcfA5_, __swift_FORCE_LOAD_$_swiftDarwin_$_Config, _$sSa22_allocateUninitializedySayxG_SpyxGtSiFZSS_Tgmq5, __swift_FORCE_LOAD_$_swiftXPC_$_Config, _symbolic _____Sg 18ProjectDescription5CloudV, _got.$s18ProjectDescription4PathVMn, __swift_FORCE_LOAD_$_swiftIOKit_$_Config, _$s18ProjectDescription5TuistV23compatibleXcodeVersions5cloud10fullHandle3url12swiftVersion7plugins17generationOptions07installO0AcA010CompatibleeF0O_AA5CloudVSgSSSgSSAA0L0VSgSayAA14PluginLocationVGAC010GenerationO0VAC07InstallO0VtcfcfA2_, _$s18ProjectDescription7VersionVSgMD, __swift_FORCE_LOAD_$_swiftCoreFoundation_$_Config, _$s18ProjectDescription4PathVSgMD, _got.$s18ProjectDescription7VersionVMn, _$s18ProjectDescription4PathVSgWOh, ___swift_allocate_value_buffer, _symbolic _____Sg 18ProjectDescription7VersionV, ___swift_project_value_buffer, _symbolic _____Sg 18ProjectDescription4PathV, _$s6Config6config18ProjectDescription5TuistVvp, _got.$s18ProjectDescription5CloudVMn }) }

zsh: trace trap  ./tuist version

It’s the first time I see it. I’m a bit surprised this hasn’t happened before to other users. Does it happen in all the environments? How can I reproduce this error locally?

We have a very specific execution context here. It’s a virtual file system and MDM laptops (jamf). Without a complete understanding of the reason, I don’t know how to reproduce this environment elsewhere. I’ll try to dig deeper into logs for a root cause.

Is it posible to have additional zip with unsigned tuist on github release page?

This would be great. The certificate that we use to sign the binaries should be a valid one. Note that the file is notarized too, so I wonder if it could be connected to that.

Regarding providing an unsigned version of the binary I have mixed feelings. On one side, I’d understand that you want to take the risk, specially in a situation like this, but on the other side, I wouldn’t want developers to compromise on security because we haven’t figured out what’s wrong with the signature. Thoughts @core ?

1 Like

I’d suggest spending some more time to figure out the issue before publishing a CLI version without the signature. @Gladkov-Art, I believe you can still use the older unsigned CLI for the time being?

Yes. Fortunately, we have the required fixes in 4.37.0.

I tried once again to drop the signature. I did it on both tuist’s binaries:

codesign -f -s - tuist
codesign -f -s - ProjectDescription.framework/Versions/A/ProjectDescription

And now it runs correctly. So, it’s an acceptable solution for my use case.