@validate.qa/runner 1.0.93 → 1.0.94

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -8566,10 +8566,13 @@ var require_google_signin = __commonJS({
8566
8566
  exports2.googleSignInGuidanceOpts = googleSignInGuidanceOpts;
8567
8567
  exports2.googleSignInAllowedEmails = googleSignInAllowedEmails;
8568
8568
  exports2.collectGoogleSignInEnv = collectGoogleSignInEnv;
8569
+ exports2.isGoogleAccountsUrl = isGoogleAccountsUrl;
8570
+ exports2.googleSignInCredentialMismatch = googleSignInCredentialMismatch;
8569
8571
  exports2.generateTotp = generateTotp;
8570
8572
  exports2.buildGoogleSignInPromptSection = buildGoogleSignInPromptSection;
8571
8573
  var node_crypto_1 = require("crypto");
8572
8574
  exports2.GOOGLE_SIGNIN_PASSWORD_KEY = "GOOGLE_SIGNIN_PASSWORD";
8575
+ var APP_REGISTER_CREDENTIAL_KEYS = /^(TEST_|E2E_|QA_)?(USER_?EMAIL|USER_?PASSWORD|USER_?NAME|USERNAME)$/i;
8573
8576
  exports2.GOOGLE_SIGNIN_ENV_KEYS = [
8574
8577
  "GOOGLE_SIGNIN_PASSWORD",
8575
8578
  "GOOGLE_SIGNIN_EMAIL",
@@ -8626,6 +8629,34 @@ var require_google_signin = __commonJS({
8626
8629
  }
8627
8630
  return out;
8628
8631
  }
8632
+ function isGoogleAccountsUrl(url) {
8633
+ if (!url)
8634
+ return false;
8635
+ try {
8636
+ const host = new URL(url).hostname.toLowerCase();
8637
+ return host === "accounts.google.com" || host.endsWith(".google.com") && host.includes("accounts");
8638
+ } catch {
8639
+ return /accounts\.google\.com/i.test(url);
8640
+ }
8641
+ }
8642
+ function googleSignInCredentialMismatch(pageUrl, credentialKey, opts) {
8643
+ const configured = opts?.configured ?? !!loadGoogleSignInConfig(opts?.env);
8644
+ if (!configured)
8645
+ return null;
8646
+ const onGoogle = isGoogleAccountsUrl(pageUrl);
8647
+ if (onGoogle) {
8648
+ if (credentialKey === exports2.GOOGLE_SIGNIN_PASSWORD_KEY)
8649
+ return null;
8650
+ if (APP_REGISTER_CREDENTIAL_KEYS.test(credentialKey)) {
8651
+ return `fill_credential: this is Google account login (accounts.google.com), not app email signup. Do not use ${credentialKey}. Type the BARE Google email with browser_type, then fill_credential with credentialKey ${exports2.GOOGLE_SIGNIN_PASSWORD_KEY}. Do not click Continue with phone / SMS OTP when Continue with Google is available.`;
8652
+ }
8653
+ return null;
8654
+ }
8655
+ if (credentialKey === exports2.GOOGLE_SIGNIN_PASSWORD_KEY) {
8656
+ return `fill_credential: ${exports2.GOOGLE_SIGNIN_PASSWORD_KEY} is only for accounts.google.com. Click Continue with Google first (not Continue with phone). Phone / "Mobile or email" is not app email signup.`;
8657
+ }
8658
+ return null;
8659
+ }
8629
8660
  function generateTotp(secret, atMs = Date.now(), stepSeconds = 30, digits = 6) {
8630
8661
  const key = decodeBase32(secret);
8631
8662
  const counter = Math.floor(atMs / 1e3 / stepSeconds);
@@ -8664,10 +8695,14 @@ var require_google_signin = __commonJS({
8664
8695
  const fill = variant === "cli" ? `fill_credential with credentialKey \`${opts.googlePasswordKey}\`` : `\`fill_credential\` (credentialKey \`${opts.googlePasswordKey}\`)`;
8665
8696
  const plainProvision = variant === "cli" ? "`inbox_provision_identity` with `plain: true`" : "`provision_identity` with `plain: true`";
8666
8697
  return `
8667
- Google / Gmail SSO fallback (SECOND choice \u2014 email+password signup is FIRST):
8668
- - FIRST follow the email-field playbook above whenever a signup form has an email / username / password field (including after clicking "Sign up with email"). Do NOT click Google if that form exists.
8669
- - ONLY if there is no email+password signup field and the only path is "Continue with Google" / "Sign up with Gmail" / "Sign in with Google": click that button. If a Google popup opens, switch to it (browser tabs).
8670
- - On accounts.google.com, type the BARE Google account email \`${opts.googleEmail}\` (no plus-tag \u2014 Google account login rejects plus-addresses) with browser_type, click Next, then fill the Google password with ${fill}. NEVER type the Google password as text and NEVER use the IMAP app password here.
8698
+ Google / Gmail SSO (use this when the APP has no Create-account email form):
8699
+ - App email+password SIGNUP means a form ON THIS APP to create an account (Sign up / Create account / Register, including after "Sign up with email"). That is FIRST. Do not use Google if that form exists.
8700
+ - These are NOT app email signup \u2014 do not treat them as the email playbook, and do not fill TEST_USER_EMAIL / TEST_USER_PASSWORD into them when Continue with Google is available:
8701
+ - "Continue with phone" / SMS / OTP
8702
+ - "Mobile or email" / phone-number identity on a Sign in page
8703
+ - Google's own email and password fields on accounts.google.com
8704
+ - If Sign in offers Continue with Google (and there is no app Create-account email form): click Continue with Google. Do NOT click Continue with phone for this registration.
8705
+ - If a Google popup or tab opens, switch to it. On accounts.google.com, type the BARE Google account email \`${opts.googleEmail}\` (no plus-tag) with browser_type, click Next, then fill the Google password with ${fill}. NEVER type the Google password as text, NEVER use TEST_USER_PASSWORD here, NEVER use the IMAP app password.
8671
8706
  - Click Next.${totp}
8672
8707
  - Click Continue / Allow on any consent screen, then return to the app tab.
8673
8708
  - If the app then emails a verification code/link, first call ${plainProvision} (Google SSO uses the bare inbox address, not the +tag), then complete it with the inbox tools as usual.
@@ -8699,7 +8734,7 @@ var require_credential_tools = __commonJS({
8699
8734
  type: "function",
8700
8735
  function: {
8701
8736
  name: "fill_credential",
8702
- description: 'Fill a stored credential VALUE into a form field. ALWAYS use this instead of `browser_type` for ANY email/password/token/auth field. You pass the variable KEY (e.g. "TEST_USER_EMAIL") and the runner injects the real value server-side \u2014 you never see the secret. The list of available credential keys is in the system prompt.',
8737
+ description: 'Fill a stored credential VALUE into a form field. ALWAYS use this instead of `browser_type` for ANY email/password/token/auth field. You pass the variable KEY (e.g. "TEST_USER_EMAIL") and the runner injects the real value server-side \u2014 you never see the secret. On accounts.google.com use GOOGLE_SIGNIN_PASSWORD (never TEST_USER_PASSWORD). The list of available credential keys is in the system prompt.',
8703
8738
  parameters: {
8704
8739
  type: "object",
8705
8740
  properties: {
@@ -8861,6 +8896,22 @@ CREDENTIAL ROTATION (required when the STORED user's secret changes \u2014 read
8861
8896
  return entries.map(([k, v]) => `- **${k}**: \`${v}\``).join("\n");
8862
8897
  }
8863
8898
  var DEFAULT_MAX_RESULT_CHARS = 15e3;
8899
+ var PAGE_URL_RE = /Page URL:\s*(\S+)/i;
8900
+ async function peekPageUrl(mcpClient) {
8901
+ try {
8902
+ const mcpResult = await mcpClient.callTool({ name: "browser_snapshot", arguments: {} });
8903
+ const { text } = parseMcpContent(mcpResult);
8904
+ const match = text.match(PAGE_URL_RE);
8905
+ return match?.[1]?.replace(/[),.;]+$/, "");
8906
+ } catch {
8907
+ return void 0;
8908
+ }
8909
+ }
8910
+ function googleFillBlocked(pageUrl, credentialKey, credentials) {
8911
+ return (0, google_signin_js_1.googleSignInCredentialMismatch)(pageUrl, credentialKey, {
8912
+ configured: !!credentials[google_signin_js_1.GOOGLE_SIGNIN_PASSWORD_KEY]
8913
+ });
8914
+ }
8864
8915
  async function handleFillCredential(toolArgs, ctx) {
8865
8916
  const key = typeof toolArgs.credentialKey === "string" ? toolArgs.credentialKey : "";
8866
8917
  const element = typeof toolArgs.element === "string" ? toolArgs.element : "";
@@ -8882,6 +8933,13 @@ CREDENTIAL ROTATION (required when the STORED user's secret changes \u2014 read
8882
8933
  didMutate: false
8883
8934
  };
8884
8935
  }
8936
+ if (ctx.credentials[google_signin_js_1.GOOGLE_SIGNIN_PASSWORD_KEY]) {
8937
+ const pageUrl = await peekPageUrl(ctx.mcpClient);
8938
+ const blocked = googleFillBlocked(pageUrl, key, ctx.credentials);
8939
+ if (blocked) {
8940
+ return { content: JSON.stringify({ error: blocked }), didMutate: false };
8941
+ }
8942
+ }
8885
8943
  const underlyingArgs = { element, ref, text: value, submit };
8886
8944
  const mcpResult = await ctx.mcpClient.callTool({ name: "browser_type", arguments: underlyingArgs });
8887
8945
  const mcpFailed = mcpResultIsError(mcpResult);
@@ -8920,6 +8978,16 @@ CREDENTIAL ROTATION (required when the STORED user's secret changes \u2014 read
8920
8978
  }
8921
8979
  resolved.push({ field, value });
8922
8980
  }
8981
+ if (ctx.credentials[google_signin_js_1.GOOGLE_SIGNIN_PASSWORD_KEY]) {
8982
+ const pageUrl = await peekPageUrl(ctx.mcpClient);
8983
+ for (const f of fields) {
8984
+ const key = typeof f.credentialKey === "string" ? f.credentialKey : typeof f.key === "string" ? f.key : "";
8985
+ const blocked = googleFillBlocked(pageUrl, key, ctx.credentials);
8986
+ if (blocked) {
8987
+ return { content: JSON.stringify({ error: blocked }), didMutate: false };
8988
+ }
8989
+ }
8990
+ }
8923
8991
  if (missing.length > 0) {
8924
8992
  const available = Object.keys(ctx.credentials).filter((k) => ctx.credentials[k]).join(", ") || "(none configured)";
8925
8993
  return {
@@ -74749,7 +74817,7 @@ var require_inbox_tools = __commonJS({
74749
74817
  ${where} You register using ONE real, monitored email (\`${opts.email}\`) and can complete email-verification (OTP code or confirmation link) end-to-end. This OVERRIDES the general "do not submit forms" rule for the signup/registration form ONLY.
74750
74818
 
74751
74819
  Steps:
74752
- 1. Navigate to the Sign Up / Register page (click the link in the UI). FIRST look for an email+password signup form (including after "Sign up with email"). Use Google / Gmail SSO ONLY if that form does not exist.
74820
+ 1. Navigate to the Sign Up / Register / Sign in page (click the link in the UI). FIRST look for an app Create-account email+password form (including after "Sign up with email").${opts.googleEmail && opts.googlePasswordKey ? ' "Continue with phone", SMS OTP, and "Mobile or email" on a Sign in page are NOT that form \u2014 if Continue with Google is offered and there is no app Create-account email form, use the Google / Gmail SSO playbook below (do not click Continue with phone).' : ""}
74753
74821
  2. Call \`provision_identity\` \u2192 it returns the email to register with (\`${opts.email}\`). The \`+\` part is a normal sub-address that still lands in our inbox.
74754
74822
  3. Fill the signup form: type that email into the email field with \`browser_type\` (this generated inbox email is intentionally visible and is allowed for registration); fill the password field with single-field \`fill_credential\` (credentialKey \`${opts.passwordKey}\`); fill any name/other required fields with simple test values. Do NOT use \`fill_credential_form\` for registration.
74755
74823
  - If the form REJECTS the email (says "invalid email" / will not accept the "+"), call \`provision_identity\` again with \`plain: true\` and use the bare address it returns instead.
@@ -74931,7 +74999,7 @@ This project asked to REGISTER a new account, but this runner CANNOT receive ema
74931
74999
  return `## Account registration & email verification (ENABLED)
74932
75000
  This run registers a new account using our ONE real, monitored inbox (the address \`${email}\` \u2014 the "+" part is a normal sub-address that still lands in our inbox) and can complete email verification end-to-end. This overrides any "do not submit forms" guidance for the signup form only.
74933
75001
 
74934
- 1. Go to the Sign Up / Register page. FIRST look for an email+password signup form (including after "Sign up with email"). Use Google / Gmail SSO ONLY if that form does not exist.
75002
+ 1. Go to the Sign Up / Register / Sign in page. FIRST look for an app Create-account email+password form (including after "Sign up with email").${google ? ' "Continue with phone", SMS OTP, and "Mobile or email" on a Sign in page are NOT that form \u2014 if Continue with Google is offered and there is no app Create-account email form, use the Google / Gmail SSO playbook below (do not click Continue with phone).' : ""}
74935
75003
  2. Call \`inbox_provision_identity\` \u2192 it returns the email to register with (\`${email}\`). Type that email into the email field.
74936
75004
  - If the form REJECTS the email (says "invalid email" / will not accept the "+"), call \`inbox_provision_identity\` with \`plain: true\` and use the bare address it returns instead.
74937
75005
  3. Fill the password with the \`${passwordKey}\` credential (use fill_credential). Submit the signup form.
@@ -333344,7 +333412,7 @@ ${keyLines || "- (none provided)"}
333344
333412
  ## EXACTLY what to do
333345
333413
  1. Navigate to ${baseUrl} and take a \`browser_snapshot\`.
333346
333414
  2. Find the Sign Up / Register / Create account affordance (match by PURPOSE, in the app's own language) and open the signup form. If a reveal button hides the fields ("Sign up with Email"), click it first.
333347
- 3. Follow the "Account Registration (verification inbox is ENABLED)" steps below EXACTLY: call \`provision_identity\` for the email, type that email, fill the password with \`fill_credential\`, fill any other required fields with simple test values, and submit. If there is NO email+password signup field and only "Continue with Google" / "Sign up with Gmail", follow the Google / Gmail SSO fallback in that section (bare Google account email, \`fill_credential\` with \`GOOGLE_SIGNIN_PASSWORD\`, never the IMAP app password).
333415
+ 3. Follow the "Account Registration (verification inbox is ENABLED)" steps below EXACTLY: call \`provision_identity\` for the email, type that email, fill the password with \`fill_credential\`, fill any other required fields with simple test values, and submit. If there is no app Create-account email form (phone / "Mobile or email" / SMS do not count) and Sign in offers "Continue with Google", follow the Google / Gmail SSO playbook (bare Google account email, \`fill_credential\` with \`GOOGLE_SIGNIN_PASSWORD\` on accounts.google.com, never TEST_USER_PASSWORD, never Continue with phone).
333348
333416
  4. Complete email verification using the inbox tools (\`wait_for_verification\` \u2192 enter the code or \`open_verification_link\`). Re-poll if the email is slow; resend AT MOST once; NEVER register a second account.
333349
333417
  5. Confirm you are signed in \u2014 a redirect to an authenticated route, or an in-place change to authenticated content. Take a \`browser_snapshot\`.
333350
333418
  6. \`capture_page\` the authenticated landing page in its DEFAULT state, then call \`finish_exploration\`. Do this the MOMENT the account is verified and you are signed in.
@@ -356286,7 +356354,7 @@ var require_package4 = __commonJS({
356286
356354
  "package.json"(exports2, module2) {
356287
356355
  module2.exports = {
356288
356356
  name: "@validate.qa/runner",
356289
- version: "1.0.93",
356357
+ version: "1.0.94",
356290
356358
  description: "validate local test runner - execute Playwright tests on your machine, connected to validate.qa cloud.",
356291
356359
  bin: {
356292
356360
  "validate-runner": "dist/cli.js"
package/dist/cli.mjs CHANGED
@@ -8571,10 +8571,13 @@ var require_google_signin = __commonJS({
8571
8571
  exports.googleSignInGuidanceOpts = googleSignInGuidanceOpts;
8572
8572
  exports.googleSignInAllowedEmails = googleSignInAllowedEmails;
8573
8573
  exports.collectGoogleSignInEnv = collectGoogleSignInEnv;
8574
+ exports.isGoogleAccountsUrl = isGoogleAccountsUrl;
8575
+ exports.googleSignInCredentialMismatch = googleSignInCredentialMismatch;
8574
8576
  exports.generateTotp = generateTotp;
8575
8577
  exports.buildGoogleSignInPromptSection = buildGoogleSignInPromptSection;
8576
8578
  var node_crypto_1 = __require("crypto");
8577
8579
  exports.GOOGLE_SIGNIN_PASSWORD_KEY = "GOOGLE_SIGNIN_PASSWORD";
8580
+ var APP_REGISTER_CREDENTIAL_KEYS = /^(TEST_|E2E_|QA_)?(USER_?EMAIL|USER_?PASSWORD|USER_?NAME|USERNAME)$/i;
8578
8581
  exports.GOOGLE_SIGNIN_ENV_KEYS = [
8579
8582
  "GOOGLE_SIGNIN_PASSWORD",
8580
8583
  "GOOGLE_SIGNIN_EMAIL",
@@ -8631,6 +8634,34 @@ var require_google_signin = __commonJS({
8631
8634
  }
8632
8635
  return out;
8633
8636
  }
8637
+ function isGoogleAccountsUrl(url) {
8638
+ if (!url)
8639
+ return false;
8640
+ try {
8641
+ const host = new URL(url).hostname.toLowerCase();
8642
+ return host === "accounts.google.com" || host.endsWith(".google.com") && host.includes("accounts");
8643
+ } catch {
8644
+ return /accounts\.google\.com/i.test(url);
8645
+ }
8646
+ }
8647
+ function googleSignInCredentialMismatch(pageUrl, credentialKey, opts) {
8648
+ const configured = opts?.configured ?? !!loadGoogleSignInConfig(opts?.env);
8649
+ if (!configured)
8650
+ return null;
8651
+ const onGoogle = isGoogleAccountsUrl(pageUrl);
8652
+ if (onGoogle) {
8653
+ if (credentialKey === exports.GOOGLE_SIGNIN_PASSWORD_KEY)
8654
+ return null;
8655
+ if (APP_REGISTER_CREDENTIAL_KEYS.test(credentialKey)) {
8656
+ return `fill_credential: this is Google account login (accounts.google.com), not app email signup. Do not use ${credentialKey}. Type the BARE Google email with browser_type, then fill_credential with credentialKey ${exports.GOOGLE_SIGNIN_PASSWORD_KEY}. Do not click Continue with phone / SMS OTP when Continue with Google is available.`;
8657
+ }
8658
+ return null;
8659
+ }
8660
+ if (credentialKey === exports.GOOGLE_SIGNIN_PASSWORD_KEY) {
8661
+ return `fill_credential: ${exports.GOOGLE_SIGNIN_PASSWORD_KEY} is only for accounts.google.com. Click Continue with Google first (not Continue with phone). Phone / "Mobile or email" is not app email signup.`;
8662
+ }
8663
+ return null;
8664
+ }
8634
8665
  function generateTotp(secret, atMs = Date.now(), stepSeconds = 30, digits = 6) {
8635
8666
  const key = decodeBase32(secret);
8636
8667
  const counter = Math.floor(atMs / 1e3 / stepSeconds);
@@ -8669,10 +8700,14 @@ var require_google_signin = __commonJS({
8669
8700
  const fill = variant === "cli" ? `fill_credential with credentialKey \`${opts.googlePasswordKey}\`` : `\`fill_credential\` (credentialKey \`${opts.googlePasswordKey}\`)`;
8670
8701
  const plainProvision = variant === "cli" ? "`inbox_provision_identity` with `plain: true`" : "`provision_identity` with `plain: true`";
8671
8702
  return `
8672
- Google / Gmail SSO fallback (SECOND choice \u2014 email+password signup is FIRST):
8673
- - FIRST follow the email-field playbook above whenever a signup form has an email / username / password field (including after clicking "Sign up with email"). Do NOT click Google if that form exists.
8674
- - ONLY if there is no email+password signup field and the only path is "Continue with Google" / "Sign up with Gmail" / "Sign in with Google": click that button. If a Google popup opens, switch to it (browser tabs).
8675
- - On accounts.google.com, type the BARE Google account email \`${opts.googleEmail}\` (no plus-tag \u2014 Google account login rejects plus-addresses) with browser_type, click Next, then fill the Google password with ${fill}. NEVER type the Google password as text and NEVER use the IMAP app password here.
8703
+ Google / Gmail SSO (use this when the APP has no Create-account email form):
8704
+ - App email+password SIGNUP means a form ON THIS APP to create an account (Sign up / Create account / Register, including after "Sign up with email"). That is FIRST. Do not use Google if that form exists.
8705
+ - These are NOT app email signup \u2014 do not treat them as the email playbook, and do not fill TEST_USER_EMAIL / TEST_USER_PASSWORD into them when Continue with Google is available:
8706
+ - "Continue with phone" / SMS / OTP
8707
+ - "Mobile or email" / phone-number identity on a Sign in page
8708
+ - Google's own email and password fields on accounts.google.com
8709
+ - If Sign in offers Continue with Google (and there is no app Create-account email form): click Continue with Google. Do NOT click Continue with phone for this registration.
8710
+ - If a Google popup or tab opens, switch to it. On accounts.google.com, type the BARE Google account email \`${opts.googleEmail}\` (no plus-tag) with browser_type, click Next, then fill the Google password with ${fill}. NEVER type the Google password as text, NEVER use TEST_USER_PASSWORD here, NEVER use the IMAP app password.
8676
8711
  - Click Next.${totp}
8677
8712
  - Click Continue / Allow on any consent screen, then return to the app tab.
8678
8713
  - If the app then emails a verification code/link, first call ${plainProvision} (Google SSO uses the bare inbox address, not the +tag), then complete it with the inbox tools as usual.
@@ -8704,7 +8739,7 @@ var require_credential_tools = __commonJS({
8704
8739
  type: "function",
8705
8740
  function: {
8706
8741
  name: "fill_credential",
8707
- description: 'Fill a stored credential VALUE into a form field. ALWAYS use this instead of `browser_type` for ANY email/password/token/auth field. You pass the variable KEY (e.g. "TEST_USER_EMAIL") and the runner injects the real value server-side \u2014 you never see the secret. The list of available credential keys is in the system prompt.',
8742
+ description: 'Fill a stored credential VALUE into a form field. ALWAYS use this instead of `browser_type` for ANY email/password/token/auth field. You pass the variable KEY (e.g. "TEST_USER_EMAIL") and the runner injects the real value server-side \u2014 you never see the secret. On accounts.google.com use GOOGLE_SIGNIN_PASSWORD (never TEST_USER_PASSWORD). The list of available credential keys is in the system prompt.',
8708
8743
  parameters: {
8709
8744
  type: "object",
8710
8745
  properties: {
@@ -8866,6 +8901,22 @@ CREDENTIAL ROTATION (required when the STORED user's secret changes \u2014 read
8866
8901
  return entries.map(([k, v]) => `- **${k}**: \`${v}\``).join("\n");
8867
8902
  }
8868
8903
  var DEFAULT_MAX_RESULT_CHARS = 15e3;
8904
+ var PAGE_URL_RE = /Page URL:\s*(\S+)/i;
8905
+ async function peekPageUrl(mcpClient) {
8906
+ try {
8907
+ const mcpResult = await mcpClient.callTool({ name: "browser_snapshot", arguments: {} });
8908
+ const { text } = parseMcpContent(mcpResult);
8909
+ const match = text.match(PAGE_URL_RE);
8910
+ return match?.[1]?.replace(/[),.;]+$/, "");
8911
+ } catch {
8912
+ return void 0;
8913
+ }
8914
+ }
8915
+ function googleFillBlocked(pageUrl, credentialKey, credentials) {
8916
+ return (0, google_signin_js_1.googleSignInCredentialMismatch)(pageUrl, credentialKey, {
8917
+ configured: !!credentials[google_signin_js_1.GOOGLE_SIGNIN_PASSWORD_KEY]
8918
+ });
8919
+ }
8869
8920
  async function handleFillCredential(toolArgs, ctx) {
8870
8921
  const key = typeof toolArgs.credentialKey === "string" ? toolArgs.credentialKey : "";
8871
8922
  const element = typeof toolArgs.element === "string" ? toolArgs.element : "";
@@ -8887,6 +8938,13 @@ CREDENTIAL ROTATION (required when the STORED user's secret changes \u2014 read
8887
8938
  didMutate: false
8888
8939
  };
8889
8940
  }
8941
+ if (ctx.credentials[google_signin_js_1.GOOGLE_SIGNIN_PASSWORD_KEY]) {
8942
+ const pageUrl = await peekPageUrl(ctx.mcpClient);
8943
+ const blocked = googleFillBlocked(pageUrl, key, ctx.credentials);
8944
+ if (blocked) {
8945
+ return { content: JSON.stringify({ error: blocked }), didMutate: false };
8946
+ }
8947
+ }
8890
8948
  const underlyingArgs = { element, ref, text: value, submit };
8891
8949
  const mcpResult = await ctx.mcpClient.callTool({ name: "browser_type", arguments: underlyingArgs });
8892
8950
  const mcpFailed = mcpResultIsError(mcpResult);
@@ -8925,6 +8983,16 @@ CREDENTIAL ROTATION (required when the STORED user's secret changes \u2014 read
8925
8983
  }
8926
8984
  resolved.push({ field, value });
8927
8985
  }
8986
+ if (ctx.credentials[google_signin_js_1.GOOGLE_SIGNIN_PASSWORD_KEY]) {
8987
+ const pageUrl = await peekPageUrl(ctx.mcpClient);
8988
+ for (const f of fields) {
8989
+ const key = typeof f.credentialKey === "string" ? f.credentialKey : typeof f.key === "string" ? f.key : "";
8990
+ const blocked = googleFillBlocked(pageUrl, key, ctx.credentials);
8991
+ if (blocked) {
8992
+ return { content: JSON.stringify({ error: blocked }), didMutate: false };
8993
+ }
8994
+ }
8995
+ }
8928
8996
  if (missing.length > 0) {
8929
8997
  const available = Object.keys(ctx.credentials).filter((k) => ctx.credentials[k]).join(", ") || "(none configured)";
8930
8998
  return {
@@ -74754,7 +74822,7 @@ var require_inbox_tools = __commonJS({
74754
74822
  ${where} You register using ONE real, monitored email (\`${opts.email}\`) and can complete email-verification (OTP code or confirmation link) end-to-end. This OVERRIDES the general "do not submit forms" rule for the signup/registration form ONLY.
74755
74823
 
74756
74824
  Steps:
74757
- 1. Navigate to the Sign Up / Register page (click the link in the UI). FIRST look for an email+password signup form (including after "Sign up with email"). Use Google / Gmail SSO ONLY if that form does not exist.
74825
+ 1. Navigate to the Sign Up / Register / Sign in page (click the link in the UI). FIRST look for an app Create-account email+password form (including after "Sign up with email").${opts.googleEmail && opts.googlePasswordKey ? ' "Continue with phone", SMS OTP, and "Mobile or email" on a Sign in page are NOT that form \u2014 if Continue with Google is offered and there is no app Create-account email form, use the Google / Gmail SSO playbook below (do not click Continue with phone).' : ""}
74758
74826
  2. Call \`provision_identity\` \u2192 it returns the email to register with (\`${opts.email}\`). The \`+\` part is a normal sub-address that still lands in our inbox.
74759
74827
  3. Fill the signup form: type that email into the email field with \`browser_type\` (this generated inbox email is intentionally visible and is allowed for registration); fill the password field with single-field \`fill_credential\` (credentialKey \`${opts.passwordKey}\`); fill any name/other required fields with simple test values. Do NOT use \`fill_credential_form\` for registration.
74760
74828
  - If the form REJECTS the email (says "invalid email" / will not accept the "+"), call \`provision_identity\` again with \`plain: true\` and use the bare address it returns instead.
@@ -74936,7 +75004,7 @@ This project asked to REGISTER a new account, but this runner CANNOT receive ema
74936
75004
  return `## Account registration & email verification (ENABLED)
74937
75005
  This run registers a new account using our ONE real, monitored inbox (the address \`${email}\` \u2014 the "+" part is a normal sub-address that still lands in our inbox) and can complete email verification end-to-end. This overrides any "do not submit forms" guidance for the signup form only.
74938
75006
 
74939
- 1. Go to the Sign Up / Register page. FIRST look for an email+password signup form (including after "Sign up with email"). Use Google / Gmail SSO ONLY if that form does not exist.
75007
+ 1. Go to the Sign Up / Register / Sign in page. FIRST look for an app Create-account email+password form (including after "Sign up with email").${google ? ' "Continue with phone", SMS OTP, and "Mobile or email" on a Sign in page are NOT that form \u2014 if Continue with Google is offered and there is no app Create-account email form, use the Google / Gmail SSO playbook below (do not click Continue with phone).' : ""}
74940
75008
  2. Call \`inbox_provision_identity\` \u2192 it returns the email to register with (\`${email}\`). Type that email into the email field.
74941
75009
  - If the form REJECTS the email (says "invalid email" / will not accept the "+"), call \`inbox_provision_identity\` with \`plain: true\` and use the bare address it returns instead.
74942
75010
  3. Fill the password with the \`${passwordKey}\` credential (use fill_credential). Submit the signup form.
@@ -333349,7 +333417,7 @@ ${keyLines || "- (none provided)"}
333349
333417
  ## EXACTLY what to do
333350
333418
  1. Navigate to ${baseUrl} and take a \`browser_snapshot\`.
333351
333419
  2. Find the Sign Up / Register / Create account affordance (match by PURPOSE, in the app's own language) and open the signup form. If a reveal button hides the fields ("Sign up with Email"), click it first.
333352
- 3. Follow the "Account Registration (verification inbox is ENABLED)" steps below EXACTLY: call \`provision_identity\` for the email, type that email, fill the password with \`fill_credential\`, fill any other required fields with simple test values, and submit. If there is NO email+password signup field and only "Continue with Google" / "Sign up with Gmail", follow the Google / Gmail SSO fallback in that section (bare Google account email, \`fill_credential\` with \`GOOGLE_SIGNIN_PASSWORD\`, never the IMAP app password).
333420
+ 3. Follow the "Account Registration (verification inbox is ENABLED)" steps below EXACTLY: call \`provision_identity\` for the email, type that email, fill the password with \`fill_credential\`, fill any other required fields with simple test values, and submit. If there is no app Create-account email form (phone / "Mobile or email" / SMS do not count) and Sign in offers "Continue with Google", follow the Google / Gmail SSO playbook (bare Google account email, \`fill_credential\` with \`GOOGLE_SIGNIN_PASSWORD\` on accounts.google.com, never TEST_USER_PASSWORD, never Continue with phone).
333353
333421
  4. Complete email verification using the inbox tools (\`wait_for_verification\` \u2192 enter the code or \`open_verification_link\`). Re-poll if the email is slow; resend AT MOST once; NEVER register a second account.
333354
333422
  5. Confirm you are signed in \u2014 a redirect to an authenticated route, or an in-place change to authenticated content. Take a \`browser_snapshot\`.
333355
333423
  6. \`capture_page\` the authenticated landing page in its DEFAULT state, then call \`finish_exploration\`. Do this the MOMENT the account is verified and you are signed in.
@@ -356291,7 +356359,7 @@ var require_package4 = __commonJS({
356291
356359
  "package.json"(exports, module) {
356292
356360
  module.exports = {
356293
356361
  name: "@validate.qa/runner",
356294
- version: "1.0.93",
356362
+ version: "1.0.94",
356295
356363
  description: "validate local test runner - execute Playwright tests on your machine, connected to validate.qa cloud.",
356296
356364
  bin: {
356297
356365
  "validate-runner": "dist/cli.js"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@validate.qa/runner",
3
- "version": "1.0.93",
3
+ "version": "1.0.94",
4
4
  "description": "validate local test runner - execute Playwright tests on your machine, connected to validate.qa cloud.",
5
5
  "bin": {
6
6
  "validate-runner": "dist/cli.js"