@ai-ecoverse/slicc-browsers 1.19.2 → 1.20.1

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.
@@ -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 skipWhy(vector, row, known, guard) {
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:') && known.has(reason.slice('not-supported:'.length)))
377
- return null;
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 { extensionWorld } from './extension-world.mjs';
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(probe) &&
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 { results, summary: (metadata = {}) => summary({ set, results, ...metadata }) };
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'