Skip to content

Cover credential refresh coalescing - #148

Merged
HemSoft merged 2 commits into
mainfrom
fix/issue-147-credential-refresh-coalescing
Aug 7, 2026
Merged

Cover credential refresh coalescing#148
HemSoft merged 2 commits into
mainfrom
fix/issue-147-credential-refresh-coalescing

Conversation

@HemSoft

@HemSoft HemSoft commented Aug 7, 2026

Copy link
Copy Markdown
Owner

Closes #147

Summary

  • exercise same-account task joining and different-account isolation directly in CredentialRefreshCoordinator
  • cover concurrent GitHub Copilot browser credential refreshes with an isolated URL session and explicit async gates
  • add a bounded test watchdog that returns without awaiting cancellation-insensitive operations
  • record the concurrency coverage under Unreleased / Developer Experience

Verification

  • ./test.sh (351 tests; cut-changelog, release-artifact, and run smoke scripts passed)
  • xcodebuild ... -enableThreadSanitizer YES test (351 tests; no sanitizer reports)
  • xcodebuild ... analyze
  • targeted coverage run with -enableCodeCoverage YES plus xccov (existing-task return executed twice)

Risk

  • Production behavior is unchanged except for a package-internal, optional observation callback used only by deterministic tests.

Summary by cubic

Add deterministic concurrency coverage for account-scoped credential-refresh coalescing. Confirms concurrent Copilot browser refreshes join a single in-flight task per account and stay isolated across accounts.

  • Refactors
    • Added onJoinExistingTask to CredentialRefreshCoordinator.run() and wired onJoinInFlightRefresh through CopilotUsageProvider as an internal-only test hook.
    • Introduced IsolatedTestURLSession (custom URLProtocol) to sandbox concurrent network tests.
    • Hardened test sync: added TestSignal, TestAsyncGate, and a bounded watchdog with a start latch and task coordination; verifies it doesn’t await cancellation-insensitive work.
    • New tests cover same-account joining, multi-account isolation, watchdog timeout behavior, and Copilot concurrent refresh coalescing (single refresh request, shared token).

Written for commit ca1849d. Summary will update on new commits.

Review in cubic

Note

Add tests covering credential refresh coalescing in CredentialRefreshCoordinator and CopilotUsageProvider

  • Adds CredentialRefreshCoordinatorTests with tests for same-account coalescing, independent multi-account execution, and watchdog timeout behavior.
  • Adds testConcurrentCopilotFetchesCoalesceBrowserCredentialRefresh to CopilotProviderTests to verify concurrent fetches share a single refresh and propagate the new token correctly.
  • Adds an onJoinInFlightRefresh callback to CopilotUsageProvider and onJoinExistingTask to CredentialRefreshCoordinator.run to make join events observable in tests without changing default behavior.
  • Introduces test support utilities in NetworkTestSupport.swift (isolated per-test URLSession/URLProtocol) and RefreshTestSupport.swift (withTestWatchdog, TestAsyncGate, TestSignal) to enable deterministic async concurrency testing.

Macroscope summarized 37fa304.

Greptile Summary

The PR adds deterministic test coverage for account-scoped credential-refresh coalescing without changing the default production behavior.

  • Adds same-account joining and different-account isolation tests for CredentialRefreshCoordinator.
  • Adds an isolated URL-session fixture and concurrent Copilot credential-refresh coverage.
  • Adds bounded watchdog and synchronization utilities for asynchronous tests.
  • Exposes an internal optional join-observation callback used by deterministic tests.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
CodexBarMac/Services/CredentialRefreshCoordinator.swift Adds an optional callback when a caller joins an existing account-scoped refresh task; default behavior is unchanged.
CodexBarMac/Services/CopilotUsageProvider.swift Adds an internal test-observation hook while preserving the existing public initializer and production defaults.
CodexBarMacTests/CredentialRefreshCoordinatorTests.swift Covers same-account coalescing, different-account isolation, and cancellation-insensitive watchdog behavior.
CodexBarMacTests/CopilotProviderTests.swift Adds deterministic concurrent Copilot refresh coverage using explicit join and network gates.
CodexBarMacTests/NetworkTestSupport.swift Adds per-session URL protocol handler isolation and idempotent cleanup for concurrent network tests.
CodexBarMacTests/RefreshTestSupport.swift Adds async signals, gates, and a bounded watchdog that returns without awaiting cancellation-insensitive operations.

Sequence Diagram

sequenceDiagram
    participant F1 as First fetch
    participant F2 as Second fetch
    participant C as Refresh coordinator
    participant R as Credential refresh

    F1->>C: run(account)
    C->>R: start refresh task
    F2->>C: run(same account)
    C-->>F2: join existing task
    R-->>C: refreshed credentials
    C-->>F1: shared result
    C-->>F2: shared result
Loading

Reviews (2): Last reviewed commit: "Harden concurrency test synchronization" | Re-trigger Greptile

@cursor

cursor Bot commented Aug 7, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@HemSoft

HemSoft commented Aug 7, 2026

Copy link
Copy Markdown
Owner Author

@macroscope-app review

@HemSoft

HemSoft commented Aug 7, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes

    • Improved concurrent credential refresh handling so simultaneous requests for the same account share a single refresh operation.
    • Ensured concurrent Copilot usage requests use the refreshed access token and return consistent results.
    • Preserved independent refresh operations for different accounts.
  • Tests

    • Added coverage for concurrent refreshes, cancellation handling, timeout behavior, and isolated network request scenarios.

Walkthrough

Changes

Credential refresh concurrency

Layer / File(s) Summary
Coordinator coalescing contract and tests
CodexBarMac/Services/CredentialRefreshCoordinator.swift, CodexBarMacTests/CredentialRefreshCoordinatorTests.swift, CodexBarMacTests/RefreshTestSupport.swift, CodexBarMac.xcodeproj/project.pbxproj
The coordinator reports when a caller joins an existing account task. Tests cover same-account sharing, account isolation, and watchdog handling.
Copilot refresh integration and isolated requests
CodexBarMac/Services/CopilotUsageProvider.swift, CodexBarMacTests/CopilotProviderTests.swift, CodexBarMacTests/NetworkTestSupport.swift, CHANGELOG.md
Copilot passes the join callback to the coordinator. Concurrent provider tests verify one refresh request, refreshed authorization headers, and successful results using isolated request handlers.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related issues

Possibly related PRs

Sequence Diagram(s)

sequenceDiagram
  participant CopilotProviderTests
  participant CopilotUsageProvider
  participant CredentialRefreshCoordinator
  participant IsolatedTestURLSession
  CopilotProviderTests->>CopilotUsageProvider: start two concurrent fetches
  CopilotUsageProvider->>CredentialRefreshCoordinator: refresh credentials for account
  CredentialRefreshCoordinator->>IsolatedTestURLSession: perform one token refresh request
  CopilotUsageProvider->>CredentialRefreshCoordinator: join existing account refresh
  CredentialRefreshCoordinator-->>CopilotUsageProvider: return shared refreshed credential
  CopilotUsageProvider->>IsolatedTestURLSession: send usage requests with refreshed token
  IsolatedTestURLSession-->>CopilotProviderTests: return both usage results
Loading

Poem

A rabbit watched two refresh calls race,
One shared token held its place.
Gates stayed steady, watchdogs wise,
Two Copilot results came back in size.
“Hop,” said the rabbit, “the tests now sing!”

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes satisfy the deterministic coordinator, Copilot, watchdog, isolation, coverage, test, and changelog objectives in [#147].
Out of Scope Changes check ✅ Passed All production and test changes support the linked issue objectives, with no unrelated code changes identified.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Title check ✅ Passed The title clearly summarizes the main change: coverage for credential refresh coalescing.
Description check ✅ Passed The description directly explains the concurrency tests, supporting utilities, verification, and production impact.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/issue-147-credential-refresh-coalescing

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@macroscopeapp

macroscopeapp Bot commented Aug 7, 2026

Copy link
Copy Markdown

Manual reviews triggered for commit ca1849d:

All prior checks · these links stay valid even if you push more commits.

@macroscopeapp

macroscopeapp Bot commented Aug 7, 2026

Copy link
Copy Markdown

Review in progress. Results will be posted when the checks complete.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Bravo.

Reviewed commit: 37fa304f6f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
CodexBarMac/Services/CopilotUsageProvider.swift (1)

34-79: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Delegate the public initializer to the internal one to remove the duplicated body.

The two initializers assign the same nine stored properties and repeat the gitHubTokenResolver fallback that calls LocalCredentialDiscovery.gitHubAuthToken(for:). A future dependency or a change to the resolver fallback must be applied twice. Convergence failures in this type affect credential resolution.

Keep the public signature and defaults, and forward to the internal initializer.

♻️ Proposed refactor
     public init(
         secretStore: any SecretStore = KeychainService(),
         session: URLSession = .shared,
         usageEndpoint: URL = URL(string: "https://api.github.com/copilot_internal/user")!,
         githubAPIBaseURL: URL = URL(string: "https://api.github.com")!,
         tokenEndpoint: URL = CopilotWebAuthService.tokenEndpoint,
         oauthConfiguration: CopilotOAuthConfiguration = .bundled,
         gitHubTokenResolver: (`@Sendable` (String?) throws -> String?)? = nil,
         now: `@escaping` `@Sendable` () -> Date = { Date() }
     ) {
-        self.secretStore = secretStore
-        self.session = session
-        self.usageEndpoint = usageEndpoint
-        self.githubAPIBaseURL = githubAPIBaseURL
-        self.tokenEndpoint = tokenEndpoint
-        self.oauthConfiguration = oauthConfiguration
-        self.gitHubTokenResolver = gitHubTokenResolver ?? { username in
-            try LocalCredentialDiscovery.gitHubAuthToken(for: username)
-        }
-        self.now = now
-        self.onJoinInFlightRefresh = nil
+        self.init(
+            secretStore: secretStore,
+            session: session,
+            usageEndpoint: usageEndpoint,
+            githubAPIBaseURL: githubAPIBaseURL,
+            tokenEndpoint: tokenEndpoint,
+            oauthConfiguration: oauthConfiguration,
+            gitHubTokenResolver: gitHubTokenResolver,
+            now: now,
+            onJoinInFlightRefresh: nil
+        )
     }

Note: a delegating initializer in a class must be marked convenience, and the internal initializer stays designated. Verify the build after the change.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CodexBarMac/Services/CopilotUsageProvider.swift` around lines 34 - 79, Mark
the public init in CopilotUsageProvider as convenience and delegate to the
existing internal initializer, forwarding all parameters including the public
defaults and passing through onJoinInFlightRefresh as nil. Remove its duplicated
property assignments and gitHubTokenResolver fallback, leaving the internal
initializer as the designated initializer.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@CodexBarMacTests/CredentialRefreshCoordinatorTests.swift`:
- Around line 103-123: Update TestAsyncGate in RefreshTestSupport.swift so
waitUntilBlocked() cannot complete until wait() has stored its continuation,
ensuring a concurrent release() always resumes the suspended operation. Preserve
the existing gate behavior and API while reordering the blocked
signal/continuation setup.

In `@CodexBarMacTests/RefreshTestSupport.swift`:
- Line 55: Add explicit empty deinitializers to all new classes required by
SwiftLint: TestWatchdogStartLatch, TestWatchdogTaskCoordinator, and
TestWatchdogOutcomeCoordinator in RefreshTestSupport.swift;
CredentialRefreshCoordinatorTests and LockedTestFlag in
CredentialRefreshCoordinatorTests.swift. Apply the same deinit convention
already used by the test suite at the cited anchor and sibling sites.

---

Outside diff comments:
In `@CodexBarMac/Services/CopilotUsageProvider.swift`:
- Around line 34-79: Mark the public init in CopilotUsageProvider as convenience
and delegate to the existing internal initializer, forwarding all parameters
including the public defaults and passing through onJoinInFlightRefresh as nil.
Remove its duplicated property assignments and gitHubTokenResolver fallback,
leaving the internal initializer as the designated initializer.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: f3fa97fc-0628-42b8-8e3d-54bb4a091b0b

📥 Commits

Reviewing files that changed from the base of the PR and between bb3689f and 37fa304.

📒 Files selected for processing (8)
  • CHANGELOG.md
  • CodexBarMac.xcodeproj/project.pbxproj
  • CodexBarMac/Services/CopilotUsageProvider.swift
  • CodexBarMac/Services/CredentialRefreshCoordinator.swift
  • CodexBarMacTests/CopilotProviderTests.swift
  • CodexBarMacTests/CredentialRefreshCoordinatorTests.swift
  • CodexBarMacTests/NetworkTestSupport.swift
  • CodexBarMacTests/RefreshTestSupport.swift

Comment thread CodexBarMacTests/CredentialRefreshCoordinatorTests.swift
Comment thread CodexBarMacTests/RefreshTestSupport.swift
@macroscopeapp

macroscopeapp Bot commented Aug 7, 2026

Copy link
Copy Markdown

Approvability

Verdict: Would Approve

This PR adds test coverage for credential refresh coalescing with minimal production code changes. The production modifications are limited to adding optional callback parameters (defaulting to nil) for test observability, maintaining full backward compatibility.

Macroscope would have approved this PR. Enable approvability here.

@HemSoft

HemSoft commented Aug 7, 2026

Copy link
Copy Markdown
Owner Author

Addressed CodeRabbit’s outside-diff initializer finding in ca1849d: the public CopilotUsageProvider initializer is now convenience and delegates to the package-internal designated initializer, removing duplicated dependency setup. Full XCTest, smoke, and Thread Sanitizer runs pass.

@HemSoft

HemSoft commented Aug 7, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@HemSoft

HemSoft commented Aug 7, 2026

Copy link
Copy Markdown
Owner Author

@macroscope-app review

@HemSoft

HemSoft commented Aug 7, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@macroscopeapp

macroscopeapp Bot commented Aug 7, 2026

Copy link
Copy Markdown

Review in progress. Results will be posted when the checks complete.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. What shall we delve into next?

Reviewed commit: ca1849db6c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@HemSoft
HemSoft merged commit f97038b into main Aug 7, 2026
6 checks passed
@HemSoft
HemSoft deleted the fix/issue-147-credential-refresh-coalescing branch August 7, 2026 07:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cover concurrent credential-refresh coalescing

1 participant