Skip to content
This repository was archived by the owner on Nov 20, 2025. It is now read-only.

Commit ba48164

Browse files
fix: throw when adc cannot acquire a projectId (#658)
1 parent 48a1c81 commit ba48164

File tree

3 files changed

+49
-34
lines changed

3 files changed

+49
-34
lines changed

src/auth/googleauth.ts

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -170,19 +170,24 @@ export class GoogleAuth {
170170
// - Cloud SDK: `gcloud config config-helper --format json`
171171
// - GCE project ID from metadata server)
172172
if (!this._getDefaultProjectIdPromise) {
173-
this._getDefaultProjectIdPromise =
174-
new Promise(async (resolve, reject) => {
175-
try {
176-
const projectId = this.getProductionProjectId() ||
177-
await this.getFileProjectId() ||
178-
await this.getDefaultServiceProjectId() ||
179-
await this.getGCEProjectId();
180-
this._cachedProjectId = projectId;
181-
resolve(projectId);
182-
} catch (e) {
183-
reject(e);
184-
}
185-
});
173+
this._getDefaultProjectIdPromise = new Promise(async (resolve, reject) => {
174+
try {
175+
const projectId = this.getProductionProjectId() ||
176+
await this.getFileProjectId() ||
177+
await this.getDefaultServiceProjectId() ||
178+
await this.getGCEProjectId();
179+
this._cachedProjectId = projectId;
180+
if (!projectId) {
181+
throw new Error(
182+
'Unable to detect a Project Id in the current environment. \n' +
183+
'To learn more about authentication and Google APIs, visit: \n' +
184+
'https://cloud.google.com/docs/authentication/getting-started');
185+
}
186+
resolve(projectId);
187+
} catch (e) {
188+
reject(e);
189+
}
190+
});
186191
}
187192
return this._getDefaultProjectIdPromise;
188193
}

test/fixtures/private.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@
33
"private_key": "privatekey",
44
"client_email": "hello@youarecool.com",
55
"client_id": "client123",
6-
"type": "service_account"
6+
"type": "service_account",
7+
"project_id": "not-a-project-id"
78
}

test/test.googleauth.ts

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ describe('googleauth', () => {
7878
return nock(host).get(instancePath).reply(404);
7979
}
8080

81-
function createGetProjectIdNock(projectId: string) {
81+
function createGetProjectIdNock(projectId = 'not-real') {
8282
return nock(host)
8383
.get(`${BASE_PATH}/project/project-id`)
8484
.reply(200, projectId, HEADERS);
@@ -108,11 +108,6 @@ describe('googleauth', () => {
108108
return {auth, scopes: [scope1, scope2]};
109109
}
110110

111-
// Matches the ending of a string.
112-
function stringEndsWith(str: string, suffix: string) {
113-
return str.indexOf(suffix, str.length - suffix.length) !== -1;
114-
}
115-
116111
// Simulates a path join.
117112
function pathJoin(item1: string, item2: string) {
118113
return item1 + ':' + item2;
@@ -871,16 +866,13 @@ describe('googleauth', () => {
871866

872867
it('getApplicationDefault should return a new credential the first time and a cached credential the second time',
873868
async () => {
874-
const scope = nockNotGCE();
875869
// Create a function which will set up a GoogleAuth instance to match
876870
// on an environment variable json file, but not on anything else.
877871
mockEnvVar(
878872
'GOOGLE_APPLICATION_CREDENTIALS', './test/fixtures/private.json');
879-
auth._fileExists = () => false;
880873

881874
// Ask for credentials, the first time.
882875
const result = await auth.getApplicationDefault();
883-
scope.isDone();
884876
assert.notEqual(null, result);
885877

886878
// Capture the returned credential.
@@ -931,11 +923,11 @@ describe('googleauth', () => {
931923
async () => {
932924
blockGoogleApplicationCredentialEnvironmentVariable();
933925
auth._fileExists = () => false;
934-
const scope = nockIsGCE();
926+
const scopes = [nockIsGCE(), createGetProjectIdNock()];
935927

936928
// Ask for credentials, the first time.
937929
const result = await auth.getApplicationDefault();
938-
scope.done();
930+
scopes.forEach(x => x.done());
939931
assert.notEqual(null, result);
940932

941933
// Capture the returned credential.
@@ -1012,9 +1004,9 @@ describe('googleauth', () => {
10121004
auth._pathJoin = pathJoin;
10131005
auth._osPlatform = () => 'win32';
10141006
auth._fileExists = () => false;
1015-
const scope = nockIsGCE();
1007+
const scopes = [nockIsGCE(), createGetProjectIdNock()];
10161008
const res = await auth.getApplicationDefault();
1017-
scope.done();
1009+
scopes.forEach(x => x.done());
10181010
// This indicates that we got a ComputeClient instance back, rather than
10191011
// a JWTClient.
10201012
assert.strictEqual(
@@ -1141,7 +1133,7 @@ describe('googleauth', () => {
11411133
}
11421134
};
11431135
const scopes = [
1144-
nockIsGCE(),
1136+
nockIsGCE(), createGetProjectIdNock(),
11451137
nock(host).get(svcAccountPath).reply(200, response, HEADERS)
11461138
];
11471139
blockGoogleApplicationCredentialEnvironmentVariable();
@@ -1157,8 +1149,10 @@ describe('googleauth', () => {
11571149
});
11581150

11591151
it('getCredentials should error if metadata server is not reachable', async () => {
1160-
const scopes =
1161-
[nockIsGCE(), nock(HOST_ADDRESS).get(svcAccountPath).reply(404)];
1152+
const scopes = [
1153+
nockIsGCE(), createGetProjectIdNock(),
1154+
nock(HOST_ADDRESS).get(svcAccountPath).reply(404)
1155+
];
11621156
blockGoogleApplicationCredentialEnvironmentVariable();
11631157
auth._fileExists = () => false;
11641158
await auth._checkIsGCE();
@@ -1172,8 +1166,10 @@ describe('googleauth', () => {
11721166
it('getCredentials should error if body is empty', async () => {
11731167
blockGoogleApplicationCredentialEnvironmentVariable();
11741168
auth._fileExists = () => false;
1175-
const scopes =
1176-
[nockIsGCE(), nock(HOST_ADDRESS).get(svcAccountPath).reply(200, {})];
1169+
const scopes = [
1170+
nockIsGCE(), createGetProjectIdNock(),
1171+
nock(HOST_ADDRESS).get(svcAccountPath).reply(200, {})
1172+
];
11771173
await auth._checkIsGCE();
11781174
assert.strictEqual(true, auth.isGCE);
11791175
await assertRejects(
@@ -1305,20 +1301,23 @@ describe('googleauth', () => {
13051301

13061302
it('should get an access token', async () => {
13071303
const {auth, scopes} = mockGCE();
1304+
scopes.push(createGetProjectIdNock());
13081305
const token = await auth.getAccessToken();
13091306
scopes.forEach(s => s.done());
13101307
assert.strictEqual(token, 'abc123');
13111308
});
13121309

13131310
it('should get request headers', async () => {
13141311
const {auth, scopes} = mockGCE();
1312+
scopes.push(createGetProjectIdNock());
13151313
const headers = await auth.getRequestHeaders();
13161314
scopes.forEach(s => s.done());
13171315
assert.deepStrictEqual(headers, {Authorization: 'Bearer abc123'});
13181316
});
13191317

13201318
it('should authorize the request', async () => {
13211319
const {auth, scopes} = mockGCE();
1320+
scopes.push(createGetProjectIdNock());
13221321
const opts = await auth.authorizeRequest({url: 'http://example.com'});
13231322
scopes.forEach(s => s.done());
13241323
assert.deepStrictEqual(opts.headers, {Authorization: 'Bearer abc123'});
@@ -1359,9 +1358,9 @@ describe('googleauth', () => {
13591358
it('should make the request', async () => {
13601359
const url = 'http://example.com';
13611360
const {auth, scopes} = mockGCE();
1361+
scopes.push(createGetProjectIdNock());
13621362
const data = {breakfast: 'coffee'};
1363-
const scope = nock(url).get('/').reply(200, data);
1364-
scopes.push(scope);
1363+
scopes.push(nock(url).get('/').reply(200, data));
13651364
const res = await auth.request({url});
13661365
scopes.forEach(s => s.done());
13671366
assert.deepStrictEqual(res.data, data);
@@ -1467,4 +1466,14 @@ describe('googleauth', () => {
14671466
const client = await auth.getClient() as JWT;
14681467
assert.strictEqual(client.subject, subject);
14691468
});
1469+
1470+
it('should throw if getProjectId cannot find a projectId', async () => {
1471+
blockGoogleApplicationCredentialEnvironmentVariable();
1472+
auth._fileExists = () => false;
1473+
// tslint:disable-next-line no-any
1474+
sinon.stub(auth as any, 'getDefaultServiceProjectId').resolves();
1475+
await assertRejects(
1476+
auth.getProjectId(),
1477+
/Unable to detect a Project Id in the current environment/);
1478+
});
14701479
});

0 commit comments

Comments
 (0)