@@ -356,10 +356,7 @@ static void testOneShotControllerClearsVintedSignedCustomGroup(void) {
356356 @" requestID" : request.requestID ,
357357 @" targetBundleID" : request.targetBundleID ,
358358 @" success" : @YES ,
359- @" results" : successfulOneShotResults (
360- @[applicationIdentifier, vintedAccessGroup],
361- vintedAccessGroup
362- ),
359+ @" results" : successfulOneShotResults (@[vintedAccessGroup], vintedAccessGroup),
363360 @" failureCode" : @" " ,
364361 @" protectedSharedAccessGroupCount" : @0
365362 } error: nil ];
@@ -377,7 +374,9 @@ static void testOneShotControllerClearsVintedSignedCustomGroup(void) {
377374 assert (response.protectedSharedAccessGroupCount == 0 );
378375 assert (execution.invocationCount == 1 );
379376 assert (([execution.lastWorkerEntitlements[@" keychain-access-groups" ] isEqualToArray:
380- @[applicationIdentifier, vintedAccessGroup]]));
377+ @[vintedAccessGroup]]));
378+ assert (![execution.lastWorkerEntitlements[@" keychain-access-groups" ]
379+ containsObject: applicationIdentifier]);
381380}
382381
383382static void testOneShotEntitlementPlanRejectsDuplicateSignedGroups (void ) {
@@ -585,7 +584,63 @@ - (int32_t)deleteItemsForClass:(NSString *)keychainClass
585584
586585@end
587586
588- static void testOneShotControllerRejectsIncompleteProtectedGroupCleanup (void ) {
587+ @interface VintedCustomGroupSecurityAdapter : SuccessfulSecurityAdapter
588+ @property (nonatomic , strong ) NSMutableSet <NSString *> *deletedGroups;
589+ @end
590+
591+ @implementation VintedCustomGroupSecurityAdapter
592+
593+ - (instancetype )init {
594+ self = [super init ];
595+ if (self) _deletedGroups = [NSMutableSet set ];
596+ return self;
597+ }
598+
599+ - (NSDictionary <NSString *, id> *)entitlementsForBundleIdentifier : (NSString *)bundleIdentifier
600+ error : (NSError **)error {
601+ (void )error;
602+ assert ([bundleIdentifier isEqualToString: @" lt.manodrabuziai.fr" ]);
603+ return @{
604+ @" application-identifier" : @" 4Y2CNF6C99.lt.manodrabuziai.fr" ,
605+ @" keychain-access-groups" : @[@" 4Y2CNF6C99.com.vinted.keychain-group" ]
606+ };
607+ }
608+
609+ - (int32_t )deleteItemsForClass : (NSString *)keychainClass
610+ accessGroup : (NSString *)accessGroup
611+ synchronizable : (BOOL )synchronizable {
612+ assert ([accessGroup isEqualToString: @" 4Y2CNF6C99.com.vinted.keychain-group" ]);
613+ [self .deletedGroups addObject: accessGroup];
614+ return [super deleteItemsForClass: keychainClass
615+ accessGroup: accessGroup
616+ synchronizable: synchronizable];
617+ }
618+
619+ @end
620+
621+ static void testExecutorClearsOnlyVintedSignedCustomGroup (void ) {
622+ NSString *bundleIdentifier = @" lt.manodrabuziai.fr" ;
623+ PXKeychainCommandRequest *request = [PXKeychainCommandRequest
624+ requestWithPropertyList: freshRequestPropertyList (bundleIdentifier)
625+ error: nil ];
626+ VintedCustomGroupSecurityAdapter *adapter = [[VintedCustomGroupSecurityAdapter alloc ] init ];
627+ PXKeychainCommandExecutor *executor = [[PXKeychainCommandExecutor alloc ]
628+ initWithValidator: [[PXKeychainCommandValidator alloc ] init ]
629+ securityAdapter: adapter];
630+ NSError *error = nil ;
631+ PXKeychainCommandResponse *response = [executor
632+ executeRequest: request
633+ context: context (bundleIdentifier, YES , NO )
634+ now: [NSDate dateWithTimeIntervalSince1970: 1010 ]
635+ error: &error];
636+ assert (response.isSuccessful );
637+ assert (error == nil );
638+ assert (response.results .count == 5 );
639+ assert ([adapter.deletedGroups isEqualToSet:
640+ [NSSet setWithObject: @" 4Y2CNF6C99.com.vinted.keychain-group" ]]);
641+ }
642+
643+ static void testOneShotControllerReportsProtectedGroupForExclusiveCleanup (void ) {
589644 NSMutableDictionary <NSString *, id > *propertyList =
590645 [freshRequestPropertyList (@" com.example.target" ) mutableCopy ];
591646 propertyList[@" includeSharedAccessGroups" ] = @NO ;
@@ -600,6 +655,15 @@ static void testOneShotControllerRejectsIncompleteProtectedGroupCleanup(void) {
600655 @" TEAM123.group.example.shared"
601656 ]
602657 };
658+ execution.response = [PXKeychainCommandResponse responseWithPropertyList: @{
659+ @" schemaVersion" : @(PXKeychainCommandSchemaVersion),
660+ @" requestID" : request.requestID ,
661+ @" targetBundleID" : request.targetBundleID ,
662+ @" success" : @YES ,
663+ @" results" : successfulOneShotResults (@[@" TEAM123.com.example.target" ], @" " ),
664+ @" failureCode" : @" " ,
665+ @" protectedSharedAccessGroupCount" : @0
666+ } error: nil ];
603667 NSError *error = nil ;
604668 PXKeychainOneShotResponse *response = [[[PXKeychainOneShotController alloc ]
605669 initWithExecution: execution]
@@ -608,9 +672,12 @@ static void testOneShotControllerRejectsIncompleteProtectedGroupCleanup(void) {
608672 now: [NSDate dateWithTimeIntervalSince1970: 1010 ]
609673 error: &error];
610674
611- assert (response == nil );
612- assert ([error.domain isEqualToString: PXKeychainOneShotErrorDomain]);
613- assert (execution.invocationCount == 0 );
675+ assert (response.isSuccessful );
676+ assert (error == nil );
677+ assert (response.protectedSharedAccessGroupCount == 1 );
678+ assert (execution.invocationCount == 1 );
679+ assert ([execution.lastWorkerEntitlements[@" keychain-access-groups" ] isEqualToArray:
680+ @[@" TEAM123.com.example.target" ]]);
614681}
615682
616683
@@ -1289,7 +1356,8 @@ int main(void) {
12891356 testOneShotEntitlementPlanRejectsDuplicateSignedGroups ();
12901357 testOneShotControllerDoesNotLeakGroupsAcrossMultipleSelectedApps ();
12911358 testOneShotControllerRejectsSynchronizableCleanupBeforeExecution ();
1292- testOneShotControllerRejectsIncompleteProtectedGroupCleanup ();
1359+ testOneShotControllerReportsProtectedGroupForExclusiveCleanup ();
1360+ testExecutorClearsOnlyVintedSignedCustomGroup ();
12931361 testOneShotControllerRejectsWorkerResultsOutsideExactApplicationGroup ();
12941362 testFullSuccessRequiresPostDeleteVerificationForEveryScope ();
12951363 testPartialFailureIsNotSuccessAndResponseContainsNoItemMetadata ();
0 commit comments