From 4156eb67c22e57d801b690cd349029f82a127885 Mon Sep 17 00:00:00 2001 From: Nicholas Shirley Date: Wed, 25 Feb 2026 17:49:00 -0700 Subject: [PATCH] feat(fxa): Pass WAF bypass token with functional-test auth-client Because: - Some functional tests make use of the auth-client for direct calls to the auth-server - And we want to enable blocking direct requests to the auth-server This commit: - Passes a unique token to the auth-client requests that are blocking to enable bypassing the rule Closes: --- packages/functional-tests/README.md | 4 +++ packages/functional-tests/lib/targets/base.ts | 12 ++++++++ .../functional-tests/lib/targets/local.ts | 7 ++++- .../functional-tests/lib/targets/remote.ts | 3 +- .../tests/misc/authClientV2.spec.ts | 29 +++++++++++++------ 5 files changed, 44 insertions(+), 11 deletions(-) diff --git a/packages/functional-tests/README.md b/packages/functional-tests/README.md index 434e78d371c..c6be2929fde 100644 --- a/packages/functional-tests/README.md +++ b/packages/functional-tests/README.md @@ -34,6 +34,10 @@ For example, to run a specific test against stage: yarn test --project=stage --grep="errors on xss redirect_to parameter" ``` +### Running against Stage or Production + +In order to run local tests against stage or production, you'll need to set a few environment variables first. Some tests make use of the auth-client for direct calls to auth-server, so we use a bypass header for the WAF to allow the traffic. You'll need to set both `CI=1` and `CI_WAF_TOKEN="my_token"` environment variables. You can get a copy of the bypass token from 1Password. + ### Specifying a target in tests Some tests only work with certain targets. The content-server mocha tests for example will only work on `local`. Use [annotations](https://playwright.dev/docs/test-annotations#annotations) and [TestInfo](https://playwright.dev/docs/api/class-testinfo) to determine when a test should run. diff --git a/packages/functional-tests/lib/targets/base.ts b/packages/functional-tests/lib/targets/base.ts index e04710a5dc4..be4643ee9e1 100644 --- a/packages/functional-tests/lib/targets/base.ts +++ b/packages/functional-tests/lib/targets/base.ts @@ -37,6 +37,18 @@ export abstract class BaseTarget { return this.contentServerUrl; } + /** + * Will return a `Headers` object with the WAF bypass header if we're in + * CI and the token is set, otherwise undefined. + * + * This can be passed to the auth-client calls that support optional headers. + */ + get ciHeader(): Headers | undefined { + const ci = !!process.env.CI; + const ciWafToken = process.env.CI_WAF_TOKEN; + return ci && ciWafToken ? new Headers({ 'fxa-ci': ciWafToken }) : undefined; + } + constructor( readonly authServerUrl: string, emailUrl?: string diff --git a/packages/functional-tests/lib/targets/local.ts b/packages/functional-tests/lib/targets/local.ts index d83e74fae8b..47be2d34d37 100644 --- a/packages/functional-tests/lib/targets/local.ts +++ b/packages/functional-tests/lib/targets/local.ts @@ -33,7 +33,12 @@ export class LocalTarget extends BaseTarget { ) { // Quick and dirty way to see if this works... await this.rateLimitClient.resetCounts(); - const result = await this.authClient.signUp(email, password, options); + const result = await this.authClient.signUp( + email, + password, + options, + this.ciHeader + ); await this.authClient.deviceRegister( result.sessionToken, 'playwright', diff --git a/packages/functional-tests/lib/targets/remote.ts b/packages/functional-tests/lib/targets/remote.ts index e56afdd1604..65ffedc3dcc 100644 --- a/packages/functional-tests/lib/targets/remote.ts +++ b/packages/functional-tests/lib/targets/remote.ts @@ -19,7 +19,8 @@ export abstract class RemoteTarget extends BaseTarget { const creds = await this.authClient.signUp( email, password, - filteredOptions + filteredOptions, + this.ciHeader ); if (preVerified === 'true') { const code = await this.emailClient.getVerifyCode(email); diff --git a/packages/functional-tests/tests/misc/authClientV2.spec.ts b/packages/functional-tests/tests/misc/authClientV2.spec.ts index 07d18b8e149..60217a782fd 100644 --- a/packages/functional-tests/tests/misc/authClientV2.spec.ts +++ b/packages/functional-tests/tests/misc/authClientV2.spec.ts @@ -8,14 +8,25 @@ import AuthClient, { getCredentialsV2, } from '../../../fxa-auth-client/browser'; import { expect, test } from '../../lib/fixtures/standard'; +import { BaseTarget } from '../../lib/targets/base'; test.describe('auth-client-tests', () => { - async function signUp(client: AuthClient, email: string, password: string) { - const credentials = await client.signUp(email, password, { - keys: true, - lang: 'en', - preVerified: 'true', - }); + async function signUp( + client: AuthClient, + email: string, + password: string, + target: BaseTarget + ) { + const credentials = await client.signUp( + email, + password, + { + keys: true, + lang: 'en', + preVerified: 'true', + }, + target.ciHeader + ); expect(credentials.sessionToken).toBeDefined(); @@ -43,7 +54,7 @@ test.describe('auth-client-tests', () => { const client = target.authClient; const { email, password } = testAccountTracker.generateAccountDetails(); - await signUp(client, email, password); + await signUp(client, email, password, target); // Check the salt is V1 const status = await client.getCredentialStatusV2(email); @@ -76,7 +87,7 @@ test.describe('auth-client-tests', () => { const client = target.createAuthClient(2); const { email, password } = testAccountTracker.generateAccountDetails(); - await signUp(client, email, password); + await signUp(client, email, password, target); // Check the salt is V1 const status = await client.getCredentialStatusV2(email); @@ -119,7 +130,7 @@ test.describe('auth-client-tests', () => { const client = target.authClient; const { email, password } = testAccountTracker.generateAccountDetails(); - await signUp(client, email, password); + await signUp(client, email, password, target); const signInResult = await client.signIn(email, password, { keys: true }); expect(signInResult.keyFetchToken).toBeDefined();