Conversation
The 401 branch recursed with the same stale error object and an unincremented counter, so a token refresh that succeeded without clearing the 401 looped forever, issuing a real refresh-endpoint call each pass. The maxRetryCount cap existed only on the 429/408 branch. Apply the same guard: attempt one refresh, then print a clear error and exit if the 401 persists. The cap is 2 rather than the 429/408 branch's 3 because a single refresh is enough to establish that the token is dead. This brings v1-legacy in line with the v2 fix, which was never backported. The resulting file is byte-identical to the one on main. Reachability note: the callers in @contentstack/cli-variants pass an HttpResponse, whose `response` field is TypeScript-private but a real property at runtime, so `error.response.status` resolves and the branch is genuinely reachable. Adds test/unit/authentication-handler.test.ts, the first coverage for this file in either branch. Eight cases across the 401 and 429/408 paths, including a regression guard that hangs indefinitely without this fix. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
🔒 Security Scan Results
⏱️ SLA Breach Summary
ℹ️ Vulnerabilities Without Available Fixes (Informational Only)The following vulnerabilities were detected but do not have fixes available (no upgrade or patch). These are excluded from failure thresholds:
Consider reviewing these vulnerabilities when fixes become available. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
refreshAccessToken's 401 branch recursed with the same stale error object and an unincremented counter:The
maxRetryCountcap existed only on the 429/408 branch, so nothing terminated the 401 path. A refresh that succeeded without clearing the 401 looped forever, issuing a real refresh-endpoint call on every pass.This is the v1 counterpart of the v2 fix, which was never backported.
v1-legacy's copy of the file was byte-identical to main's pre-fix version, so the change applies exactly as it did there.Fix
Apply the same guard the 429/408 branch already uses — one refresh attempt, then a clear error and exit:
The cap is
2rather than the 429/408 branch's3because one refresh is enough to establish the token is dead. The resulting file is byte-identical to the version onmain.Reachability
Worth a reviewer's attention, because it is subtle. The callers in
@contentstack/cli-variants(personalization-api-adapter.ts:311,variant-api-adapter.ts:336) pass anHttpResponse, andAPIResponseis typed{ status, data }with noresponsefield — which suggests the guarderror.response?.statuscould never pass.It does pass.
HttpResponsedeclaresprivate readonly response: AxiosResponseand assigns it in the constructor; TypeScript'sprivateis erased at compile time, so.responseis a real own property at runtime. The branch is genuinely reachable — just via accidental coupling to an erased-private field. Not changed here, but worth knowing.Tests
Adds
test/unit/authentication-handler.test.ts— the first coverage for this file in either branch (the v2 fix shipped without tests). Eight cases:401 handling
cmacmais configuredOther statuses
responseThe regression guard was verified to actually catch the bug: with the source fix reverted, the suite hangs indefinitely and has to be killed. With the fix, all 8 pass in ~2s.
Verification
contentstack-utilitiessuite: 114 passingpnpm buildpassesNotes
DX-23-09-2026-Releaserather thanv1-legacy, so merging does not trigger the release workflow. Pairs with fix(deps): declare tslib as a runtime dependency #2724 and fix(deps): declare tslib as a runtime dependency cli-plugins#370.cli-pluginsis not affected.compareOAuthExpiry(true)atauth-handler.ts:391-393skips theisRefreshingTokenguard. It self-limits at two levels so it is not a live bug, but it is why each loop iteration hit the real refresh endpoint.🤖 Generated with Claude Code