@ai-ecoverse/slicc-browsers 1.19.2 → 1.20.0
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 +3 -0
- package/catalog.json +24 -0
- package/extension-frame.mjs +1048 -0
- package/extension-frames-rules.mjs +18 -0
- package/guard-driver.mjs +19 -7
- package/guard-runner.mjs +28 -4
- package/guard-vectors.json +5680 -12
- package/package.json +6 -4
- package/protected.mjs +7 -1
- package/schema/catalog.schema.json +19 -0
- package/schema/guard-vectors.schema.json +29 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export const whenShownInput = [
|
|
2
|
+
'Input.dispatchKeyEvent',
|
|
3
|
+
'Input.dispatchMouseEvent',
|
|
4
|
+
'Input.dispatchTouchEvent',
|
|
5
|
+
'Input.dispatchDragEvent',
|
|
6
|
+
'Input.emulateTouchFromMouseEvent',
|
|
7
|
+
'Input.insertText',
|
|
8
|
+
'Input.imeSetComposition',
|
|
9
|
+
'Input.synthesizePinchGesture',
|
|
10
|
+
'Input.synthesizeScrollGesture',
|
|
11
|
+
'Input.synthesizeTapGesture',
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
export const shownRefusal =
|
|
15
|
+
"slicc: refused: a browser extension's frame (chrome-extension://) is showing or focused in this tab, such as a password manager's autofill list; close it or reload the tab";
|
|
16
|
+
|
|
17
|
+
export const presentRefusal =
|
|
18
|
+
"slicc: refused: this tab holds a browser extension's frame (chrome-extension://), such as a password manager's autofill list, so it can't be captured whole or streamed; reload the tab to remove it; an active screencast is stopped or its frames are dropped until the frame is gone";
|
package/guard-driver.mjs
CHANGED
|
@@ -364,7 +364,14 @@ const canTrustedEmulation = (vector) =>
|
|
|
364
364
|
trustedEmulationMethods.has(step.cdp)
|
|
365
365
|
);
|
|
366
366
|
|
|
367
|
-
function
|
|
367
|
+
function declaredCapabilities(value) {
|
|
368
|
+
if (Array.isArray(value)) return value.filter((cap) => typeof cap === 'string' && cap !== '');
|
|
369
|
+
if (value && typeof value === 'object')
|
|
370
|
+
return Object.keys(value).filter((key) => value[key] === true);
|
|
371
|
+
return [];
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
function skipWhy(vector, row, known, guard, declared) {
|
|
368
375
|
const { reason } = row;
|
|
369
376
|
if (typeof reason !== 'string' || reason === '') return 'skip without a reason';
|
|
370
377
|
if (reason === skipReason(vector, row.target, guard)) return null;
|
|
@@ -373,13 +380,18 @@ function skipWhy(vector, row, known, guard) {
|
|
|
373
380
|
return canTrustedEmulation(vector)
|
|
374
381
|
? null
|
|
375
382
|
: `skip with a reason the runner never gives: ${reason}`;
|
|
376
|
-
if (reason.startsWith('not-supported:')
|
|
377
|
-
|
|
383
|
+
if (reason.startsWith('not-supported:')) {
|
|
384
|
+
const cap = reason.slice('not-supported:'.length);
|
|
385
|
+
if (cap === 'extensionFrame' && declared.includes(cap))
|
|
386
|
+
return `skip with not-supported:${cap} while the run declared ${cap}`;
|
|
387
|
+
if (known.has(cap)) return null;
|
|
388
|
+
}
|
|
378
389
|
return `skip with a reason the runner never gives: ${reason}`;
|
|
379
390
|
}
|
|
380
391
|
|
|
381
|
-
function forgeries(set, results, guard) {
|
|
392
|
+
function forgeries(set, results, guard, capabilitiesList) {
|
|
382
393
|
const vectors = new Map(set.vectors.map((v) => [v.id, v]));
|
|
394
|
+
const declared = declaredCapabilities(capabilitiesList);
|
|
383
395
|
const known = new Set([
|
|
384
396
|
'browserSession',
|
|
385
397
|
'unguarded-observer',
|
|
@@ -392,7 +404,7 @@ function forgeries(set, results, guard) {
|
|
|
392
404
|
const why = [];
|
|
393
405
|
if (legs.includes('not-run') && vector?.kind !== 'text')
|
|
394
406
|
why.push('not-run on a vector that is not kind text');
|
|
395
|
-
if (legs.includes('skip')) why.push(skipWhy(vector, row, known, guard));
|
|
407
|
+
if (legs.includes('skip')) why.push(skipWhy(vector, row, known, guard, declared));
|
|
396
408
|
const found = why.filter(Boolean);
|
|
397
409
|
if (!found.length) return [];
|
|
398
410
|
const { id, target, variant, transport } = row;
|
|
@@ -400,7 +412,7 @@ function forgeries(set, results, guard) {
|
|
|
400
412
|
});
|
|
401
413
|
}
|
|
402
414
|
|
|
403
|
-
export function summary({ guard, sha, set, results }) {
|
|
415
|
+
export function summary({ guard, sha, set, results, capabilities: runCapabilities }) {
|
|
404
416
|
const uniq = (k) => [...new Set(results.map((r) => r[k]))].sort();
|
|
405
417
|
const variants = [...new Set([...Object.keys(set.variants ?? {}), ...uniq('variant')])].sort();
|
|
406
418
|
const has = new Set(results.map((r) => q([r.id, r.target, r.variant, r.transport])));
|
|
@@ -410,7 +422,7 @@ export function summary({ guard, sha, set, results }) {
|
|
|
410
422
|
.flatMap((row) => variants.map((variant) => ({ ...row, variant })))
|
|
411
423
|
.flatMap((row) => uniq('transport').map((transport) => ({ ...row, transport })))
|
|
412
424
|
.filter((r) => !has.has(q([r.id, r.target, r.variant, r.transport])));
|
|
413
|
-
const forged = forgeries(set, results, guard);
|
|
425
|
+
const forged = forgeries(set, results, guard, runCapabilities);
|
|
414
426
|
const pass =
|
|
415
427
|
results.length > 0 && missing.length === 0 && forged.length === 0 && results.every(passed);
|
|
416
428
|
const name = `@ai-ecoverse/slicc-browsers@${set.setVersion}`;
|
package/guard-runner.mjs
CHANGED
|
@@ -3,7 +3,8 @@ import { fixtureClient, prepareFixture } from './fixture-client.mjs';
|
|
|
3
3
|
export { fixtureClient };
|
|
4
4
|
|
|
5
5
|
import { bfcacheRestore } from './bfcache-restore.mjs';
|
|
6
|
-
import {
|
|
6
|
+
import { extensionFrame } from './extension-frame.mjs';
|
|
7
|
+
import { DEFAULT_EXTENSION_WORLD_ID, extensionWorld } from './extension-world.mjs';
|
|
7
8
|
import { frameRead } from './frame-read.mjs';
|
|
8
9
|
import {
|
|
9
10
|
beacon,
|
|
@@ -701,13 +702,16 @@ class Execution {
|
|
|
701
702
|
'unparseable',
|
|
702
703
|
'errorPage',
|
|
703
704
|
'extensionWorld',
|
|
705
|
+
'extensionFrame',
|
|
704
706
|
'frameRead',
|
|
705
707
|
'bfcacheRestore',
|
|
706
708
|
].find((key) => step[key]);
|
|
707
709
|
if (probe && !out.ok) this.errors.push(`${probe}: ${out.error?.message ?? 'probe failed'}`);
|
|
708
710
|
if (step.client && !out.ok) this.errors.push(`client exit: ${out.error.message}`);
|
|
709
711
|
if (
|
|
710
|
-
['errorPage', 'redirectSecret', 'frameRead', 'bfcacheRestore'].includes(
|
|
712
|
+
['errorPage', 'redirectSecret', 'extensionFrame', 'frameRead', 'bfcacheRestore'].includes(
|
|
713
|
+
probe
|
|
714
|
+
) &&
|
|
711
715
|
out.ok &&
|
|
712
716
|
out.result?.incomplete
|
|
713
717
|
)
|
|
@@ -901,6 +905,21 @@ class Execution {
|
|
|
901
905
|
extensionId: this.options.extensionWorldId,
|
|
902
906
|
})
|
|
903
907
|
);
|
|
908
|
+
if (step.extensionFrame)
|
|
909
|
+
return outcome(
|
|
910
|
+
extensionFrame({
|
|
911
|
+
client: this.client,
|
|
912
|
+
reader: this.reader,
|
|
913
|
+
session,
|
|
914
|
+
targetId: this.pageTarget,
|
|
915
|
+
mode: step.extensionFrame,
|
|
916
|
+
origin: this.vars.ordinary,
|
|
917
|
+
frameMs: this.bound(1000),
|
|
918
|
+
extensionId: this.options.extensionFrameId ?? DEFAULT_EXTENSION_WORLD_ID,
|
|
919
|
+
side: this.side,
|
|
920
|
+
capabilities: this.options.capabilities,
|
|
921
|
+
})
|
|
922
|
+
);
|
|
904
923
|
if (step.guess) return this.guess(step.guess, session);
|
|
905
924
|
if (step.cdp) return this.cdp(step, session, phase);
|
|
906
925
|
if (step.page) return this.page(step, session, phase);
|
|
@@ -2063,10 +2082,14 @@ async function runAll(set, options, flights) {
|
|
|
2063
2082
|
row.transport = transport;
|
|
2064
2083
|
opts.log?.(row);
|
|
2065
2084
|
}
|
|
2066
|
-
return {
|
|
2085
|
+
return {
|
|
2086
|
+
results,
|
|
2087
|
+
summary: (metadata = {}) =>
|
|
2088
|
+
summary({ set, results, ...metadata, capabilities: opts.capabilities }),
|
|
2089
|
+
};
|
|
2067
2090
|
}
|
|
2068
2091
|
|
|
2069
|
-
export function summary({ set, results, guard = 'reference', sha = 'unknown' }) {
|
|
2092
|
+
export function summary({ set, results, guard = 'reference', sha = 'unknown', capabilities }) {
|
|
2070
2093
|
const value = report({
|
|
2071
2094
|
set: {
|
|
2072
2095
|
...set,
|
|
@@ -2077,6 +2100,7 @@ export function summary({ set, results, guard = 'reference', sha = 'unknown' })
|
|
|
2077
2100
|
results,
|
|
2078
2101
|
guard,
|
|
2079
2102
|
sha,
|
|
2103
|
+
capabilities,
|
|
2080
2104
|
});
|
|
2081
2105
|
const observerSkipped = results.filter(
|
|
2082
2106
|
(row) => row.reason === 'not-supported:unguarded-observer'
|