From cbd778e2c964834a08bb74d8c5c8a618126473e8 Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Wed, 27 May 2026 18:47:39 -0400 Subject: [PATCH 1/5] feat: Only log local debug tokens when not yet registered Updated `GACAppCheckDebugProvider` to only log the local debug token at app startup if it has not yet been successfully used. If the debug token has already been successfully exchanged for an App Check token in a previous run then it has already been registered in the Firebase Console. By only logging when necessary, developers may be more likely to notice when they need to re-register a debug token, such as when switching simulators or devices. --- .../DebugProvider/GACAppCheckDebugProvider.m | 18 +++- .../GACAppCheckDebugProviderTests.m | 85 +++++++++++++++++++ 2 files changed, 100 insertions(+), 3 deletions(-) diff --git a/AppCheckCore/Sources/DebugProvider/GACAppCheckDebugProvider.m b/AppCheckCore/Sources/DebugProvider/GACAppCheckDebugProvider.m index b27e0868..c377617e 100644 --- a/AppCheckCore/Sources/DebugProvider/GACAppCheckDebugProvider.m +++ b/AppCheckCore/Sources/DebugProvider/GACAppCheckDebugProvider.m @@ -35,6 +35,7 @@ static NSString *const kDebugTokenEnvKey = @"AppCheckDebugToken"; static NSString *const kFirebaseDebugTokenEnvKey = @"FIRAAppCheckDebugToken"; static NSString *const kDebugTokenUserDefaultsKey = @"GACAppCheckDebugToken"; +static NSString *const kDebugTokenRegisteredUserDefaultsKey = @"GACAppCheckDebugTokenRegistered"; @interface GACAppCheckDebugProvider () @property(nonatomic, readonly) id APIService; @@ -108,6 +109,8 @@ - (void)getTokenWithLimitedUse:(BOOL)limitedUse return [self.APIService appCheckTokenWithDebugToken:debugToken limitedUse:limitedUse]; }) .then(^id(GACAppCheckToken *appCheckToken) { + [[GULUserDefaults standardUserDefaults] setBool:YES + forKey:kDebugTokenRegisteredUserDefaultsKey]; handler(appCheckToken, nil); return nil; }) @@ -115,6 +118,10 @@ - (void)getTokenWithLimitedUse:(BOOL)limitedUse NSString *logMessage = [NSString stringWithFormat:@"Failed to exchange debug token to app check token: %@", error]; GACAppCheckLogDebug(GACLoggerAppCheckMessageDebugProviderFailedExchange, logMessage); + if (error.code != GACAppCheckErrorCodeServerUnreachable) { + [[GULUserDefaults standardUserDefaults] + removeObjectForKey:kDebugTokenRegisteredUserDefaultsKey]; + } handler(nil, error); }); } @@ -175,9 +182,14 @@ - (void)getTokenWithLimitedUse:(BOOL)limitedUse return firebaseEnvVariableValue; } else { - // Print only a locally generated token to avoid a valid token leak on CI. - GACAppCheckLog(GACLoggerAppCheckMessageLocalDebugToken, GACAppCheckLogLevelWarning, - [NSString stringWithFormat:@"App Check debug token: '%@'.", LocalDebugToken()]); + BOOL isRegistered = + [[GULUserDefaults standardUserDefaults] boolForKey:kDebugTokenRegisteredUserDefaultsKey]; + if (!isRegistered) { + // Print only a locally generated token to avoid a valid token leak on CI. + GACAppCheckLog( + GACLoggerAppCheckMessageLocalDebugToken, GACAppCheckLogLevelWarning, + [NSString stringWithFormat:@"App Check debug token: '%@'.", LocalDebugToken()]); + } return nil; } diff --git a/AppCheckCore/Tests/Unit/DebugProvider/GACAppCheckDebugProviderTests.m b/AppCheckCore/Tests/Unit/DebugProvider/GACAppCheckDebugProviderTests.m index d67ae3c0..9d749b9a 100644 --- a/AppCheckCore/Tests/Unit/DebugProvider/GACAppCheckDebugProviderTests.m +++ b/AppCheckCore/Tests/Unit/DebugProvider/GACAppCheckDebugProviderTests.m @@ -27,6 +27,7 @@ static NSString *const kDebugTokenEnvKey = @"AppCheckDebugToken"; static NSString *const kFirebaseDebugTokenEnvKey = @"FIRAAppCheckDebugToken"; static NSString *const kDebugTokenUserDefaultsKey = @"GACAppCheckDebugToken"; +static NSString *const kDebugTokenRegisteredUserDefaultsKey = @"GACAppCheckDebugTokenRegistered"; @interface GACAppCheckDebugProvider (Tests) @@ -59,6 +60,8 @@ - (void)tearDown { [self.processInfoMock stopMocking]; self.processInfoMock = nil; [[GULUserDefaults standardUserDefaults] removeObjectForKey:kDebugTokenUserDefaultsKey]; + [[GULUserDefaults standardUserDefaults] removeObjectForKey:kDebugTokenRegisteredUserDefaultsKey]; + [super tearDown]; } #pragma mark - Debug token generating/storing @@ -225,6 +228,88 @@ - (void)testGetLimitedUseTokenAPIError { OCMVerifyAll(self.fakeAPIService); } +- (void)testGetTokenSuccessSetsRegisteredFlag { + // 1. Stub API service. + NSString *expectedDebugToken = [self.provider currentDebugToken]; + GACAppCheckToken *validToken = [[GACAppCheckToken alloc] initWithToken:@"valid_token" + expirationDate:[NSDate date] + receivedAtDate:[NSDate date]]; + OCMExpect([self.fakeAPIService appCheckTokenWithDebugToken:expectedDebugToken limitedUse:NO]) + .andReturn([FBLPromise resolvedWith:validToken]); + + // Ensure flag is not set. + [[GULUserDefaults standardUserDefaults] removeObjectForKey:kDebugTokenRegisteredUserDefaultsKey]; + + // 2. Validate get token. + [self validateGetToken:^(GACAppCheckToken *_Nullable token, NSError *_Nullable error) { + XCTAssertNil(error); + XCTAssertNotNil(token); + }]; + + // 3. Verify flag is now YES. + XCTAssertTrue( + [[GULUserDefaults standardUserDefaults] boolForKey:kDebugTokenRegisteredUserDefaultsKey]); + + // 4. Verify fakes. + OCMVerifyAll(self.fakeAPIService); +} + +- (void)testGetTokenPermanentFailureClearsRegisteredFlag { + // 1. Stub API service. + NSString *expectedDebugToken = [self.provider currentDebugToken]; + NSError *APIError = [NSError errorWithDomain:@"testGetTokenPermanentFailureClearsRegisteredFlag" + code:-1 + userInfo:nil]; + FBLPromise *rejectedPromise = [FBLPromise pendingPromise]; + [rejectedPromise reject:APIError]; + OCMExpect([self.fakeAPIService appCheckTokenWithDebugToken:expectedDebugToken limitedUse:NO]) + .andReturn(rejectedPromise); + + // Pre-populate flag to YES. + [[GULUserDefaults standardUserDefaults] setBool:YES forKey:kDebugTokenRegisteredUserDefaultsKey]; + + // 2. Validate get token. + [self validateGetToken:^(GACAppCheckToken *_Nullable token, NSError *_Nullable error) { + XCTAssertNotNil(error); + XCTAssertNil(token); + }]; + + // 3. Verify flag is cleared. + XCTAssertNil( + [[GULUserDefaults standardUserDefaults] objectForKey:kDebugTokenRegisteredUserDefaultsKey]); + + // 4. Verify fakes. + OCMVerifyAll(self.fakeAPIService); +} + +- (void)testGetTokenNetworkFailureDoesNotClearRegisteredFlag { + // 1. Stub API service. + NSString *expectedDebugToken = [self.provider currentDebugToken]; + NSError *networkError = [NSError errorWithDomain:GACAppCheckErrorDomain + code:GACAppCheckErrorCodeServerUnreachable + userInfo:nil]; + FBLPromise *rejectedPromise = [FBLPromise pendingPromise]; + [rejectedPromise reject:networkError]; + OCMExpect([self.fakeAPIService appCheckTokenWithDebugToken:expectedDebugToken limitedUse:NO]) + .andReturn(rejectedPromise); + + // Pre-populate flag to YES. + [[GULUserDefaults standardUserDefaults] setBool:YES forKey:kDebugTokenRegisteredUserDefaultsKey]; + + // 2. Validate get token. + [self validateGetToken:^(GACAppCheckToken *_Nullable token, NSError *_Nullable error) { + XCTAssertNotNil(error); + XCTAssertNil(token); + }]; + + // 3. Verify flag is still YES. + XCTAssertTrue( + [[GULUserDefaults standardUserDefaults] boolForKey:kDebugTokenRegisteredUserDefaultsKey]); + + // 4. Verify fakes. + OCMVerifyAll(self.fakeAPIService); +} + #pragma mark - Helpers - (void)validateGetToken:(GACAppCheckTokenValidationBlock)validationBlock { From 4779a874cccb06ba0d39d929913f0da528b38aca Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Wed, 27 May 2026 19:02:01 -0400 Subject: [PATCH 2/5] Update to `Xcode_26.2` in `pod_lib_lint` job --- .github/workflows/app_check_core.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/app_check_core.yml b/.github/workflows/app_check_core.yml index 5db50fb0..29d37004 100644 --- a/.github/workflows/app_check_core.yml +++ b/.github/workflows/app_check_core.yml @@ -21,7 +21,7 @@ jobs: - os: macos-15 xcode: Xcode_16.4 - os: macos-26 - xcode: Xcode_26.1 + xcode: Xcode_26.2 runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v3 From ed895b487fff80e293d416f921aa1b34859970a5 Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Thu, 28 May 2026 11:46:49 -0400 Subject: [PATCH 3/5] Add `GACAppCheckErrors.h` import --- .../Tests/Unit/DebugProvider/GACAppCheckDebugProviderTests.m | 1 + 1 file changed, 1 insertion(+) diff --git a/AppCheckCore/Tests/Unit/DebugProvider/GACAppCheckDebugProviderTests.m b/AppCheckCore/Tests/Unit/DebugProvider/GACAppCheckDebugProviderTests.m index 9d749b9a..8baf0712 100644 --- a/AppCheckCore/Tests/Unit/DebugProvider/GACAppCheckDebugProviderTests.m +++ b/AppCheckCore/Tests/Unit/DebugProvider/GACAppCheckDebugProviderTests.m @@ -22,6 +22,7 @@ #import "AppCheckCore/Sources/DebugProvider/API/GACAppCheckDebugProviderAPIService.h" #import "AppCheckCore/Sources/Public/AppCheckCore/GACAppCheckDebugProvider.h" +#import "AppCheckCore/Sources/Public/AppCheckCore/GACAppCheckErrors.h" #import "AppCheckCore/Sources/Public/AppCheckCore/GACAppCheckToken.h" static NSString *const kDebugTokenEnvKey = @"AppCheckDebugToken"; From f57e0520d6cc6161e92987677cc7b79c84c1eaf6 Mon Sep 17 00:00:00 2001 From: Nick Cooke Date: Tue, 9 Jun 2026 18:21:40 -0400 Subject: [PATCH 4/5] fix: namespace App Check debug token registration flag by serviceName and resourceName --- .../DebugProvider/GACAppCheckDebugProvider.m | 44 +++++++++-- .../GACAppCheckDebugProviderTests.m | 75 +++++++++++++++---- 2 files changed, 96 insertions(+), 23 deletions(-) diff --git a/AppCheckCore/Sources/DebugProvider/GACAppCheckDebugProvider.m b/AppCheckCore/Sources/DebugProvider/GACAppCheckDebugProvider.m index c377617e..a10f6100 100644 --- a/AppCheckCore/Sources/DebugProvider/GACAppCheckDebugProvider.m +++ b/AppCheckCore/Sources/DebugProvider/GACAppCheckDebugProvider.m @@ -35,20 +35,35 @@ static NSString *const kDebugTokenEnvKey = @"AppCheckDebugToken"; static NSString *const kFirebaseDebugTokenEnvKey = @"FIRAAppCheckDebugToken"; static NSString *const kDebugTokenUserDefaultsKey = @"GACAppCheckDebugToken"; + +// The base key for registration status. +// NOTE: Do not use this key directly. Use `registeredUserDefaultsKeyForServiceName:resourceName:` +// to obtain the namespaced key. static NSString *const kDebugTokenRegisteredUserDefaultsKey = @"GACAppCheckDebugTokenRegistered"; @interface GACAppCheckDebugProvider () @property(nonatomic, readonly) id APIService; @property(nonatomic, readonly, nullable, copy) NSString *debugTokenEnvValue; +@property(nonatomic, readonly, copy) NSString *registeredUserDefaultsKey; + ++ (NSString *)registeredUserDefaultsKeyForServiceName:(NSString *)serviceName + resourceName:(NSString *)resourceName; @end +static NSString *_Nullable EnvironmentVariableDebugToken(NSString *registeredUserDefaultsKey); + @implementation GACAppCheckDebugProvider -- (instancetype)initWithAPIService:(id)APIService { +- (instancetype)initWithAPIService:(id)APIService + serviceName:(NSString *)serviceName + resourceName:(NSString *)resourceName { self = [super init]; if (self) { _APIService = APIService; - _debugTokenEnvValue = EnvironmentVariableDebugToken(); + _registeredUserDefaultsKey = + [[[self class] registeredUserDefaultsKeyForServiceName:serviceName + resourceName:resourceName] copy]; + _debugTokenEnvValue = EnvironmentVariableDebugToken(_registeredUserDefaultsKey); } return self; } @@ -71,7 +86,9 @@ - (instancetype)initWithServiceName:(NSString *)serviceName [[GACAppCheckDebugProviderAPIService alloc] initWithAPIService:APIService resourceName:resourceName]; - return [self initWithAPIService:debugAPIService]; + return [self initWithAPIService:debugAPIService + serviceName:serviceName + resourceName:resourceName]; } - (NSString *)currentDebugToken { @@ -109,8 +126,7 @@ - (void)getTokenWithLimitedUse:(BOOL)limitedUse return [self.APIService appCheckTokenWithDebugToken:debugToken limitedUse:limitedUse]; }) .then(^id(GACAppCheckToken *appCheckToken) { - [[GULUserDefaults standardUserDefaults] setBool:YES - forKey:kDebugTokenRegisteredUserDefaultsKey]; + [[GULUserDefaults standardUserDefaults] setBool:YES forKey:self.registeredUserDefaultsKey]; handler(appCheckToken, nil); return nil; }) @@ -120,7 +136,7 @@ - (void)getTokenWithLimitedUse:(BOOL)limitedUse GACAppCheckLogDebug(GACLoggerAppCheckMessageDebugProviderFailedExchange, logMessage); if (error.code != GACAppCheckErrorCodeServerUnreachable) { [[GULUserDefaults standardUserDefaults] - removeObjectForKey:kDebugTokenRegisteredUserDefaultsKey]; + removeObjectForKey:self.registeredUserDefaultsKey]; } handler(nil, error); }); @@ -140,7 +156,19 @@ - (void)getTokenWithLimitedUse:(BOOL)limitedUse return token; } -static NSString *_Nullable EnvironmentVariableDebugToken(void) { ++ (NSString *)registeredUserDefaultsKeyForServiceName:(NSString *)serviceName + resourceName:(NSString *)resourceName { + NSString *safeServiceName = serviceName.length > 0 ? serviceName : @"default"; + NSString *safeResourceName = [resourceName stringByReplacingOccurrencesOfString:@"/" + withString:@"_"]; + if (safeResourceName.length == 0) { + safeResourceName = @"default"; + } + return [NSString stringWithFormat:@"%@_%@_%@", kDebugTokenRegisteredUserDefaultsKey, + safeServiceName, safeResourceName]; +} + +static NSString *_Nullable EnvironmentVariableDebugToken(NSString *registeredUserDefaultsKey) { NSDictionary *environment = [[NSProcessInfo processInfo] environment]; NSString *envVariableValue = environment[kDebugTokenEnvKey]; NSString *firebaseEnvVariableValue = environment[kFirebaseDebugTokenEnvKey]; @@ -183,7 +211,7 @@ - (void)getTokenWithLimitedUse:(BOOL)limitedUse return firebaseEnvVariableValue; } else { BOOL isRegistered = - [[GULUserDefaults standardUserDefaults] boolForKey:kDebugTokenRegisteredUserDefaultsKey]; + [[GULUserDefaults standardUserDefaults] boolForKey:registeredUserDefaultsKey]; if (!isRegistered) { // Print only a locally generated token to avoid a valid token leak on CI. GACAppCheckLog( diff --git a/AppCheckCore/Tests/Unit/DebugProvider/GACAppCheckDebugProviderTests.m b/AppCheckCore/Tests/Unit/DebugProvider/GACAppCheckDebugProviderTests.m index 8baf0712..28bcce27 100644 --- a/AppCheckCore/Tests/Unit/DebugProvider/GACAppCheckDebugProviderTests.m +++ b/AppCheckCore/Tests/Unit/DebugProvider/GACAppCheckDebugProviderTests.m @@ -32,7 +32,14 @@ @interface GACAppCheckDebugProvider (Tests) -- (instancetype)initWithAPIService:(id)APIService; +- (instancetype)initWithAPIService:(id)APIService + serviceName:(NSString *)serviceName + resourceName:(NSString *)resourceName; + ++ (NSString *)registeredUserDefaultsKeyForServiceName:(NSString *)serviceName + resourceName:(NSString *)resourceName; + +@property(nonatomic, readonly, copy) NSString *registeredUserDefaultsKey; @end @@ -53,7 +60,10 @@ - (void)setUp { self.processInfoMock = OCMPartialMock([NSProcessInfo processInfo]); self.fakeAPIService = OCMProtocolMock(@protocol(GACAppCheckDebugProviderAPIServiceProtocol)); - self.provider = [[GACAppCheckDebugProvider alloc] initWithAPIService:self.fakeAPIService]; + self.provider = + [[GACAppCheckDebugProvider alloc] initWithAPIService:self.fakeAPIService + serviceName:@"test-service" + resourceName:@"projects/test-project/apps/test-app"]; } - (void)tearDown { @@ -73,7 +83,10 @@ - (void)testCurrentTokenWhenEnvironmentVariableSetAndTokenStored { NSString *envToken = @"env token"; OCMExpect([self.processInfoMock processInfo]).andReturn(self.processInfoMock); OCMExpect([self.processInfoMock environment]).andReturn(@{kDebugTokenEnvKey : envToken}); - self.provider = [[GACAppCheckDebugProvider alloc] initWithAPIService:self.fakeAPIService]; + self.provider = + [[GACAppCheckDebugProvider alloc] initWithAPIService:self.fakeAPIService + serviceName:@"test-service" + resourceName:@"projects/test-project/apps/test-app"]; XCTAssertEqualObjects([self.provider currentDebugToken], envToken); } @@ -86,7 +99,10 @@ - (void)testCurrentTokenWhenFirebaseAndCoreEnvironmentVariablesSetAndTokenStored OCMExpect([self.processInfoMock environment]) .andReturn( (@{kDebugTokenEnvKey : envToken, kFirebaseDebugTokenEnvKey : @"firebase env token"})); - self.provider = [[GACAppCheckDebugProvider alloc] initWithAPIService:self.fakeAPIService]; + self.provider = + [[GACAppCheckDebugProvider alloc] initWithAPIService:self.fakeAPIService + serviceName:@"test-service" + resourceName:@"projects/test-project/apps/test-app"]; XCTAssertEqualObjects([self.provider currentDebugToken], envToken); } @@ -99,7 +115,10 @@ - (void)testCurrentTokenWhenFirebaseEnvironmentVariableSetAndTokenStored { OCMExpect([self.processInfoMock environment]).andReturn((@{ kFirebaseDebugTokenEnvKey : envToken })); - self.provider = [[GACAppCheckDebugProvider alloc] initWithAPIService:self.fakeAPIService]; + self.provider = + [[GACAppCheckDebugProvider alloc] initWithAPIService:self.fakeAPIService + serviceName:@"test-service" + resourceName:@"projects/test-project/apps/test-app"]; XCTAssertEqualObjects([self.provider currentDebugToken], envToken); } @@ -110,7 +129,10 @@ - (void)testCurrentTokenWhenFirebaseAndCoreEnvironmentVariablesSet { OCMExpect([self.processInfoMock environment]) .andReturn( (@{kDebugTokenEnvKey : envToken, kFirebaseDebugTokenEnvKey : @"firebase env token"})); - self.provider = [[GACAppCheckDebugProvider alloc] initWithAPIService:self.fakeAPIService]; + self.provider = + [[GACAppCheckDebugProvider alloc] initWithAPIService:self.fakeAPIService + serviceName:@"test-service" + resourceName:@"projects/test-project/apps/test-app"]; XCTAssertEqualObjects([self.provider currentDebugToken], envToken); } @@ -235,11 +257,13 @@ - (void)testGetTokenSuccessSetsRegisteredFlag { GACAppCheckToken *validToken = [[GACAppCheckToken alloc] initWithToken:@"valid_token" expirationDate:[NSDate date] receivedAtDate:[NSDate date]]; + FBLPromise *resolvedPromise = [FBLPromise pendingPromise]; + [resolvedPromise fulfill:validToken]; OCMExpect([self.fakeAPIService appCheckTokenWithDebugToken:expectedDebugToken limitedUse:NO]) - .andReturn([FBLPromise resolvedWith:validToken]); + .andReturn(resolvedPromise); - // Ensure flag is not set. - [[GULUserDefaults standardUserDefaults] removeObjectForKey:kDebugTokenRegisteredUserDefaultsKey]; + [[GULUserDefaults standardUserDefaults] + removeObjectForKey:self.provider.registeredUserDefaultsKey]; // 2. Validate get token. [self validateGetToken:^(GACAppCheckToken *_Nullable token, NSError *_Nullable error) { @@ -249,7 +273,7 @@ - (void)testGetTokenSuccessSetsRegisteredFlag { // 3. Verify flag is now YES. XCTAssertTrue( - [[GULUserDefaults standardUserDefaults] boolForKey:kDebugTokenRegisteredUserDefaultsKey]); + [[GULUserDefaults standardUserDefaults] boolForKey:self.provider.registeredUserDefaultsKey]); // 4. Verify fakes. OCMVerifyAll(self.fakeAPIService); @@ -267,7 +291,8 @@ - (void)testGetTokenPermanentFailureClearsRegisteredFlag { .andReturn(rejectedPromise); // Pre-populate flag to YES. - [[GULUserDefaults standardUserDefaults] setBool:YES forKey:kDebugTokenRegisteredUserDefaultsKey]; + [[GULUserDefaults standardUserDefaults] setBool:YES + forKey:self.provider.registeredUserDefaultsKey]; // 2. Validate get token. [self validateGetToken:^(GACAppCheckToken *_Nullable token, NSError *_Nullable error) { @@ -276,8 +301,8 @@ - (void)testGetTokenPermanentFailureClearsRegisteredFlag { }]; // 3. Verify flag is cleared. - XCTAssertNil( - [[GULUserDefaults standardUserDefaults] objectForKey:kDebugTokenRegisteredUserDefaultsKey]); + XCTAssertNil([[GULUserDefaults standardUserDefaults] + objectForKey:self.provider.registeredUserDefaultsKey]); // 4. Verify fakes. OCMVerifyAll(self.fakeAPIService); @@ -295,7 +320,8 @@ - (void)testGetTokenNetworkFailureDoesNotClearRegisteredFlag { .andReturn(rejectedPromise); // Pre-populate flag to YES. - [[GULUserDefaults standardUserDefaults] setBool:YES forKey:kDebugTokenRegisteredUserDefaultsKey]; + [[GULUserDefaults standardUserDefaults] setBool:YES + forKey:self.provider.registeredUserDefaultsKey]; // 2. Validate get token. [self validateGetToken:^(GACAppCheckToken *_Nullable token, NSError *_Nullable error) { @@ -305,12 +331,31 @@ - (void)testGetTokenNetworkFailureDoesNotClearRegisteredFlag { // 3. Verify flag is still YES. XCTAssertTrue( - [[GULUserDefaults standardUserDefaults] boolForKey:kDebugTokenRegisteredUserDefaultsKey]); + [[GULUserDefaults standardUserDefaults] boolForKey:self.provider.registeredUserDefaultsKey]); // 4. Verify fakes. OCMVerifyAll(self.fakeAPIService); } +#pragma mark - Keys + +- (void)testRegisteredUserDefaultsKeyForServiceName_resourceName { + XCTAssertEqualObjects( + [GACAppCheckDebugProvider registeredUserDefaultsKeyForServiceName:@"app1" + resourceName:@"projects/p1/apps/a1"], + @"GACAppCheckDebugTokenRegistered_app1_projects_p1_apps_a1"); + XCTAssertEqualObjects( + [GACAppCheckDebugProvider registeredUserDefaultsKeyForServiceName:@"app2" + resourceName:@"projects/p2/apps/a2"], + @"GACAppCheckDebugTokenRegistered_app2_projects_p2_apps_a2"); + XCTAssertEqualObjects([GACAppCheckDebugProvider registeredUserDefaultsKeyForServiceName:@"" + resourceName:@""], + @"GACAppCheckDebugTokenRegistered_default_default"); + XCTAssertEqualObjects([GACAppCheckDebugProvider registeredUserDefaultsKeyForServiceName:nil + resourceName:nil], + @"GACAppCheckDebugTokenRegistered_default_default"); +} + #pragma mark - Helpers - (void)validateGetToken:(GACAppCheckTokenValidationBlock)validationBlock { From e4f27da61a45c012cb49affd3fb6ff9bd8e8567f Mon Sep 17 00:00:00 2001 From: Nick Cooke Date: Tue, 9 Jun 2026 18:30:00 -0400 Subject: [PATCH 5/5] CHANGELOG.md --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0fd105fd..f455b589 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # 11.3.0 -- [changed] Added Recaptcha Enterprise attestation provider. +- [changed] Added Recaptcha Enterprise attestation provider. (#94) +- [changed] Only log local debug tokens when not yet registered. (#95) # 11.2.0 - [changed] To prevent reusing expired artifacts, skip local cache when making