Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Utilize gcp-metadata's GCP Residency Check #1513

Merged
merged 14 commits into from
Jun 29, 2023
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"ecdsa-sig-formatter": "^1.0.11",
"fast-text-encoding": "^1.0.0",
"gaxios": "^5.0.0",
"gcp-metadata": "^5.2.0",
"gcp-metadata": "^5.3.0",
"gtoken": "^6.1.0",
"jws": "^4.0.0",
"lru-cache": "^6.0.0"
Expand Down
7 changes: 6 additions & 1 deletion src/auth/googleauth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -396,13 +396,18 @@ export class GoogleAuth<T extends AuthClient = JSONClient> {

/**
* Determines whether the auth layer is running on Google Compute Engine.
* Checks for GCP Residency, then fallback to checking if metadata server
* is available.
*
* @returns A promise that resolves with the boolean.
* @api private
*/
async _checkIsGCE() {
if (this.checkIsGCE === undefined) {
this.checkIsGCE = await gcpMetadata.isAvailable();
this.checkIsGCE =
gcpMetadata.getGCPResidency() || (await gcpMetadata.isAvailable());
}

return this.checkIsGCE;
}

Expand Down
64 changes: 7 additions & 57 deletions test/test.googleauth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
SECONDARY_HOST_ADDRESS,
resetIsAvailableCache,
} from 'gcp-metadata';
import * as gcpMetadata from 'gcp-metadata';
import * as nock from 'nock';
import * as os from 'os';
import * as path from 'path';
Expand Down Expand Up @@ -55,7 +56,7 @@
import {AuthClient} from '../src/auth/authclient';
import {
ExternalAccountAuthorizedUserClient,
ExternalAccountAuthorizedUserClientOptions,

Check warning on line 59 in test/test.googleauth.ts

View workflow job for this annotation

GitHub Actions / lint

'ExternalAccountAuthorizedUserClientOptions' is defined but never used
} from '../src/auth/externalAccountAuthorizedUserClient';

nock.disableNetConnect();
Expand Down Expand Up @@ -239,7 +240,7 @@
};
}

function nock500GCE() {

Check warning on line 243 in test/test.googleauth.ts

View workflow job for this annotation

GitHub Actions / lint

'nock500GCE' is defined but never used
const primary = nock(host).get(instancePath).reply(500, {}, HEADERS);
const secondary = nock(SECONDARY_HOST_ADDRESS)
.get(instancePath)
Expand Down Expand Up @@ -1137,66 +1138,15 @@
assert.strictEqual(undefined, client.scope);
});

it('_checkIsGCE should set the _isGCE flag when running on GCE', async () => {
assert.notStrictEqual(true, auth.isGCE);
const scope = nockIsGCE();
await auth._checkIsGCE();
assert.strictEqual(true, auth.isGCE);
scope.done();
});

it('_checkIsGCE should not set the _isGCE flag when not running on GCE', async () => {
Copy link
Member Author

Choose a reason for hiding this comment

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

These tests are effectively just testing gcp-metadata, which already has these tests.

const scope = nockNotGCE();
assert.notStrictEqual(true, auth.isGCE);
await auth._checkIsGCE();
assert.strictEqual(false as boolean, auth.isGCE);
scope.done();
});

it('_checkIsGCE should retry the check for isGCE on transient http errors', async () => {
assert.notStrictEqual(true, auth.isGCE);
// the first request will fail, the second one will succeed
const scopes = [nock500GCE(), nockIsGCE()];
await auth._checkIsGCE();
assert.strictEqual(true, auth.isGCE);
scopes.forEach(s => s.done());
});

it('_checkIsGCE should return false on unexpected errors', async () => {
assert.notStrictEqual(true, auth.isGCE);
const scope = nock500GCE();
assert.strictEqual(await auth._checkIsGCE(), false);
assert.strictEqual(auth.isGCE, false);
scope.done();
});
it("_checkIsGCE should be equalivalent should use GCP metadata's checks", async () => {
nockNotGCE();

it('_checkIsGCE should not retry the check for isGCE if it fails with an ENOTFOUND', async () => {
assert.notStrictEqual(true, auth.isGCE);
const scope = nockNotGCE();
await auth._checkIsGCE();
assert.strictEqual(false as boolean, auth.isGCE);
scope.done();
});

it('_checkIsGCE does not execute the second time when running on GCE', async () => {
// This test relies on the nock mock only getting called once.
assert.notStrictEqual(true, auth.isGCE);
const scope = nockIsGCE();
await auth._checkIsGCE();
assert.strictEqual(true, auth.isGCE);
await auth._checkIsGCE();
assert.strictEqual(true, auth.isGCE);
scope.done();
});
const expected =
gcpMetadata.getGCPResidency() || gcpMetadata.isAvailable();

it('_checkIsGCE does not execute the second time when not running on GCE', async () => {
assert.notStrictEqual(true, auth.isGCE);
const scope = nockNotGCE();
await auth._checkIsGCE();
assert.strictEqual(false as boolean, auth.isGCE);
assert.strict.notEqual(auth.isGCE, true);
await auth._checkIsGCE();
assert.strictEqual(false as boolean, auth.isGCE);
scope.done();
assert.strictEqual(auth.isGCE, expected);
});

it('getCredentials should get metadata from the server when running on GCE', async () => {
Expand Down
Loading