fix(common): preserve DEFAULT_PROJECT_ID_TOKEN in joinURIComponents() - #9315
akiliscodes wants to merge 3 commits into
Conversation
|
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
There was a problem hiding this comment.
Code Review
This pull request addresses a regression where the DEFAULT_PROJECT_ID_TOKEN was encoded, breaking lazy/ADC project-ID resolution. The changes update joinURIComponents to bypass encoding for this token and add corresponding unit tests. The review feedback points out two critical issues: a missing import of replaceProjectIdToken in the test file, and a potential circular dependency if DEFAULT_PROJECT_ID_TOKEN is imported from service into util. The reviewer suggests moving the token definition to util.ts to resolve the circular dependency cleanly.
| ParsedHttpRespMessage, | ||
| ParsedHttpResponseBody, | ||
| Util, | ||
| joinURIComponents, |
| const trimSlashesRegex = /^\/*|\/*$/g; | ||
| const trimmed = uriComponent.replace(trimSlashesRegex, ''); | ||
| const trimmed = uriComponent.replace(/^\/*|\/*$/g, ''); | ||
| if (trimmed === DEFAULT_PROJECT_ID_TOKEN) return trimmed; |
There was a problem hiding this comment.
Using DEFAULT_PROJECT_ID_TOKEN here will cause a compilation error if it is not imported. However, importing it from ./service into ./util introduces a circular dependency (service -> util -> service), which can lead to runtime issues (e.g., DEFAULT_PROJECT_ID_TOKEN being evaluated as undefined during module initialization).
To resolve this cleanly, consider defining DEFAULT_PROJECT_ID_TOKEN in src/util.ts and exporting it, then re-exporting it from src/service.ts to maintain backward compatibility.
encodeURIPath encodes '{{projectId}}' as '%7B%7BprojectId%7D%7D',
which prevents replaceProjectIdToken() from finding and substituting
the placeholder later in the request lifecycle (decorateRequest →
makeAuthenticatedRequest).
Skip encoding when the trimmed component equals DEFAULT_PROJECT_ID_TOKEN
so that ADC / lazy project-ID resolution continues to work for clients
that do not supply an explicit projectId (e.g. new BigQuery()).
Regression introduced by googleapis#9188.
Fixes googleapis#9256.
ba0c03b to
8e247fb
Compare
Summary
Preserve
DEFAULT_PROJECT_ID_TOKENwhen building request URIs withjoinURIComponents()so lazy project ID resolution can still replace the placeholder before the request is sent.Problem
#9188 hardened
joinURIComponents()against path traversal by encoding path components withencodeURIPath().This also causes the internal
DEFAULT_PROJECT_ID_TOKENplaceholder ({{projectId}}) to be encoded as%7B%7BprojectId%7D%7D.Project ID substitution happens later, when
decorateRequest()callsreplaceProjectIdToken(). Because that function looks for the literal{{projectId}}token, it can no longer recognize the encoded placeholder.As a result, clients relying on lazy project ID resolution can send the encoded placeholder to the backend instead of the resolved project ID, causing the request to fail.
Reported in #9256.
Fix
Update
joinURIComponents()to preserveDEFAULT_PROJECT_ID_TOKENwhen a trimmed path component exactly matches the library-owned token.Only this exact internal constant bypasses encoding. All other path components continue through
encodeURIPath(), preserving the path-traversal protection introduced in #9188.This allows the existing request flow to work as intended:
Testing
Added coverage for both the regression and the existing URI-encoding behavior:
test/util.tsDEFAULT_PROJECT_ID_TOKENsurvivesjoinURIComponents()and can subsequently be replaced byreplaceProjectIdToken(){{../../admin}}do not bypass encoding/path-traversal protectiontest/service.tsService.request_()preserves the literal{{projectId}}placeholder until the request-decoration phase when no explicit project ID is providedChecklist
DEFAULT_PROJECT_ID_TOKENbeforereplaceProjectIdToken()runs #9256Fixes #9256 🦕