diff --git a/Sources/SWBCore/PlannedTaskAction.swift b/Sources/SWBCore/PlannedTaskAction.swift index 3632cfd2..d762996f 100644 --- a/Sources/SWBCore/PlannedTaskAction.swift +++ b/Sources/SWBCore/PlannedTaskAction.swift @@ -331,7 +331,7 @@ public protocol TaskActionCreationDelegate func createLinkAssetCatalogTaskAction() -> any PlannedTaskAction func createLSRegisterURLTaskAction() -> any PlannedTaskAction func createODRAssetPackManifestTaskAction() -> any PlannedTaskAction - func createProcessProductEntitlementsTaskAction(scope: MacroEvaluationScope, mergedEntitlements: PropertyListItem, entitlementsVariant: EntitlementsVariant, destinationPlatformName: String, entitlementsFilePath: Path?, fs: any FSProxy) -> any PlannedTaskAction + func createProcessProductEntitlementsTaskAction(mergedEntitlements: PropertyListItem, entitlementsVariant: EntitlementsVariant, allowEntitlementsModification: Bool, entitlementsDestination: EntitlementsDestination, destinationPlatformName: String, entitlementsFilePath: Path?, fs: any FSProxy) -> any PlannedTaskAction func createProcessProductProvisioningProfileTaskAction() -> any PlannedTaskAction func createRegisterExecutionPolicyExceptionTaskAction() -> any PlannedTaskAction func createSwiftHeaderToolTaskAction() -> any PlannedTaskAction diff --git a/Sources/SWBCore/Settings/BuiltinMacros.swift b/Sources/SWBCore/Settings/BuiltinMacros.swift index 6c232060..b32c08df 100644 --- a/Sources/SWBCore/Settings/BuiltinMacros.swift +++ b/Sources/SWBCore/Settings/BuiltinMacros.swift @@ -2876,7 +2876,7 @@ public enum StickerSharingLevel: String, Equatable, Hashable, EnumerationMacroTy } /// Enumeration macro type for the value of the `ENTITLEMENTS_DESTINATION` build setting. -public enum EntitlementsDestination: String, Equatable, Hashable, EnumerationMacroType { +public enum EntitlementsDestination: String, Equatable, Hashable, EnumerationMacroType, Serializable { public static let defaultValue = EntitlementsDestination.none case codeSignature = "Signature" diff --git a/Sources/SWBCore/SpecImplementations/Tools/ProductPackaging.swift b/Sources/SWBCore/SpecImplementations/Tools/ProductPackaging.swift index 5cb57d51..2fec4dd2 100644 --- a/Sources/SWBCore/SpecImplementations/Tools/ProductPackaging.swift +++ b/Sources/SWBCore/SpecImplementations/Tools/ProductPackaging.swift @@ -169,7 +169,11 @@ public final class ProductPackagingToolSpec : GenericCommandLineToolSpec, SpecId } // Create the task action, and then the task. - let action = delegate.taskActionCreationDelegate.createProcessProductEntitlementsTaskAction(scope: cbc.scope, mergedEntitlements: entitlements, entitlementsVariant: entitlementsVariant, destinationPlatformName: platform.name, entitlementsFilePath: codeSignEntitlementsInput?.absolutePath, fs: fs) + let action = delegate.taskActionCreationDelegate.createProcessProductEntitlementsTaskAction(mergedEntitlements: entitlements, entitlementsVariant: entitlementsVariant, allowEntitlementsModification: cbc.scope.evaluate(BuiltinMacros.CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION), entitlementsDestination: cbc.scope.evaluate(BuiltinMacros.ENTITLEMENTS_DESTINATION), destinationPlatformName: platform.name, entitlementsFilePath: codeSignEntitlementsInput?.absolutePath, fs: fs) + // The action records a timestamp representing the last modification date of the entitlements file, so changes to the input must invalidate the build description. + if let path = codeSignEntitlementsInput?.absolutePath { + delegate.access(path: path) + } delegate.createTask(type: self, ruleInfo: ["ProcessProductPackaging", codeSignEntitlementsInput?.absolutePath.str ?? "", outputPath.str], commandLine: commandLine, additionalOutput: additionalOutput, environment: environmentFromSpec(cbc, delegate), workingDirectory: cbc.producer.defaultWorkingDirectory, inputs: inputs.map(\.absolutePath), outputs: [ outputPath ], action: action, execDescription: resolveExecutionDescription(cbc, delegate), enableSandboxing: enableSandboxing) } diff --git a/Sources/SWBTaskExecution/BuildDescriptionManager.swift b/Sources/SWBTaskExecution/BuildDescriptionManager.swift index 842c8baf..e119cd92 100644 --- a/Sources/SWBTaskExecution/BuildDescriptionManager.swift +++ b/Sources/SWBTaskExecution/BuildDescriptionManager.swift @@ -857,8 +857,8 @@ extension BuildSystemTaskPlanningDelegate: TaskActionCreationDelegate { return LSRegisterURLTaskAction() } - func createProcessProductEntitlementsTaskAction(scope: MacroEvaluationScope, mergedEntitlements: PropertyListItem, entitlementsVariant: EntitlementsVariant, destinationPlatformName: String, entitlementsFilePath: Path?, fs: any FSProxy) -> any PlannedTaskAction { - return ProcessProductEntitlementsTaskAction(scope: scope, fs: fs, entitlements: mergedEntitlements, entitlementsVariant: entitlementsVariant, destinationPlatformName: destinationPlatformName, entitlementsFilePath: entitlementsFilePath) + func createProcessProductEntitlementsTaskAction(mergedEntitlements: PropertyListItem, entitlementsVariant: EntitlementsVariant, allowEntitlementsModification: Bool, entitlementsDestination: EntitlementsDestination, destinationPlatformName: String, entitlementsFilePath: Path?, fs: any FSProxy) -> any PlannedTaskAction { + return ProcessProductEntitlementsTaskAction(fs: fs, entitlements: mergedEntitlements, entitlementsVariant: entitlementsVariant, allowEntitlementsModification: allowEntitlementsModification, entitlementsDestination: entitlementsDestination, destinationPlatformName: destinationPlatformName, entitlementsFilePath: entitlementsFilePath) } func createProcessProductProvisioningProfileTaskAction() -> any PlannedTaskAction { diff --git a/Sources/SWBTaskExecution/TaskActions/ProcessProductEntitlementsTaskAction.swift b/Sources/SWBTaskExecution/TaskActions/ProcessProductEntitlementsTaskAction.swift index 63b9fb64..02c45f8e 100644 --- a/Sources/SWBTaskExecution/TaskActions/ProcessProductEntitlementsTaskAction.swift +++ b/Sources/SWBTaskExecution/TaskActions/ProcessProductEntitlementsTaskAction.swift @@ -21,9 +21,6 @@ public import SWBMacro /// Concrete implementation of task for processing product entitlements. public final class ProcessProductEntitlementsTaskAction: TaskAction { - /// The scope the task should use to evaluate build settings. - let scope: MacroEvaluationScope - /// The merged entitlements. let entitlements: PropertyListItem @@ -31,6 +28,12 @@ public final class ProcessProductEntitlementsTaskAction: TaskAction /// macOS and device builds will normally have only signed entitlements. let entitlementsVariant: EntitlementsVariant + /// Whether unsafe modification of entitlements during the build should be allowed. + let allowEntitlementsModification: Bool + + /// The destination of the processed entitlements. + let entitlementsDestination: EntitlementsDestination + /// The platform we're building for. let destinationPlatformName: String @@ -42,12 +45,12 @@ public final class ProcessProductEntitlementsTaskAction: TaskAction /// The timestamp of the latest modification of the entitlements on `init` let entitlementsModificationTimestamp: Result? - public init(scope: MacroEvaluationScope, fs: any FSProxy, entitlements: PropertyListItem, entitlementsVariant: EntitlementsVariant, destinationPlatformName: String, entitlementsFilePath: Path?) + public init(fs: any FSProxy, entitlements: PropertyListItem, entitlementsVariant: EntitlementsVariant, allowEntitlementsModification: Bool, entitlementsDestination: EntitlementsDestination, destinationPlatformName: String, entitlementsFilePath: Path?) { - self.scope = scope - self.entitlements = entitlements self.entitlementsVariant = entitlementsVariant + self.allowEntitlementsModification = allowEntitlementsModification + self.entitlementsDestination = entitlementsDestination self.destinationPlatformName = destinationPlatformName self.entitlementsFilePath = entitlementsFilePath if let entitlementsFilePath, fs.exists(entitlementsFilePath) { @@ -257,7 +260,7 @@ public final class ProcessProductEntitlementsTaskAction: TaskAction // Updating entitlements is not something that is actively encouraged or supported, however, this is a compatibility pain point for certain projects that we need to maintain some ability to do this. A better approach is to plumb this through the system so that we can track this as a proper dependency mechanism, potentially through our virtual task producers... however, until then, we enable this functionality for those existing clients. // Also, we never modify the signed entitlements when building for simulators and ENTITLEMENTS_DESTINATION is __entitlements, since those are only expected to contain get-task-allow; see rdar://55324156. - let entitlementsVariantToModify: EntitlementsVariant = scope.evaluate(BuiltinMacros.ENTITLEMENTS_DESTINATION) == .entitlementsSection ? .simulated : .signed + let entitlementsVariantToModify: EntitlementsVariant = entitlementsDestination == .entitlementsSection ? .simulated : .signed let allowEntitlementsModification = entitlementsVariantToModify == entitlementsVariant var userModifiedEntitlements: PropertyListItem? @@ -279,7 +282,7 @@ public final class ProcessProductEntitlementsTaskAction: TaskAction } if originalModificationTimestamp != currentModificationTimestamp { - if scope.evaluate(BuiltinMacros.CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION) == false { + if !self.allowEntitlementsModification { outputDelegate.emitError("Entitlements file \"\(entitlementsFilePath.basename)\" was modified during the build, which is not supported. You can disable this error by setting 'CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION' to 'YES', however this may cause the built product's code signature or provisioning profile to contain incorrect entitlements.") return .failed } @@ -391,12 +394,13 @@ public final class ProcessProductEntitlementsTaskAction: TaskAction public override func serialize(to serializer: T) { - serializer.serializeAggregate(7) + serializer.serializeAggregate(8) { - serializer.serialize(scope) // FIXME: We have no way to handle any errors in PropertyListItem.asBytes() here. serializer.serialize(try? entitlements.asBytes(.binary)) serializer.serialize(entitlementsVariant) + serializer.serialize(allowEntitlementsModification) + serializer.serialize(entitlementsDestination) serializer.serialize(destinationPlatformName) serializer.serialize(entitlementsFilePath) serializer.serialize(entitlementsModificationTimestamp) @@ -406,10 +410,11 @@ public final class ProcessProductEntitlementsTaskAction: TaskAction public required init(from deserializer: any Deserializer) throws { - try deserializer.beginAggregate(7) - self.scope = try deserializer.deserialize() + try deserializer.beginAggregate(8) self.entitlements = try PropertyList.fromBytes(try deserializer.deserialize()) self.entitlementsVariant = try deserializer.deserialize() + self.allowEntitlementsModification = try deserializer.deserialize() + self.entitlementsDestination = try deserializer.deserialize() self.destinationPlatformName = try deserializer.deserialize() self.entitlementsFilePath = try deserializer.deserialize() self.entitlementsModificationTimestamp = try deserializer.deserialize() diff --git a/Sources/SWBTestSupport/CapturingTaskGenerationDelegate.swift b/Sources/SWBTestSupport/CapturingTaskGenerationDelegate.swift index cc3a27e6..db740865 100644 --- a/Sources/SWBTestSupport/CapturingTaskGenerationDelegate.swift +++ b/Sources/SWBTestSupport/CapturingTaskGenerationDelegate.swift @@ -180,8 +180,8 @@ extension CapturingTaskGenerationDelegate: TaskActionCreationDelegate { return LSRegisterURLTaskAction() } - package func createProcessProductEntitlementsTaskAction(scope: MacroEvaluationScope, mergedEntitlements: PropertyListItem, entitlementsVariant: EntitlementsVariant, destinationPlatformName: String, entitlementsFilePath: Path?, fs: any FSProxy) -> any PlannedTaskAction { - return ProcessProductEntitlementsTaskAction(scope: scope, fs: fs, entitlements: mergedEntitlements, entitlementsVariant: entitlementsVariant, destinationPlatformName: destinationPlatformName, entitlementsFilePath: entitlementsFilePath) + package func createProcessProductEntitlementsTaskAction(mergedEntitlements: PropertyListItem, entitlementsVariant: EntitlementsVariant, allowEntitlementsModification: Bool, entitlementsDestination: EntitlementsDestination, destinationPlatformName: String, entitlementsFilePath: Path?, fs: any FSProxy) -> any PlannedTaskAction { + return ProcessProductEntitlementsTaskAction(fs: fs, entitlements: mergedEntitlements, entitlementsVariant: entitlementsVariant, allowEntitlementsModification: allowEntitlementsModification, entitlementsDestination: entitlementsDestination, destinationPlatformName: destinationPlatformName, entitlementsFilePath: entitlementsFilePath) } package func createProcessProductProvisioningProfileTaskAction() -> any PlannedTaskAction { diff --git a/Sources/SWBTestSupport/TaskPlanningTestSupport.swift b/Sources/SWBTestSupport/TaskPlanningTestSupport.swift index e5c290aa..dc2c6988 100644 --- a/Sources/SWBTestSupport/TaskPlanningTestSupport.swift +++ b/Sources/SWBTestSupport/TaskPlanningTestSupport.swift @@ -408,8 +408,8 @@ extension TestTaskPlanningDelegate: TaskActionCreationDelegate { return LSRegisterURLTaskAction() } - package func createProcessProductEntitlementsTaskAction(scope: MacroEvaluationScope, mergedEntitlements: PropertyListItem, entitlementsVariant: EntitlementsVariant, destinationPlatformName: String, entitlementsFilePath: Path?, fs: any FSProxy) -> any PlannedTaskAction { - return ProcessProductEntitlementsTaskAction(scope: scope, fs: fs, entitlements: mergedEntitlements, entitlementsVariant: entitlementsVariant, destinationPlatformName: destinationPlatformName, entitlementsFilePath: entitlementsFilePath) + package func createProcessProductEntitlementsTaskAction(mergedEntitlements: PropertyListItem, entitlementsVariant: EntitlementsVariant, allowEntitlementsModification: Bool, entitlementsDestination: EntitlementsDestination, destinationPlatformName: String, entitlementsFilePath: Path?, fs: any FSProxy) -> any PlannedTaskAction { + return ProcessProductEntitlementsTaskAction(fs: fs, entitlements: mergedEntitlements, entitlementsVariant: entitlementsVariant, allowEntitlementsModification: allowEntitlementsModification, entitlementsDestination: entitlementsDestination, destinationPlatformName: destinationPlatformName, entitlementsFilePath: entitlementsFilePath) } package func createProcessProductProvisioningProfileTaskAction() -> any PlannedTaskAction { diff --git a/Tests/SWBBuildSystemTests/CodeSigningBuildOperationTests.swift b/Tests/SWBBuildSystemTests/CodeSigningBuildOperationTests.swift new file mode 100644 index 00000000..66cbb4e0 --- /dev/null +++ b/Tests/SWBBuildSystemTests/CodeSigningBuildOperationTests.swift @@ -0,0 +1,143 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift open source project +// +// Copyright (c) 2025 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +import SWBBuildSystem +import SWBCore +import SWBTaskExecution +import SWBTestSupport +import SWBUtil +import Testing + +@Suite +fileprivate struct CodeSigningBuildOperationTests: CoreBasedTests { + @Test(.requireSDKs(.macOS)) + func entitlementsModificationInvalidatesBuildDescription() async throws { + try await withTemporaryDirectory { tmpDirPath in + let testProject = TestProject( + "aProject", + sourceRoot: tmpDirPath, + groupTree: TestGroup( + "SomeFiles", path: "Sources", + children: [ + TestFile("AppSource.m"), + ]), + buildConfigurations: [ + TestBuildConfiguration( "Debug", buildSettings: [ + "COPY_PHASE_STRIP": "NO", + "DEBUG_INFORMATION_FORMAT": "dwarf", + "GENERATE_INFOPLIST_FILE": "YES", + "PRODUCT_NAME": "$(TARGET_NAME)", + "CODE_SIGN_IDENTITY": "-", + "CODE_SIGN_ENTITLEMENTS": "Entitlements.entitlements", + "SDKROOT": "macosx", + "SUPPORTED_PLATFORMS": "macosx", + ]), + ], + targets: [ + TestStandardTarget( + "AppTarget", + type: .application, + buildPhases: [ + TestSourcesBuildPhase([ + "AppSource.m", + ]), + ], + ), + ] + ) + + let tester = try await BuildOperationTester(getCore(), testProject, simulated: false) + let SRCROOT = tester.workspace.projects[0].sourceRoot.str + + try tester.fs.createDirectory(Path(SRCROOT).join("Sources"), recursive: true) + try tester.fs.write(Path(SRCROOT).join("Sources/AppSource.m"), contents: "int main() { return 0; }") + try await tester.fs.writePlist(Path(SRCROOT).join("Entitlements.entitlements"), .plDict([:])) + + try await tester.checkBuild(parameters: BuildParameters(configuration: "Debug"), runDestination: .macOS, persistent: true, signableTargets: ["AppTarget"]) { results in + results.checkNoDiagnostics() + } + + // Modify the entitlements in between builds, but make no other changes which would invalidate the build description. + try tester.fs.touch(Path(SRCROOT).join("Entitlements.entitlements")) + + // A subsequent build should succeed, and should NOT diagnose entitlements modification during the build. + try await tester.checkBuild(parameters: BuildParameters(configuration: "Debug"), runDestination: .macOS, persistent: true, signableTargets: ["AppTarget"]) { results in + results.checkNoDiagnostics() + } + } + } + + @Test(.requireSDKs(.macOS)) + func entitlementsProcessingNotInvalidatedByUnrelatedSettingsChange() async throws { + try await withTemporaryDirectory { tmpDirPath in + let testProject = TestProject( + "aProject", + sourceRoot: tmpDirPath, + groupTree: TestGroup( + "SomeFiles", path: "Sources", + children: [ + TestFile("AppSource.m"), + ]), + buildConfigurations: [ + TestBuildConfiguration( "Debug", buildSettings: [ + "COPY_PHASE_STRIP": "NO", + "DEBUG_INFORMATION_FORMAT": "dwarf", + "GENERATE_INFOPLIST_FILE": "YES", + "PRODUCT_NAME": "$(TARGET_NAME)", + "CODE_SIGN_IDENTITY": "-", + "CODE_SIGN_ENTITLEMENTS": "Entitlements.entitlements", + "SDKROOT": "macosx", + "SUPPORTED_PLATFORMS": "macosx", + ]), + ], + targets: [ + TestStandardTarget( + "AppTarget", + type: .application, + buildPhases: [ + TestSourcesBuildPhase([ + "AppSource.m", + ]), + ], + ), + ] + ) + + let tester = try await BuildOperationTester(getCore(), testProject, simulated: false) + let SRCROOT = tester.workspace.projects[0].sourceRoot.str + + try tester.fs.createDirectory(Path(SRCROOT).join("Sources"), recursive: true) + try tester.fs.write(Path(SRCROOT).join("Sources/AppSource.m"), contents: "int main() { return 0; }") + try await tester.fs.writePlist(Path(SRCROOT).join("Entitlements.entitlements"), .plDict([:])) + + try await tester.checkBuild(parameters: BuildParameters(configuration: "Debug"), runDestination: .macOS, persistent: true, signableTargets: ["AppTarget"]) { results in + results.checkNoDiagnostics() + } + + // After changing irrelevant settings, we should not see CodeSign/ProcessProductPackaging tasks. + // We may still see a task to process Info.plist since that supports build settings interpolation. + try await tester.checkBuild(parameters: BuildParameters(configuration: "Debug", overrides: ["Foo": "Bar"]), runDestination: .macOS, persistent: true, signableTargets: ["AppTarget"]) { results in + results.checkNoTask(.matchRuleType("CodeSign")) + results.checkNoTask(.matchRuleType("ProcessProductPackaging")) + results.checkNoDiagnostics() + } + + // Changing CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION should force them to re-run. + try await tester.checkBuild(parameters: BuildParameters(configuration: "Debug", overrides: ["CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION": "YES"]), runDestination: .macOS, persistent: true, signableTargets: ["AppTarget"]) { results in + results.checkTaskExists(.matchRuleType("CodeSign")) + results.checkTasks(.matchRuleType("ProcessProductPackaging")) { #expect(!$0.isEmpty) } + results.checkNoDiagnostics() + } + } + } +} + diff --git a/Tests/SWBCorePerfTests/CommandLineSpecPerfTests.swift b/Tests/SWBCorePerfTests/CommandLineSpecPerfTests.swift index 0cee180f..390aee2a 100644 --- a/Tests/SWBCorePerfTests/CommandLineSpecPerfTests.swift +++ b/Tests/SWBCorePerfTests/CommandLineSpecPerfTests.swift @@ -175,8 +175,8 @@ extension CapturingTaskGenerationDelegate: TaskActionCreationDelegate { return LSRegisterURLTaskAction() } - public func createProcessProductEntitlementsTaskAction(scope: MacroEvaluationScope, mergedEntitlements: PropertyListItem, entitlementsVariant: EntitlementsVariant, destinationPlatformName: String, entitlementsFilePath: Path?, fs: any FSProxy) -> any PlannedTaskAction { - return ProcessProductEntitlementsTaskAction(scope: scope, fs: fs, entitlements: mergedEntitlements, entitlementsVariant: entitlementsVariant, destinationPlatformName: destinationPlatformName, entitlementsFilePath: entitlementsFilePath) + public func createProcessProductEntitlementsTaskAction(mergedEntitlements: PropertyListItem, entitlementsVariant: EntitlementsVariant, allowEntitlementsModification: Bool, entitlementsDestination: EntitlementsDestination, destinationPlatformName: String, entitlementsFilePath: Path?, fs: any FSProxy) -> any PlannedTaskAction { + return ProcessProductEntitlementsTaskAction(fs: fs, entitlements: mergedEntitlements, entitlementsVariant: entitlementsVariant, allowEntitlementsModification: allowEntitlementsModification, entitlementsDestination: entitlementsDestination, destinationPlatformName: destinationPlatformName, entitlementsFilePath: entitlementsFilePath) } public func createProcessProductProvisioningProfileTaskAction() -> any PlannedTaskAction { diff --git a/Tests/SWBTaskExecutionTests/ProcessProductEntitlementsTaskActionTests.swift b/Tests/SWBTaskExecutionTests/ProcessProductEntitlementsTaskActionTests.swift index 0ff0f27f..27a66ec7 100644 --- a/Tests/SWBTaskExecutionTests/ProcessProductEntitlementsTaskActionTests.swift +++ b/Tests/SWBTaskExecutionTests/ProcessProductEntitlementsTaskActionTests.swift @@ -39,16 +39,12 @@ fileprivate struct ProcessProductEntitlementsTaskActionTests { /// - Parameter commandLine: array of passed command line arguments, first one is the programs name /// - Parameter expected: the returned status code of the task action that is expected for the given input /// - Parameter checkOutput: optional handler to check emitted output - func testPerformTaskAction(commandLine: [String], expected expectedResult: CommandResult, entitlementsVariant: EntitlementsVariant = .signed, destinationPlatformName: String = "platformname", schemeCommand: SchemeCommand = .launch, buildSettings: ((inout MacroValueAssignmentTable, MacroNamespace) throws -> Void)? = nil, modifications: (() throws -> Void)? = nil, checkOutput: ((MockTaskOutputDelegate) throws -> Void)? = nil) async rethrows { - let namespace = MacroNamespace(parent: BuiltinMacros.namespace, debugDescription: #function) - var table = MacroValueAssignmentTable(namespace: namespace) - try buildSettings?(&table, namespace) - let scope = MacroEvaluationScope(table: table) - - let action = ProcessProductEntitlementsTaskAction(scope: scope, - fs: fs, + func testPerformTaskAction(commandLine: [String], expected expectedResult: CommandResult, entitlementsVariant: EntitlementsVariant = .signed, allowEntitlementsModification: Bool = false, entitlementsDestination: EntitlementsDestination = .none, destinationPlatformName: String = "platformname", schemeCommand: SchemeCommand = .launch, modifications: (() throws -> Void)? = nil, checkOutput: ((MockTaskOutputDelegate) throws -> Void)? = nil) async rethrows { + let action = ProcessProductEntitlementsTaskAction(fs: fs, entitlements: entitlements, entitlementsVariant: entitlementsVariant, + allowEntitlementsModification: allowEntitlementsModification, + entitlementsDestination: entitlementsDestination, destinationPlatformName: destinationPlatformName, entitlementsFilePath: entitlementsPath) @@ -98,7 +94,7 @@ fileprivate struct ProcessProductEntitlementsTaskActionTests { // No error if we opt out try await testPerformTaskAction(commandLine: ["programName", "-entitlements", "-o", "/temp/foobar.output"], expected: .succeeded, - buildSettings: { table, namespace in table.push(BuiltinMacros.CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION, namespace.parseLiteralString("YES")) }, + allowEntitlementsModification: true, modifications: { try fs.write(entitlementsPath, contents: ByteString(PropertyListItem.plDict(["key": .plString("value2")]).asBytes(.xml))) }, checkOutput: { output in #expect(output.warnings.isEmpty, "Warnings shouldn't be emitted") @@ -110,10 +106,8 @@ fileprivate struct ProcessProductEntitlementsTaskActionTests { try await testPerformTaskAction(commandLine: ["programName", "-entitlements", "-o", "/temp/foobar.output"], expected: .succeeded, entitlementsVariant: .signed, - buildSettings: { table, namespace in - table.push(BuiltinMacros.CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION, namespace.parseLiteralString("YES")) - table.push(BuiltinMacros.ENTITLEMENTS_DESTINATION, namespace.parseLiteralString("__entitlements")) - }, + allowEntitlementsModification: true, + entitlementsDestination: .entitlementsSection, modifications: { try fs.write(entitlementsPath, contents: ByteString(PropertyListItem.plDict(["key": .plString("value2")]).asBytes(.xml))) }, checkOutput: { output in #expect(output.warnings.isEmpty, "Warnings shouldn't be emitted") @@ -125,10 +119,8 @@ fileprivate struct ProcessProductEntitlementsTaskActionTests { try await testPerformTaskAction(commandLine: ["programName", "-entitlements", "-o", "/temp/foobar.output"], expected: .succeeded, entitlementsVariant: .signed, - buildSettings: { table, namespace in - table.push(BuiltinMacros.CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION, namespace.parseLiteralString("YES")) - table.push(BuiltinMacros.ENTITLEMENTS_DESTINATION, namespace.parseLiteralString("Signature")) - }, + allowEntitlementsModification: true, + entitlementsDestination: .codeSignature, modifications: { try fs.write(entitlementsPath, contents: ByteString(PropertyListItem.plDict(["key": .plString("value2")]).asBytes(.xml))) }, checkOutput: { output in #expect(output.warnings.isEmpty, "Warnings shouldn't be emitted") @@ -140,10 +132,8 @@ fileprivate struct ProcessProductEntitlementsTaskActionTests { try await testPerformTaskAction(commandLine: ["programName", "-entitlements", "-o", "/temp/foobar.output"], expected: .succeeded, entitlementsVariant: .simulated, - buildSettings: { table, namespace in - table.push(BuiltinMacros.CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION, namespace.parseLiteralString("YES")) - table.push(BuiltinMacros.ENTITLEMENTS_DESTINATION, namespace.parseLiteralString("__entitlements")) - }, + allowEntitlementsModification: true, + entitlementsDestination: .entitlementsSection, modifications: { try fs.write(entitlementsPath, contents: ByteString(PropertyListItem.plDict(["key": .plString("value2")]).asBytes(.xml))) }, checkOutput: { output in #expect(output.warnings.isEmpty, "Warnings shouldn't be emitted") @@ -153,10 +143,8 @@ fileprivate struct ProcessProductEntitlementsTaskActionTests { try await testPerformTaskAction(commandLine: ["programName", "-entitlements", "-o", "/temp/foobar.output"], expected: .succeeded, entitlementsVariant: .simulated, - buildSettings: { table, namespace in - table.push(BuiltinMacros.CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION, namespace.parseLiteralString("YES")) - table.push(BuiltinMacros.ENTITLEMENTS_DESTINATION, namespace.parseLiteralString("Signature")) - }, + allowEntitlementsModification: true, + entitlementsDestination: .codeSignature, modifications: { try fs.write(entitlementsPath, contents: ByteString(PropertyListItem.plDict(["key": .plString("value2")]).asBytes(.xml))) }, checkOutput: { output in #expect(output.warnings.isEmpty, "Warnings shouldn't be emitted") @@ -168,10 +156,8 @@ fileprivate struct ProcessProductEntitlementsTaskActionTests { try await testPerformTaskAction(commandLine: ["programName", "-entitlements", "-o", "/temp/foobar.output"], expected: .succeeded, entitlementsVariant: .simulated, - buildSettings: { table, namespace in - table.push(BuiltinMacros.CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION, namespace.parseLiteralString("YES")) - table.push(BuiltinMacros.ENTITLEMENTS_DESTINATION, namespace.parseLiteralString("")) - }, + allowEntitlementsModification: true, + entitlementsDestination: .none, modifications: { try fs.write(entitlementsPath, contents: ByteString(PropertyListItem.plDict(["key": .plString("value2")]).asBytes(.xml))) }, checkOutput: { output in #expect(output.warnings.isEmpty, "Warnings shouldn't be emitted") @@ -181,10 +167,8 @@ fileprivate struct ProcessProductEntitlementsTaskActionTests { try await testPerformTaskAction(commandLine: ["programName", "-entitlements", "-o", "/temp/foobar.output"], expected: .succeeded, entitlementsVariant: .signed, - buildSettings: { table, namespace in - table.push(BuiltinMacros.CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION, namespace.parseLiteralString("YES")) - table.push(BuiltinMacros.ENTITLEMENTS_DESTINATION, namespace.parseLiteralString("")) - }, + allowEntitlementsModification: true, + entitlementsDestination: .none, modifications: { try fs.write(entitlementsPath, contents: ByteString(PropertyListItem.plDict(["key": .plString("value2")]).asBytes(.xml))) }, checkOutput: { output in #expect(output.warnings.isEmpty, "Warnings shouldn't be emitted") diff --git a/Tests/SWBTaskExecutionTests/ProcessProductPackagingTaskTests.swift b/Tests/SWBTaskExecutionTests/ProcessProductPackagingTaskTests.swift index 8433f549..92403287 100644 --- a/Tests/SWBTaskExecutionTests/ProcessProductPackagingTaskTests.swift +++ b/Tests/SWBTaskExecutionTests/ProcessProductPackagingTaskTests.swift @@ -29,10 +29,7 @@ fileprivate struct ProcessProductEntitlementsTaskTests { func diagnostics() async { func checkDiagnostics(_ commandLine: [String], errors: [String] = [], warnings: [String] = [], notes: [String] = [], sourceLocation: SourceLocation = #_sourceLocation) async { - let namespace = MacroNamespace(parent: BuiltinMacros.namespace, debugDescription: #function) - let table = MacroValueAssignmentTable(namespace: namespace) - let scope = MacroEvaluationScope(table: table) - let action = ProcessProductEntitlementsTaskAction(scope: scope, fs: PseudoFS(), entitlements: .plDict([:]), entitlementsVariant: .signed, destinationPlatformName: "iphoneos", entitlementsFilePath: nil) + let action = ProcessProductEntitlementsTaskAction(fs: PseudoFS(), entitlements: .plDict([:]), entitlementsVariant: .signed, allowEntitlementsModification: false, entitlementsDestination: .none, destinationPlatformName: "iphoneos", entitlementsFilePath: nil) let task = Task(forTarget: nil, ruleInfo: [], commandLine: commandLine, workingDirectory: Path(""), action: action) let executionDelegate = MockExecutionDelegate() let outputDelegate = MockTaskOutputDelegate() @@ -87,17 +84,11 @@ fileprivate struct ProcessProductEntitlementsTaskTests { let entitlements = PropertyListItem(entitlementsData) - // Create a MacroEvaluationScope for the tool to use to evaluate build settings. - let namespace = MacroNamespace(parent: BuiltinMacros.namespace, debugDescription: "testEntitlementsBasics()") - let table = MacroValueAssignmentTable(namespace: namespace) - // Any overrides desired should be pushed here. - let scope = MacroEvaluationScope(table: table) - // Define the location of the output file. let output = Path.root.join("dst/iOSApp.app.xcent") try executionDelegate.fs.createDirectory(output.dirname) - let action = ProcessProductEntitlementsTaskAction(scope: scope, fs: PseudoFS(), entitlements: entitlements, entitlementsVariant: .signed, destinationPlatformName: "iphoneos", entitlementsFilePath: nil) + let action = ProcessProductEntitlementsTaskAction(fs: PseudoFS(), entitlements: entitlements, entitlementsVariant: .signed, allowEntitlementsModification: false, entitlementsDestination: .none, destinationPlatformName: "iphoneos", entitlementsFilePath: nil) var builder = PlannedTaskBuilder(type: mockTaskType, ruleInfo: [], commandLine: ["productPackagingUtility", "-entitlements", "-format", "xml", input.str, "-o", output.str].map{ .literal(ByteString(encodingAsUTF8: $0)) }) let task = Task(&builder) let result = await action.performTaskAction( @@ -181,16 +172,11 @@ fileprivate struct ProcessProductEntitlementsTaskTests { ], ].merging(additionalEntitlements) { (_, new) in new } - // Create a MacroEvaluationScope for the tool to use to evaluate build settings. - let namespace = MacroNamespace(parent: BuiltinMacros.namespace, debugDescription: "testEntitlementsBasics()") - let table = MacroValueAssignmentTable(namespace: namespace) - let scope = MacroEvaluationScope(table: table) - // Define the location of the output file. let output = Path.root.join("dst/macOSApp.app.xcent") try executionDelegate.fs.createDirectory(output.dirname) - let action = ProcessProductEntitlementsTaskAction(scope: scope, fs: PseudoFS(), entitlements: .plDict(entitlements), entitlementsVariant: .signed, destinationPlatformName: destinationPlatformName, entitlementsFilePath: nil) + let action = ProcessProductEntitlementsTaskAction(fs: PseudoFS(), entitlements: .plDict(entitlements), entitlementsVariant: .signed, allowEntitlementsModification: false, entitlementsDestination: .none, destinationPlatformName: destinationPlatformName, entitlementsFilePath: nil) var builder = PlannedTaskBuilder(type: mockTaskType, ruleInfo: [], commandLine: ["productPackagingUtility", "-entitlements", "-format", "xml", input.str, "-o", output.str].map{ .literal(ByteString(encodingAsUTF8: $0)) }) let task = Task(&builder) let result = await action.performTaskAction(