@validate.qa/runner 1.0.103 → 1.0.104
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/README.md +7 -2
- package/dist/{chunk-YI3ZC2XI.mjs → chunk-6N4QCCEH.mjs} +2 -2
- package/dist/{chunk-CMM4DOXC.mjs → chunk-EBWZ7NGU.mjs} +11 -8
- package/dist/{chunk-OTKJZIOD.mjs → chunk-EKY6CN4Y.mjs} +659 -122
- package/dist/{chunk-CG75I3ZZ.mjs → chunk-MEE4DXRX.mjs} +13437 -1386
- package/dist/{chunk-WVLBQDFP.mjs → chunk-OXDU6ARE.mjs} +8 -2
- package/dist/{chunk-AAUHXGDS.mjs → chunk-PUMRAFJS.mjs} +37 -13
- package/dist/{chunk-BECCGMU4.mjs → chunk-TGVKABFN.mjs} +45 -3
- package/dist/{chunk-YIM746WO.mjs → chunk-TS4OUJVT.mjs} +1 -1
- package/dist/{chunk-NNJYKR3O.mjs → chunk-UR7KDOTP.mjs} +29 -6
- package/dist/{chunk-36AWDKPL.mjs → chunk-UZ67UBXH.mjs} +14 -3
- package/dist/{chunk-7SH3COMQ.mjs → chunk-VWE3SQ2Z.mjs} +1 -1
- package/dist/{chunk-TK5KEGNW.mjs → chunk-XXZZMG6Q.mjs} +15 -3
- package/dist/cli.js +20962 -7343
- package/dist/cli.mjs +1159 -245
- package/dist/credential-mcp-server.js +671 -127
- package/dist/credential-mcp-server.mjs +3 -3
- package/dist/discovery-mcp-server.js +710 -129
- package/dist/discovery-mcp-server.mjs +4 -4
- package/dist/dist-BXHLIG5H.mjs +17 -0
- package/dist/inbox-mcp-server.js +664 -123
- package/dist/inbox-mcp-server.mjs +3 -3
- package/dist/route-seed-worker.js +671 -124
- package/dist/route-seed-worker.mjs +3 -3
- package/dist/run-write-guard-preload.js +713 -125
- package/dist/run-write-guard-preload.mjs +4 -4
- package/dist/run-write-guard.js +713 -125
- package/dist/run-write-guard.mjs +3 -3
- package/dist/tar-extract-child.js +38 -14
- package/dist/tar-extract-child.mjs +2 -2
- package/package.json +3 -2
- package/dist/dist-2G7YTNH5.mjs +0 -17
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
dist_exports,
|
|
3
3
|
init_dist
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-EKY6CN4Y.mjs";
|
|
5
5
|
import {
|
|
6
6
|
__commonJS,
|
|
7
7
|
__esm,
|
|
@@ -68077,7 +68077,13 @@ await expect(page).not.toHaveURL(/accounts\\.google\\.com/, { timeout: 60_000 })
|
|
|
68077
68077
|
\`\`\`
|
|
68078
68078
|
Never emit code that clicks, fills or asserts anything on accounts.google.com.`;
|
|
68079
68079
|
}
|
|
68080
|
-
function buildGoogleSignInTestGenSection(_opts) {
|
|
68080
|
+
function buildGoogleSignInTestGenSection(_opts, ctx = {}) {
|
|
68081
|
+
if (ctx.appLoginGiven) {
|
|
68082
|
+
return `
|
|
68083
|
+
## SIGN-IN: USE THE TEST ACCOUNT
|
|
68084
|
+
This project gave a test account (the Browser Credentials / \`process.env.TEST_USER_*\` values). Sign in with it on the app's own email (or username) and password form, even when the app also offers Continue with Google. Do not click Continue with Google / Sign in with Google / Sign up with Google to sign in.
|
|
68085
|
+
Use Continue with Google only when this scenario's goal is the Google sign-in itself, or the app has no email/username and password sign-in at all. Then click that control on the app and wait until the browser is back on the app: \`await expect(page).not.toHaveURL(/accounts\\.google\\.com/, { timeout: 60_000 })\` (the runner completes Google's step). Never click, fill or assert anything on accounts.google.com, never type a password or code there.`;
|
|
68086
|
+
}
|
|
68081
68087
|
return `
|
|
68082
68088
|
## GOOGLE SIGN-IN (the runner completes Google's step)
|
|
68083
68089
|
When this scenario uses Continue with Google / Sign in with Google / Sign up with Google:
|
|
@@ -6225,7 +6225,7 @@ var require_repo_acquire = __commonJS({
|
|
|
6225
6225
|
return mod && mod.__esModule ? mod : { "default": mod };
|
|
6226
6226
|
};
|
|
6227
6227
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6228
|
-
exports.ARCHIVE_TOO_LARGE_RE = exports.MAX_ZIP_TOTAL_BYTES = exports.MAX_ZIP_FILE_BYTES = exports.MAX_ZIP_ENTRIES = exports.MAX_ARCHIVE_BYTES = void 0;
|
|
6228
|
+
exports.ARCHIVE_TOO_LARGE_RE = exports.REPO_TARBALL_LIMITS = exports.MAX_ZIP_TOTAL_BYTES = exports.MAX_ZIP_FILE_BYTES = exports.MAX_ZIP_ENTRIES = exports.MAX_ARCHIVE_BYTES = void 0;
|
|
6229
6229
|
exports.acquireRepoForImport = acquireRepoForImport;
|
|
6230
6230
|
exports.downloadArchiveCapped = downloadArchiveCapped;
|
|
6231
6231
|
exports.formatArchiveCap = formatArchiveCap;
|
|
@@ -6251,6 +6251,7 @@ var require_repo_acquire = __commonJS({
|
|
|
6251
6251
|
exports.MAX_ZIP_ENTRIES = 2e4;
|
|
6252
6252
|
exports.MAX_ZIP_FILE_BYTES = 50 * 1024 * 1024;
|
|
6253
6253
|
exports.MAX_ZIP_TOTAL_BYTES = 600 * 1024 * 1024;
|
|
6254
|
+
exports.REPO_TARBALL_LIMITS = { maxEntries: 2e5, maxFileBytes: exports.MAX_ZIP_FILE_BYTES, maxTotalBytes: exports.MAX_ZIP_TOTAL_BYTES, oversizeFiles: "skip" };
|
|
6254
6255
|
function envGithubTokenForImports() {
|
|
6255
6256
|
const optedIn = ["1", "true", "yes", "on"].includes(String(process.env.RUNNER_IMPORT_ENV_GITHUB_TOKEN ?? "").trim().toLowerCase());
|
|
6256
6257
|
if (!optedIn)
|
|
@@ -6294,7 +6295,14 @@ var require_repo_acquire = __commonJS({
|
|
|
6294
6295
|
extractRoot,
|
|
6295
6296
|
/* strip */
|
|
6296
6297
|
1,
|
|
6297
|
-
{
|
|
6298
|
+
{
|
|
6299
|
+
subject: "repository archive",
|
|
6300
|
+
onUnavailable: "in-process",
|
|
6301
|
+
log,
|
|
6302
|
+
signal: spec.signal,
|
|
6303
|
+
tenantKey: spec.projectId,
|
|
6304
|
+
limits: { ...exports.REPO_TARBALL_LIMITS }
|
|
6305
|
+
}
|
|
6298
6306
|
);
|
|
6299
6307
|
await (0, promises_1.rm)(tarPath, { force: true }).catch(noop);
|
|
6300
6308
|
log(`[repo-acquire] extracted github tarball (${archiveBytes} bytes)`);
|
|
@@ -6317,7 +6325,8 @@ var require_repo_acquire = __commonJS({
|
|
|
6317
6325
|
log,
|
|
6318
6326
|
signal: spec.signal,
|
|
6319
6327
|
tenantKey: spec.projectId,
|
|
6320
|
-
hint: "Check it is a valid .tar.gz, or upload it as a .zip."
|
|
6328
|
+
hint: "Check it is a valid .tar.gz, or upload it as a .zip.",
|
|
6329
|
+
limits: { ...exports.REPO_TARBALL_LIMITS }
|
|
6321
6330
|
}
|
|
6322
6331
|
);
|
|
6323
6332
|
} else if (kind === "zip") {
|
|
@@ -6326,7 +6335,8 @@ var require_repo_acquire = __commonJS({
|
|
|
6326
6335
|
log,
|
|
6327
6336
|
signal: spec.signal,
|
|
6328
6337
|
tenantKey: spec.projectId,
|
|
6329
|
-
hint: "Check it is a valid .zip, or upload it as a .tar.gz."
|
|
6338
|
+
hint: "Check it is a valid .zip, or upload it as a .tar.gz.",
|
|
6339
|
+
oversizeFiles: exports.REPO_TARBALL_LIMITS.oversizeFiles
|
|
6330
6340
|
});
|
|
6331
6341
|
} else {
|
|
6332
6342
|
await (0, promises_1.rm)(archivePath, { force: true }).catch(noop);
|
|
@@ -6536,7 +6546,7 @@ var require_repo_acquire = __commonJS({
|
|
|
6536
6546
|
bad = new Error(`Tar entry path contains a NUL byte: ${JSON.stringify(shownPath)}`);
|
|
6537
6547
|
} else if (typeof size !== "number" || !Number.isSafeInteger(size) || size < 0 || size > MAX_OCTAL_TAR_SIZE) {
|
|
6538
6548
|
bad = new Error(`Tar entry has an invalid size field: ${shownPath}`);
|
|
6539
|
-
} else if (size > limits.maxFileBytes) {
|
|
6549
|
+
} else if (size > limits.maxFileBytes && limits.oversizeFiles !== "skip") {
|
|
6540
6550
|
bad = new Error(`Tar entry too large: ${shownPath} (declared ${size} bytes > ${limits.maxFileBytes} cap)`);
|
|
6541
6551
|
} else if ((declaredTotal += size) > limits.maxTotalBytes) {
|
|
6542
6552
|
bad = new Error(`Tar total uncompressed size exceeds ${limits.maxTotalBytes} cap (tar-bomb guard)`);
|
|
@@ -6603,7 +6613,8 @@ var require_repo_acquire = __commonJS({
|
|
|
6603
6613
|
return false;
|
|
6604
6614
|
}
|
|
6605
6615
|
const sz = Number(entry.size ?? 0);
|
|
6606
|
-
|
|
6616
|
+
const oversize = sz > limits.maxFileBytes;
|
|
6617
|
+
if (oversize && limits.oversizeFiles !== "skip") {
|
|
6607
6618
|
capError = new Error(`Tar entry too large: ${p} (declared ${sz} bytes > ${limits.maxFileBytes} cap)`);
|
|
6608
6619
|
return false;
|
|
6609
6620
|
}
|
|
@@ -6612,13 +6623,13 @@ var require_repo_acquire = __commonJS({
|
|
|
6612
6623
|
capError = new Error(`Tar total uncompressed size exceeds ${limits.maxTotalBytes} cap (tar-bomb guard)`);
|
|
6613
6624
|
return false;
|
|
6614
6625
|
}
|
|
6615
|
-
return
|
|
6626
|
+
return !oversize;
|
|
6616
6627
|
}
|
|
6617
6628
|
}));
|
|
6618
6629
|
if (capError)
|
|
6619
6630
|
throw capError;
|
|
6620
6631
|
}
|
|
6621
|
-
async function extractZipSafely(buf, destDir, log = noop) {
|
|
6632
|
+
async function extractZipSafely(buf, destDir, log = noop, options = {}) {
|
|
6622
6633
|
const zip = new adm_zip_1.default(buf);
|
|
6623
6634
|
const entries = zip.getEntries();
|
|
6624
6635
|
if (entries.length > exports.MAX_ZIP_ENTRIES) {
|
|
@@ -6627,6 +6638,7 @@ var require_repo_acquire = __commonJS({
|
|
|
6627
6638
|
const destResolved = (0, node_path_1.resolve)(destDir);
|
|
6628
6639
|
let total = 0;
|
|
6629
6640
|
let files = 0;
|
|
6641
|
+
let skipped = 0;
|
|
6630
6642
|
for (const entry of entries) {
|
|
6631
6643
|
const name = entry.entryName;
|
|
6632
6644
|
if (isUnsafeEntryName(name)) {
|
|
@@ -6641,12 +6653,18 @@ var require_repo_acquire = __commonJS({
|
|
|
6641
6653
|
continue;
|
|
6642
6654
|
}
|
|
6643
6655
|
const declared = entry.header?.size ?? 0;
|
|
6644
|
-
if (declared > exports.MAX_ZIP_FILE_BYTES) {
|
|
6645
|
-
throw new Error(`Zip entry too large: ${name} (declared ${declared} bytes > ${exports.MAX_ZIP_FILE_BYTES} cap)`);
|
|
6646
|
-
}
|
|
6647
6656
|
if (total + declared > exports.MAX_ZIP_TOTAL_BYTES) {
|
|
6648
6657
|
throw new Error(`Zip total uncompressed size exceeds ${exports.MAX_ZIP_TOTAL_BYTES} cap (zip-bomb guard)`);
|
|
6649
6658
|
}
|
|
6659
|
+
if (declared > exports.MAX_ZIP_FILE_BYTES && options.oversizeFiles !== "skip") {
|
|
6660
|
+
throw new Error(`Zip entry too large: ${name} (declared ${declared} bytes > ${exports.MAX_ZIP_FILE_BYTES} cap)`);
|
|
6661
|
+
}
|
|
6662
|
+
if (declared > exports.MAX_ZIP_FILE_BYTES) {
|
|
6663
|
+
total += declared;
|
|
6664
|
+
skipped++;
|
|
6665
|
+
log(`[repo-acquire] zip: skipped ${name} (declared ${declared} bytes > ${exports.MAX_ZIP_FILE_BYTES} per-file cap)`);
|
|
6666
|
+
continue;
|
|
6667
|
+
}
|
|
6650
6668
|
const data = entry.getData();
|
|
6651
6669
|
if (data.length > exports.MAX_ZIP_FILE_BYTES) {
|
|
6652
6670
|
throw new Error(`Zip entry too large: ${name} (${data.length} bytes > ${exports.MAX_ZIP_FILE_BYTES} cap)`);
|
|
@@ -6659,7 +6677,7 @@ var require_repo_acquire = __commonJS({
|
|
|
6659
6677
|
await (0, promises_1.writeFile)(target, data);
|
|
6660
6678
|
files++;
|
|
6661
6679
|
}
|
|
6662
|
-
log(`[repo-acquire] zip extracted: ${files} file(s), ${total} bytes`);
|
|
6680
|
+
log(`[repo-acquire] zip extracted: ${files} file(s), ${total} bytes${skipped ? `, ${skipped} oversize file(s) skipped` : ""}`);
|
|
6663
6681
|
}
|
|
6664
6682
|
async function normalizeRepoRoot(extractRoot) {
|
|
6665
6683
|
let entries;
|
|
@@ -7162,7 +7180,13 @@ var require_tar_isolated = __commonJS({
|
|
|
7162
7180
|
}
|
|
7163
7181
|
async function extractZipIsolated(archivePath, destDir, options) {
|
|
7164
7182
|
try {
|
|
7165
|
-
|
|
7183
|
+
const job = {
|
|
7184
|
+
op: "extract-zip",
|
|
7185
|
+
archivePath: (0, node_path_1.resolve)(archivePath),
|
|
7186
|
+
destDir: (0, node_path_1.resolve)(destDir),
|
|
7187
|
+
...options.oversizeFiles ? { oversizeFiles: options.oversizeFiles } : {}
|
|
7188
|
+
};
|
|
7189
|
+
await runTarJobIsolated(job, options.subject, options);
|
|
7166
7190
|
} catch (err) {
|
|
7167
7191
|
if (err instanceof TarIsolationUnavailableError)
|
|
7168
7192
|
throw refuseUnavailable(err, options.subject, options.log);
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
require_survey_network_guard
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-UZ67UBXH.mjs";
|
|
4
4
|
import {
|
|
5
5
|
dist_exports,
|
|
6
6
|
init_dist
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-EKY6CN4Y.mjs";
|
|
8
8
|
import {
|
|
9
9
|
__commonJS,
|
|
10
10
|
__require,
|
|
@@ -462,6 +462,13 @@ var require_run_write_guard = __commonJS({
|
|
|
462
462
|
function currentRunSignInSecrets() {
|
|
463
463
|
return policyScope.getStore()?.signInSecrets ?? [];
|
|
464
464
|
}
|
|
465
|
+
function isSocketIoPollingPost(pathname, search) {
|
|
466
|
+
if (pathname !== "/socket.io" && pathname !== "/socket.io/")
|
|
467
|
+
return false;
|
|
468
|
+
const eio = search.getAll("EIO");
|
|
469
|
+
const transport = search.getAll("transport");
|
|
470
|
+
return eio.length === 1 && /^[0-9]{1,2}$/.test(eio[0]) && transport.length === 1 && transport[0] === "polling";
|
|
471
|
+
}
|
|
465
472
|
var READ_METHODS = /* @__PURE__ */ new Set(["GET", "HEAD", "OPTIONS"]);
|
|
466
473
|
var MAX_BODY_CHARS = 262144;
|
|
467
474
|
var MAX_SIGN_IN_LOG_LINES = 20;
|
|
@@ -1296,7 +1303,8 @@ var require_run_write_guard = __commonJS({
|
|
|
1296
1303
|
const method = facts.method.toUpperCase();
|
|
1297
1304
|
const host = url.hostname.toLowerCase().replace(/\.$/, "");
|
|
1298
1305
|
const pathname = url.pathname;
|
|
1299
|
-
|
|
1306
|
+
const queryRead = method === "QUERY" && !(0, survey_network_guard_js_1.queryMethodMayWrite)(url, facts.postData, isGraphqlPath(pathname));
|
|
1307
|
+
if (READ_METHODS.has(method) || queryRead) {
|
|
1300
1308
|
if (method === "GET" && isGraphqlPath(pathname) && (0, survey_network_guard_js_1.graphqlGetMayWrite)(url, facts.postData)) {
|
|
1301
1309
|
return { action: "write", rule: "graphql-get-mutation", record: describe(facts, url, "graphql-get-mutation") };
|
|
1302
1310
|
}
|
|
@@ -1351,6 +1359,8 @@ var require_run_write_guard = __commonJS({
|
|
|
1351
1359
|
if (segs.length > 0 && SEARCH_LAST_SEGMENTS.has(segs[segs.length - 1]))
|
|
1352
1360
|
return { action: "allow", rule: "search-post" };
|
|
1353
1361
|
}
|
|
1362
|
+
if (appSite && method === "POST" && isSocketIoPollingPost(pathname, url.searchParams))
|
|
1363
|
+
return { action: "allow", rule: "realtime-poll" };
|
|
1354
1364
|
if (hostIs(host, PAYMENT_HOSTS))
|
|
1355
1365
|
return { action: "write", rule: "payment", record: describe(facts, url, "payment") };
|
|
1356
1366
|
if (appSite)
|
|
@@ -2155,6 +2165,32 @@ var require_run_write_guard = __commonJS({
|
|
|
2155
2165
|
return false;
|
|
2156
2166
|
}
|
|
2157
2167
|
}
|
|
2168
|
+
function contextStartsOffline(context) {
|
|
2169
|
+
try {
|
|
2170
|
+
return context._options?.offline === true;
|
|
2171
|
+
} catch {
|
|
2172
|
+
return false;
|
|
2173
|
+
}
|
|
2174
|
+
}
|
|
2175
|
+
function trackOffline(context) {
|
|
2176
|
+
const state = { offline: contextStartsOffline(context) };
|
|
2177
|
+
const original = context.setOffline;
|
|
2178
|
+
if (typeof original === "function") {
|
|
2179
|
+
Object.assign(context, {
|
|
2180
|
+
setOffline: async (offline) => {
|
|
2181
|
+
const before = state.offline;
|
|
2182
|
+
state.offline = offline === true;
|
|
2183
|
+
try {
|
|
2184
|
+
await original.call(context, offline);
|
|
2185
|
+
} catch (err) {
|
|
2186
|
+
state.offline = before;
|
|
2187
|
+
throw err;
|
|
2188
|
+
}
|
|
2189
|
+
}
|
|
2190
|
+
});
|
|
2191
|
+
}
|
|
2192
|
+
return state;
|
|
2193
|
+
}
|
|
2158
2194
|
function hopRequestHeaders(pageHeaders, cookie) {
|
|
2159
2195
|
const out = { accept: "*/*" };
|
|
2160
2196
|
for (const [name, value] of Object.entries(pageHeaders)) {
|
|
@@ -2484,6 +2520,7 @@ var require_run_write_guard = __commonJS({
|
|
|
2484
2520
|
return existing;
|
|
2485
2521
|
const guard = new RunWriteGuard(policy, opts);
|
|
2486
2522
|
countAppWebSocketMessages(context, guard);
|
|
2523
|
+
const emulated = policy.mode === "block" ? trackOffline(context) : { offline: false };
|
|
2487
2524
|
if (policy.mode === "observe") {
|
|
2488
2525
|
context.on("request", (request) => {
|
|
2489
2526
|
try {
|
|
@@ -2516,6 +2553,11 @@ var require_run_write_guard = __commonJS({
|
|
|
2516
2553
|
}
|
|
2517
2554
|
}
|
|
2518
2555
|
if (decision.action === "allow" && !READ_METHODS.has(request.method().toUpperCase()) && checksRedirect(decision.rule, request.url(), guard.policy)) {
|
|
2556
|
+
if (emulated.offline) {
|
|
2557
|
+
await route.fallback().catch(() => {
|
|
2558
|
+
});
|
|
2559
|
+
return;
|
|
2560
|
+
}
|
|
2519
2561
|
await sendCheckingRedirect(route, guard, context);
|
|
2520
2562
|
return;
|
|
2521
2563
|
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
require_route_manifest
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-XXZZMG6Q.mjs";
|
|
4
4
|
import {
|
|
5
5
|
require_survey_network_guard
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-UZ67UBXH.mjs";
|
|
7
7
|
import {
|
|
8
8
|
dist_exports,
|
|
9
9
|
init_dist
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-EKY6CN4Y.mjs";
|
|
11
11
|
import {
|
|
12
12
|
__commonJS,
|
|
13
13
|
__toCommonJS
|
|
@@ -1904,8 +1904,9 @@ var require_repo_feature_verification = __commonJS({
|
|
|
1904
1904
|
"the",
|
|
1905
1905
|
"for"
|
|
1906
1906
|
]);
|
|
1907
|
+
var UNSPACED_SCRIPT = /[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}]/u;
|
|
1907
1908
|
function rootCardTerms(featureName) {
|
|
1908
|
-
const words = String(featureName ?? "").toLowerCase().split(/[
|
|
1909
|
+
const words = String(featureName ?? "").toLowerCase().split(/[^\p{L}\p{N}]+/u).filter((w) => [...w].length >= (UNSPACED_SCRIPT.test(w) ? 2 : 4) && !ROOT_GENERIC_WORDS.has(w));
|
|
1909
1910
|
return [...new Set(words.map((w) => w.length > 4 && w.endsWith("s") ? w.slice(0, -1) : w))];
|
|
1910
1911
|
}
|
|
1911
1912
|
function textShowsAnyTerm(text, terms) {
|
|
@@ -1959,7 +1960,7 @@ var require_repo_feature_verification = __commonJS({
|
|
|
1959
1960
|
return null;
|
|
1960
1961
|
}
|
|
1961
1962
|
function normalizeControlText(text) {
|
|
1962
|
-
return text.normalize("NFKC").toLowerCase().replace(/[^\p{L}\p{N}\p{M}]+/gu, " ").trim();
|
|
1963
|
+
return text.normalize("NFKD").replace(/(\p{Script=Latin})\p{M}+/gu, "$1").normalize("NFKC").toLowerCase().replace(/[^\p{L}\p{N}\p{M}]+/gu, " ").trim();
|
|
1963
1964
|
}
|
|
1964
1965
|
var SESSION_END_LABEL = /^(?:log|sign) ?(?:out|off)$/;
|
|
1965
1966
|
var SESSION_END_SPELLINGS = ["log out", "logout", "log off", "logoff", "sign out", "signout", "sign off", "signoff"];
|
|
@@ -1972,13 +1973,35 @@ var require_repo_feature_verification = __commonJS({
|
|
|
1972
1973
|
return [];
|
|
1973
1974
|
return SESSION_END_LABEL.test(wanted) ? SESSION_END_SPELLINGS : [wanted];
|
|
1974
1975
|
}
|
|
1976
|
+
var SHORT_LABEL_CHARS = 2;
|
|
1977
|
+
var WORD_SEGMENTER = new Intl.Segmenter(void 0, { granularity: "word" });
|
|
1978
|
+
function wholeWordsSpell(text, wanted) {
|
|
1979
|
+
const words = [];
|
|
1980
|
+
for (const s of WORD_SEGMENTER.segment(text))
|
|
1981
|
+
if (s.isWordLike)
|
|
1982
|
+
words.push(s.segment);
|
|
1983
|
+
for (let i = 0; i < words.length; i++) {
|
|
1984
|
+
let run = "";
|
|
1985
|
+
for (let j = i; j < words.length && run.length < wanted.length; j++) {
|
|
1986
|
+
run += words[j];
|
|
1987
|
+
if (run === wanted)
|
|
1988
|
+
return true;
|
|
1989
|
+
}
|
|
1990
|
+
}
|
|
1991
|
+
return false;
|
|
1992
|
+
}
|
|
1975
1993
|
function textNamesControl(text, label) {
|
|
1976
1994
|
const spellings = controlSpellings(label);
|
|
1977
1995
|
if (spellings.length === 0)
|
|
1978
1996
|
return false;
|
|
1979
1997
|
const haystack = normalizeControlText(text);
|
|
1980
1998
|
const squeezed = haystack.replace(/ /g, "");
|
|
1981
|
-
return spellings.some((w) =>
|
|
1999
|
+
return spellings.some((w) => {
|
|
2000
|
+
const bare = w.replace(/ /g, "");
|
|
2001
|
+
if (!haystack.includes(w) && !squeezed.includes(bare))
|
|
2002
|
+
return false;
|
|
2003
|
+
return [...bare].length > SHORT_LABEL_CHARS || wholeWordsSpell(haystack, bare);
|
|
2004
|
+
});
|
|
1982
2005
|
}
|
|
1983
2006
|
function pageShowsControl(page, label) {
|
|
1984
2007
|
const text = capturedPageText(page);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
dist_exports,
|
|
3
3
|
init_dist
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-EKY6CN4Y.mjs";
|
|
5
5
|
import {
|
|
6
6
|
__commonJS,
|
|
7
7
|
__require,
|
|
@@ -27,6 +27,7 @@ var require_survey_network_guard = __commonJS({
|
|
|
27
27
|
exports.graphqlUrlCarriesQuery = graphqlUrlCarriesQuery;
|
|
28
28
|
exports.graphqlUrlQueriesAreReads = graphqlUrlQueriesAreReads;
|
|
29
29
|
exports.graphqlGetMayWrite = graphqlGetMayWrite;
|
|
30
|
+
exports.queryMethodMayWrite = queryMethodMayWrite;
|
|
30
31
|
exports.writeShapedGet = writeShapedGet;
|
|
31
32
|
exports.decideSurveyRequest = decideSurveyRequest;
|
|
32
33
|
exports.installSurveyNetworkGuard = installSurveyNetworkGuard;
|
|
@@ -591,6 +592,12 @@ var require_survey_network_guard = __commonJS({
|
|
|
591
592
|
const docs = url.searchParams.getAll("query");
|
|
592
593
|
return docs.length > 0 && (typeof body === "string" && body.length > 0 || docs.some((doc) => !graphqlDocumentIsQueryOnly(doc)));
|
|
593
594
|
}
|
|
595
|
+
function queryMethodMayWrite(url, body, graphqlEndpoint) {
|
|
596
|
+
if (graphqlEndpoint)
|
|
597
|
+
return true;
|
|
598
|
+
const operation = /\b(?:mutation|subscription)\b/i;
|
|
599
|
+
return typeof body === "string" && operation.test(body) || [...url.searchParams.values()].some((v) => operation.test(v));
|
|
600
|
+
}
|
|
594
601
|
function isGraphqlGetWrite(url, s, body) {
|
|
595
602
|
return isGraphqlEndpoint(url, s) && graphqlGetMayWrite(url, body);
|
|
596
603
|
}
|
|
@@ -618,6 +625,7 @@ var require_survey_network_guard = __commonJS({
|
|
|
618
625
|
"log-out"
|
|
619
626
|
]);
|
|
620
627
|
exports.AMBIGUOUS_WRITE_VERBS = /* @__PURE__ */ new Set(["archive", "confirm", "disable"]);
|
|
628
|
+
var LABEL_PAGE_NOUNS = /* @__PURE__ */ new Set(["archive"]);
|
|
621
629
|
var RESET_PAGE_WORDS = /* @__PURE__ */ new Set(["reset-password", "password-reset", "reset_password", "password_reset", "resetpassword", "forgot-password"]);
|
|
622
630
|
var isTokenLikeSegment = (seg) => exports.ID_SEGMENT_RE.test(seg) || /^[A-Za-z0-9_-]{20,}$/.test(seg);
|
|
623
631
|
var WRITE_SHAPED_STATIC_EXTENSIONS = [
|
|
@@ -763,6 +771,8 @@ var require_survey_network_guard = __commonJS({
|
|
|
763
771
|
if (oneTimeToken)
|
|
764
772
|
return { reason: "one-time-token" };
|
|
765
773
|
const verb = opts.triggerLabel ? labelVerb(opts.triggerLabel) : void 0;
|
|
774
|
+
if (verb && LABEL_PAGE_NOUNS.has(verb) && last === verb && params.length === 0)
|
|
775
|
+
return null;
|
|
766
776
|
return verb && !opts.ignoreVerbs?.has(verb) ? { reason: "label", verb } : null;
|
|
767
777
|
}
|
|
768
778
|
function writeShapedText(w) {
|
|
@@ -797,9 +807,10 @@ var require_survey_network_guard = __commonJS({
|
|
|
797
807
|
return { action: "allow", rule: readMethod ? "read" : "non-http" };
|
|
798
808
|
const appSite = isAppSite(url.hostname, s.appBaseUrl);
|
|
799
809
|
const graphqlGet = method === "GET" && isGraphqlGetWrite(url, s, req.postData);
|
|
810
|
+
const queryRead = method === "QUERY" && !queryMethodMayWrite(url, req.postData, isGraphqlEndpoint(url, s));
|
|
800
811
|
const inActionWindow = s.lastActionAt > 0 && s.now - s.lastActionAt <= ACTION_NAVIGATION_WINDOW_MS;
|
|
801
812
|
const typedLoad = s.agentLoad === true && req.resourceType === "document";
|
|
802
|
-
const writeShaped = method === "GET" && appSite && !graphqlGet && (inActionWindow || typedLoad) ? writeShapedGet(req.url, {
|
|
813
|
+
const writeShaped = (method === "GET" || queryRead) && appSite && !graphqlGet && (inActionWindow || typedLoad) ? writeShapedGet(req.url, {
|
|
803
814
|
appSites: appSitesOf(s.appBaseUrl),
|
|
804
815
|
resourceType: req.resourceType ?? "",
|
|
805
816
|
// A label says what a click opens: it only judges a page load, never the app's own fetches, and never a typed URL.
|
|
@@ -807,7 +818,7 @@ var require_survey_network_guard = __commonJS({
|
|
|
807
818
|
}) : null;
|
|
808
819
|
if (writeShaped)
|
|
809
820
|
return decideWriteShapedGet(req, s, writeShaped);
|
|
810
|
-
if (readMethod && !graphqlGet)
|
|
821
|
+
if ((readMethod || queryRead) && !graphqlGet)
|
|
811
822
|
return { action: "allow", rule: "read" };
|
|
812
823
|
if (!appSite && ((0, shared_1.isAuthProviderHost)(url.hostname) || isTelemetryHost(url.hostname)))
|
|
813
824
|
return { action: "allow", rule: "third-party" };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
dist_exports,
|
|
3
3
|
init_dist
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-EKY6CN4Y.mjs";
|
|
5
5
|
import {
|
|
6
6
|
__commonJS,
|
|
7
7
|
__require,
|
|
@@ -133,6 +133,7 @@ var require_repo_brief = __commonJS({
|
|
|
133
133
|
exports.briefSectionForFeature = briefSectionForFeature;
|
|
134
134
|
exports.buildBriefRouteAllowlist = buildBriefRouteAllowlist;
|
|
135
135
|
exports.buildBriefDoNotTestRoutes = buildBriefDoNotTestRoutes;
|
|
136
|
+
exports.briefJobRoute = briefJobRoute;
|
|
136
137
|
exports.unopenedBriefJobs = unopenedBriefJobs;
|
|
137
138
|
var shared_1 = (init_dist(), __toCommonJS(dist_exports));
|
|
138
139
|
var model_json_document_js_1 = require_model_json_document();
|
|
@@ -391,14 +392,25 @@ ${scenarios}` : ""
|
|
|
391
392
|
}
|
|
392
393
|
return [...routes];
|
|
393
394
|
}
|
|
394
|
-
|
|
395
|
+
var ENTRY_ROUTE_RE = /(?:^|[\s(])((?:\/|#\/)[^\s?,;()]*)/;
|
|
396
|
+
function briefJobRoute(job) {
|
|
397
|
+
const match = ENTRY_ROUTE_RE.exec(job.entry.trim());
|
|
398
|
+
if (!match)
|
|
399
|
+
return null;
|
|
400
|
+
const route = match[1].replace(/[.:]+$/, "");
|
|
401
|
+
return route === "#/" ? null : route || null;
|
|
402
|
+
}
|
|
403
|
+
function unopenedBriefJobs(brief, coveredText, isOpenedRoute) {
|
|
395
404
|
const haystack = coveredText.toLowerCase();
|
|
396
405
|
return brief.jobs.filter((job) => {
|
|
397
406
|
if (job.doNotTest)
|
|
398
407
|
return false;
|
|
399
408
|
const name = job.name.toLowerCase();
|
|
400
409
|
const entry = job.entry.toLowerCase();
|
|
401
|
-
|
|
410
|
+
if (haystack.includes(name) || haystack.includes(entry))
|
|
411
|
+
return false;
|
|
412
|
+
const route = isOpenedRoute ? briefJobRoute(job) : null;
|
|
413
|
+
return !(route && isOpenedRoute?.(route));
|
|
402
414
|
});
|
|
403
415
|
}
|
|
404
416
|
exports.REPO_BRIEF_PROMPT = [
|