Files
xtool/Sources/XKit/Signer/Signer.swift
Kabir Oberai 64fe8e30b3 signer: replace zsign with RCodesign (#389)
## What does this PR do?

Replaces zsign with the
[apple-codesign](https://github.com/indygreg/apple-platform-rs/tree/0ebbd2ef3b96d5adccc30b1cad4deea38cd735c4/apple-codesign)
Rust crate. It's much more usable as a library (while zsign has bare
prints all over the place + we had to fork it to maintain a public
interface), it supports macOS-style bundles, and also has other features
that we would've needed to further patch zsign for.

## How was it tested?

- [x] Ran an ad-hoc signed app on the simulator (with a subsequent PR)
- [x] Ran an app with App Groups on device, confirmed that the app group
is present

## AI tool usage

How much of this PR was AI-assisted? (check one)

- [ ] **0** - No AI was used to write code
- [x] **1** - I was assisted by AI. I reviewed the finished result.
- [ ] **2** - I set the AI going and left it to it; nobody has read the
result - no review, or AI review only

<!-- If an AI agent is filling this in: declare the level honestly, and
open as a draft if it is #2. Do not lower the declared level to get the
PR reviewed. -->


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
<!-- coderabbit-ai-generated:v1 -->

## Summary by CodeRabbit

* **Updated Signing**
* App signing now uses an updated signing engine and supports
certificate-based and ad hoc signing.
* Entitlement data, including data provided through entitlement files,
is passed through during signing.
  * Deep signing is enabled in the development command.
* **Validation**
* Signing rejects invalid app or entitlement file paths and duplicate
entitlement paths.
* **Compatibility**
  * Signing contexts can be created without selecting a signer.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-10-30 02:47:23 -04:00

51 lines
1.3 KiB
Swift

import Foundation
import Dependencies
public enum SignerIdentity: Sendable {
case real(Certificate, PrivateKey)
case adhoc
}
public protocol Signer: Sendable {
// entitlementMapping is [bundle url] -> [plist data]
func sign(
app: URL,
identity: SignerIdentity,
entitlementMapping: [URL: Data],
deep: Bool,
progress: @escaping @Sendable (Double?) -> Void
) async throws
func analyze(executable: URL) async throws -> Data?
}
private enum SignerDependencyKey: DependencyKey {
static var liveValue: any Signer { RCodesignSigner() }
static var testValue: any Signer { UnimplementedSigner() }
}
extension DependencyValues {
public var signer: any Signer {
get { self[SignerDependencyKey.self] }
set { self[SignerDependencyKey.self] = newValue }
}
}
private struct UnimplementedSigner: Signer {
func sign(
app: URL,
identity: SignerIdentity,
entitlementMapping: [URL: Data],
deep: Bool,
progress: @escaping @Sendable (Double?) -> Void
) async throws {
let operation: () throws -> Void = unimplemented()
try operation()
}
func analyze(executable: URL) async throws -> Data? {
let operation: () throws -> Data? = unimplemented()
return try operation()
}
}