diff --git a/.github/sync-repo-settings.yaml b/.github/sync-repo-settings.yaml index 1b362683..d1e8b5e6 100644 --- a/.github/sync-repo-settings.yaml +++ b/.github/sync-repo-settings.yaml @@ -9,9 +9,9 @@ branchProtectionRules: - "ci/kokoro: System test" - docs - lint - - test (10) - test (12) - test (14) + - test (16) - cla/google - windows - OwlBot Post Processor diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 25251dbb..f447b84a 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node: [10, 12, 14] + node: [12, 14, 16] steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 diff --git a/.kokoro/continuous/node10/common.cfg b/.kokoro/continuous/node10/common.cfg deleted file mode 100644 index d144aee1..00000000 --- a/.kokoro/continuous/node10/common.cfg +++ /dev/null @@ -1,34 +0,0 @@ -# Format: //devtools/kokoro/config/proto/build.proto - -# Build logs will be here -action { - define_artifacts { - regex: "**/*sponge_log.xml" - } -} - -# Bring in codecov.io token into the build as $KOKORO_KEYSTORE_DIR/73713_dpebot_codecov_token -before_action { - fetch_keystore { - keystore_resource { - keystore_config_id: 73713 - keyname: "dpebot_codecov_token" - } - } -} - -# Download trampoline resources. -gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline" - -# Use the trampoline script to run in docker. -build_file: "google-auth-library-nodejs/.kokoro/trampoline_v2.sh" - -# Configure the docker image for kokoro-trampoline. -env_vars: { - key: "TRAMPOLINE_IMAGE" - value: "gcr.io/cloud-devrel-kokoro-resources/node:10-user" -} -env_vars: { - key: "TRAMPOLINE_BUILD_FILE" - value: "github/google-auth-library-nodejs/.kokoro/test.sh" -} diff --git a/.kokoro/continuous/node10/docs.cfg b/.kokoro/continuous/node10/docs.cfg deleted file mode 100644 index 213beda5..00000000 --- a/.kokoro/continuous/node10/docs.cfg +++ /dev/null @@ -1,4 +0,0 @@ -env_vars: { - key: "TRAMPOLINE_BUILD_FILE" - value: "github/google-auth-library-nodejs/.kokoro/docs.sh" -} diff --git a/.kokoro/continuous/node10/test.cfg b/.kokoro/continuous/node10/test.cfg deleted file mode 100644 index 609c0cf0..00000000 --- a/.kokoro/continuous/node10/test.cfg +++ /dev/null @@ -1,9 +0,0 @@ -# Bring in codecov.io token into the build as $KOKORO_KEYSTORE_DIR/73713_dpebot_codecov_token -before_action { - fetch_keystore { - keystore_resource { - keystore_config_id: 73713 - keyname: "dpebot_codecov_token" - } - } -} diff --git a/.kokoro/continuous/node8/browser-test.cfg b/.kokoro/continuous/node8/browser-test.cfg deleted file mode 100644 index fb5125fb..00000000 --- a/.kokoro/continuous/node8/browser-test.cfg +++ /dev/null @@ -1,12 +0,0 @@ -# Download resources for system tests (service account key, etc.) -gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/google-cloud-nodejs" - -# Configure the docker image for kokoro-trampoline. -env_vars: { - key: "TRAMPOLINE_IMAGE" - value: "gcr.io/cloud-devrel-kokoro-resources/node:8-puppeteer" -} -env_vars: { - key: "TRAMPOLINE_BUILD_FILE" - value: "github/google-auth-library-nodejs/.kokoro/browser-test.sh" -} diff --git a/.kokoro/continuous/node8/common.cfg b/.kokoro/continuous/node8/common.cfg deleted file mode 100644 index e3a36c7f..00000000 --- a/.kokoro/continuous/node8/common.cfg +++ /dev/null @@ -1,24 +0,0 @@ -# Format: //devtools/kokoro/config/proto/build.proto - -# Build logs will be here -action { - define_artifacts { - regex: "**/*sponge_log.xml" - } -} - -# Download trampoline resources. -gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline" - -# Use the trampoline script to run in docker. -build_file: "google-auth-library-nodejs/.kokoro/trampoline.sh" - -# Configure the docker image for kokoro-trampoline. -env_vars: { - key: "TRAMPOLINE_IMAGE" - value: "gcr.io/cloud-devrel-kokoro-resources/node:8-user" -} -env_vars: { - key: "TRAMPOLINE_BUILD_FILE" - value: "github/google-auth-library-nodejs/.kokoro/test.sh" -} diff --git a/.kokoro/continuous/node8/test.cfg b/.kokoro/continuous/node8/test.cfg deleted file mode 100644 index e69de29b..00000000 diff --git a/.kokoro/presubmit/node10/common.cfg b/.kokoro/presubmit/node10/common.cfg deleted file mode 100644 index d144aee1..00000000 --- a/.kokoro/presubmit/node10/common.cfg +++ /dev/null @@ -1,34 +0,0 @@ -# Format: //devtools/kokoro/config/proto/build.proto - -# Build logs will be here -action { - define_artifacts { - regex: "**/*sponge_log.xml" - } -} - -# Bring in codecov.io token into the build as $KOKORO_KEYSTORE_DIR/73713_dpebot_codecov_token -before_action { - fetch_keystore { - keystore_resource { - keystore_config_id: 73713 - keyname: "dpebot_codecov_token" - } - } -} - -# Download trampoline resources. -gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline" - -# Use the trampoline script to run in docker. -build_file: "google-auth-library-nodejs/.kokoro/trampoline_v2.sh" - -# Configure the docker image for kokoro-trampoline. -env_vars: { - key: "TRAMPOLINE_IMAGE" - value: "gcr.io/cloud-devrel-kokoro-resources/node:10-user" -} -env_vars: { - key: "TRAMPOLINE_BUILD_FILE" - value: "github/google-auth-library-nodejs/.kokoro/test.sh" -} diff --git a/.kokoro/presubmit/node10/docs.cfg b/.kokoro/presubmit/node10/docs.cfg deleted file mode 100644 index 213beda5..00000000 --- a/.kokoro/presubmit/node10/docs.cfg +++ /dev/null @@ -1,4 +0,0 @@ -env_vars: { - key: "TRAMPOLINE_BUILD_FILE" - value: "github/google-auth-library-nodejs/.kokoro/docs.sh" -} diff --git a/.kokoro/presubmit/node10/lint.cfg b/.kokoro/presubmit/node10/lint.cfg deleted file mode 100644 index 49ffcd82..00000000 --- a/.kokoro/presubmit/node10/lint.cfg +++ /dev/null @@ -1,4 +0,0 @@ -env_vars: { - key: "TRAMPOLINE_BUILD_FILE" - value: "github/google-auth-library-nodejs/.kokoro/lint.sh" -} diff --git a/.kokoro/presubmit/node10/test.cfg b/.kokoro/presubmit/node10/test.cfg deleted file mode 100644 index e69de29b..00000000 diff --git a/package.json b/package.json index 2af0488c..f43a5aa0 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "author": "Google Inc.", "description": "Google APIs Authentication Client Library for Node.js", "engines": { - "node": ">=10" + "node": ">=12" }, "main": "./build/src/index.js", "types": "./build/src/index.d.ts", @@ -44,7 +44,7 @@ "chai": "^4.2.0", "codecov": "^3.0.2", "execa": "^5.0.0", - "gts": "^2.0.0", + "gts": "^3.1.0", "is-docker": "^2.0.0", "karma": "^6.0.0", "karma-chrome-launcher": "^3.0.0", @@ -65,7 +65,7 @@ "sinon": "^13.0.0", "tmp": "^0.2.0", "ts-loader": "^8.0.0", - "typescript": "^3.8.3", + "typescript": "^4.6.3", "webpack": "^5.21.2", "webpack-cli": "^4.0.0" }, diff --git a/samples/package.json b/samples/package.json index f0d1e038..e26fc245 100644 --- a/samples/package.json +++ b/samples/package.json @@ -9,7 +9,7 @@ "test": "mocha --timeout 60000" }, "engines": { - "node": ">=10" + "node": ">=12" }, "license": "Apache-2.0", "dependencies": { diff --git a/samples/puppeteer/package.json b/samples/puppeteer/package.json index ce54cfb0..9c38a8b1 100644 --- a/samples/puppeteer/package.json +++ b/samples/puppeteer/package.json @@ -4,7 +4,7 @@ "description": "An example of using puppeteer to orchestrate a Google sign in flow.", "main": "oauth2-test.js", "engines": { - "node": ">=8" + "node": ">=12" }, "scripts": { "start": "node oauth2-test.js" diff --git a/src/auth/baseexternalclient.ts b/src/auth/baseexternalclient.ts index 691e3964..bf13d368 100644 --- a/src/auth/baseexternalclient.ts +++ b/src/auth/baseexternalclient.ts @@ -247,7 +247,7 @@ export abstract class BaseExternalAccountClient extends AuthClient { * the type of external credential used. * @return A promise that resolves with the external subject token. */ - abstract async retrieveSubjectToken(): Promise; + abstract retrieveSubjectToken(): Promise; /** * @return A promise that resolves with the current GCP access token diff --git a/src/auth/computeclient.ts b/src/auth/computeclient.ts index 1bfb4d51..db91df01 100644 --- a/src/auth/computeclient.ts +++ b/src/auth/computeclient.ts @@ -73,8 +73,11 @@ export class Compute extends OAuth2Client { } data = await gcpMetadata.instance(instanceOptions); } catch (e) { - e.message = `Could not refresh access token: ${e.message}`; - this.wrapError(e); + if (e instanceof GaxiosError) { + e.message = `Could not refresh access token: ${e.message}`; + this.wrapError(e); + } + throw e; } const tokens = data as Credentials; @@ -101,7 +104,10 @@ export class Compute extends OAuth2Client { }; idToken = await gcpMetadata.instance(instanceOptions); } catch (e) { - e.message = `Could not fetch ID token: ${e.message}`; + if (e instanceof Error) { + e.message = `Could not fetch ID token: ${e.message}`; + } + throw e; } diff --git a/src/auth/identitypoolclient.ts b/src/auth/identitypoolclient.ts index eed39b1c..102025ed 100644 --- a/src/auth/identitypoolclient.ts +++ b/src/auth/identitypoolclient.ts @@ -155,7 +155,10 @@ export class IdentityPoolClient extends BaseExternalAccountClient { throw new Error(); } } catch (err) { - err.message = `The file at ${filePath} does not exist, or it is not a file. ${err.message}`; + if (err instanceof Error) { + err.message = `The file at ${filePath} does not exist, or it is not a file. ${err.message}`; + } + throw err; } diff --git a/src/auth/impersonated.ts b/src/auth/impersonated.ts index a6646095..fb1085f6 100644 --- a/src/auth/impersonated.ts +++ b/src/auth/impersonated.ts @@ -16,6 +16,7 @@ import {GetTokenResponse, OAuth2Client, RefreshOptions} from './oauth2client'; import {AuthClient} from './authclient'; +import {GaxiosError} from 'gaxios'; export interface ImpersonatedOptions extends RefreshOptions { /** @@ -132,8 +133,16 @@ export class Impersonated extends OAuth2Client { res, }; } catch (error) { - const status = error?.response?.data?.error?.status; - const message = error?.response?.data?.error?.message; + if (!(error instanceof Error)) throw error; + + let status = 0; + let message = ''; + + if (error instanceof GaxiosError) { + status = error?.response?.data?.error?.status; + message = error?.response?.data?.error?.message; + } + if (status && message) { error.message = `${status}: unable to impersonate: ${message}`; throw error; diff --git a/src/auth/oauth2client.ts b/src/auth/oauth2client.ts index 34ff13d4..de70e452 100644 --- a/src/auth/oauth2client.ts +++ b/src/auth/oauth2client.ts @@ -1155,7 +1155,10 @@ export class OAuth2Client extends AuthClient { try { res = await this.transporter.request({url}); } catch (e) { - e.message = `Failed to retrieve verification certificates: ${e.message}`; + if (e instanceof Error) { + e.message = `Failed to retrieve verification certificates: ${e.message}`; + } + throw e; } @@ -1220,7 +1223,10 @@ export class OAuth2Client extends AuthClient { try { res = await this.transporter.request({url}); } catch (e) { - e.message = `Failed to retrieve verification certificates: ${e.message}`; + if (e instanceof Error) { + e.message = `Failed to retrieve verification certificates: ${e.message}`; + } + throw e; } @@ -1271,7 +1277,10 @@ export class OAuth2Client extends AuthClient { try { envelope = JSON.parse(crypto.decodeBase64StringUtf8(segments[0])); } catch (err) { - err.message = `Can't parse token envelope: ${segments[0]}': ${err.message}`; + if (err instanceof Error) { + err.message = `Can't parse token envelope: ${segments[0]}': ${err.message}`; + } + throw err; } @@ -1282,7 +1291,9 @@ export class OAuth2Client extends AuthClient { try { payload = JSON.parse(crypto.decodeBase64StringUtf8(segments[1])); } catch (err) { - err.message = `Can't parse token payload '${segments[0]}`; + if (err instanceof Error) { + err.message = `Can't parse token payload '${segments[0]}`; + } throw err; } diff --git a/src/auth/stscredentials.ts b/src/auth/stscredentials.ts index 497b1e76..52178b82 100644 --- a/src/auth/stscredentials.ts +++ b/src/auth/stscredentials.ts @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import {GaxiosOptions, GaxiosResponse} from 'gaxios'; +import {GaxiosError, GaxiosOptions, GaxiosResponse} from 'gaxios'; import * as querystring from 'querystring'; import {DefaultTransporter} from '../transporters'; @@ -216,7 +216,7 @@ export class StsCredentials extends OAuthClientAuthHandler { return stsSuccessfulResponse; } catch (error) { // Translate error to OAuthError. - if (error.response) { + if (error instanceof GaxiosError && error.response) { throw getErrorFromOAuthErrorResponse( error.response.data as OAuthErrorResponse, // Preserve other fields from the original error. diff --git a/src/transporters.ts b/src/transporters.ts index 3b3fded6..952f22af 100644 --- a/src/transporters.ts +++ b/src/transporters.ts @@ -104,7 +104,7 @@ export class DefaultTransporter { validate(opts); } catch (e) { if (callback) { - return callback(e); + return callback(e as Error); } else { throw e; } diff --git a/test/test.awsclient.ts b/test/test.awsclient.ts index 762e9a30..496d6599 100644 --- a/test/test.awsclient.ts +++ b/test/test.awsclient.ts @@ -408,7 +408,9 @@ describe('AwsClient', () => { {}, awsCredentialSource ); - delete missingUrlCredentialSource.url; + delete ( + missingUrlCredentialSource as Partial + ).url; const invalidOptions = { type: 'external_account', audience, @@ -435,7 +437,11 @@ describe('AwsClient', () => { {}, awsCredentialSource ); - delete missingRegionUrlCredentialSource.region_url; + delete ( + missingRegionUrlCredentialSource as Partial< + typeof awsCredentialSource + > + ).region_url; const invalidOptions = { type: 'external_account', audience, @@ -707,8 +713,12 @@ describe('AwsClient', () => { awsCredentialSource ); // Remove all optional fields. - delete requiredOnlyCredentialSource.region_url; - delete requiredOnlyCredentialSource.url; + delete ( + requiredOnlyCredentialSource as Partial + ).region_url; + delete ( + requiredOnlyCredentialSource as Partial + ).url; const requiredOnlyOptions = { type: 'external_account', audience, diff --git a/test/test.externalclient.ts b/test/test.externalclient.ts index f341d343..645ac30c 100644 --- a/test/test.externalclient.ts +++ b/test/test.externalclient.ts @@ -191,7 +191,8 @@ describe('ExternalAccountClient', () => { it('should throw when given invalid ExternalAccountClient', () => { const invalidOptions = Object.assign({}, fileSourcedOptions); - delete invalidOptions.credential_source; + delete (invalidOptions as Partial) + .credential_source; assert.throws(() => { return ExternalAccountClient.fromJSON(invalidOptions); diff --git a/test/test.googleauth.ts b/test/test.googleauth.ts index f9b601cb..ef5bc3cf 100644 --- a/test/test.googleauth.ts +++ b/test/test.googleauth.ts @@ -406,7 +406,7 @@ describe('googleauth', () => { it('fromJSON should error on missing client_email', () => { const json = createJwtJSON(); - delete json.client_email; + delete (json as Partial).client_email; assert.throws(() => { auth.fromJSON(json); }); @@ -414,7 +414,7 @@ describe('googleauth', () => { it('fromJSON should error on missing private_key', () => { const json = createJwtJSON(); - delete json.private_key; + delete (json as Partial).private_key; assert.throws(() => { auth.fromJSON(json); }); @@ -1600,6 +1600,7 @@ describe('googleauth', () => { try { await auth.getIdTokenClient('a-target-audience'); } catch (e) { + assert(e instanceof Error); assert( e.message.startsWith('Cannot fetch ID token in this environment') ); diff --git a/test/test.jwt.ts b/test/test.jwt.ts index 274fe889..6f94f281 100644 --- a/test/test.jwt.ts +++ b/test/test.jwt.ts @@ -633,7 +633,7 @@ describe('jwt', () => { it('should error on missing client_id', () => { const json = createRefreshJSON(); - delete json.client_id; + delete (json as Partial).client_id; const jwt = new JWT(); assert.throws(() => { jwt.fromJSON(json); @@ -642,7 +642,7 @@ describe('jwt', () => { it('should error on missing client_secret', () => { const json = createRefreshJSON(); - delete json.client_secret; + delete (json as Partial).client_secret; const jwt = new JWT(); assert.throws(() => { jwt.fromJSON(json); @@ -651,7 +651,7 @@ describe('jwt', () => { it('should error on missing refresh_token', () => { const json = createRefreshJSON(); - delete json.refresh_token; + delete (json as Partial).refresh_token; const jwt = new JWT(); assert.throws(() => { jwt.fromJSON(json); diff --git a/test/test.jwtaccess.ts b/test/test.jwtaccess.ts index 438e84c8..1434f256 100644 --- a/test/test.jwtaccess.ts +++ b/test/test.jwtaccess.ts @@ -128,7 +128,7 @@ describe('jwtaccess', () => { it('fromJson should error on missing client_email', () => { const j = Object.assign({}, json); - delete j.client_email; + delete (j as Partial).client_email; assert.throws(() => { client.fromJSON(j); }); @@ -136,7 +136,7 @@ describe('jwtaccess', () => { it('fromJson should error on missing private_key', () => { const j = Object.assign({}, json); - delete j.private_key; + delete (j as Partial).private_key; assert.throws(() => { client.fromJSON(j); }); diff --git a/test/test.refresh.ts b/test/test.refresh.ts index 2e06d7de..4f7b888f 100644 --- a/test/test.refresh.ts +++ b/test/test.refresh.ts @@ -55,7 +55,7 @@ describe('refresh', () => { it('fromJSON should error on missing client_id', () => { const json = createJSON(); - delete json.client_id; + delete (json as Partial).client_id; const refresh = new UserRefreshClient(); assert.throws(() => { refresh.fromJSON(json); @@ -64,7 +64,7 @@ describe('refresh', () => { it('fromJSON should error on missing client_secret', () => { const json = createJSON(); - delete json.client_secret; + delete (json as Partial).client_secret; const refresh = new UserRefreshClient(); assert.throws(() => { refresh.fromJSON(json); @@ -73,7 +73,7 @@ describe('refresh', () => { it('fromJSON should error on missing refresh_token', () => { const json = createJSON(); - delete json.refresh_token; + delete (json as Partial).refresh_token; const refresh = new UserRefreshClient(); assert.throws(() => { refresh.fromJSON(json);