@modelprofile.com/browser-runtime 2.1.0 → 2.1.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.
package/changelog.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## 2026-08-13 - 2.1.1
4
+
5
+ ### Fixes
6
+
7
+ - isolate production confinement probe in a disposable tab (confinement)
8
+ - Run loopback, invalid host, and WebRTC confinement checks in an inactive probe tab instead of the active session tab.
9
+ - Close the probe tab during cleanup and fail closed if cleanup leaves session state changed.
10
+ - Preserve both probe and cleanup failures with AggregateError when both occur.
11
+
3
12
  ## 2026-08-12 - 2.1.0
4
13
 
5
14
  ### Features
@@ -3,7 +3,7 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@modelprofile.com/browser-runtime',
6
- version: '2.1.0',
6
+ version: '2.1.1',
7
7
  description: 'Parent-owned, resource-centric Chromium runtime with revisioned attachment fencing, authenticated human and agent control, fail-closed egress, bounded artifacts, and Flex/MCP adapters.'
8
8
  };
9
9
  //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSxtQ0FBbUM7SUFDekMsT0FBTyxFQUFFLE9BQU87SUFDaEIsV0FBVyxFQUFFLDBMQUEwTDtDQUN4TSxDQUFBIn0=
@@ -20,14 +20,25 @@ const listenOnUnsupportedPort = async (allowedPorts, onRequest) => {
20
20
  throw new BrowserRuntimeError('CONFINEMENT_FAILED');
21
21
  };
22
22
  export const runProductionConfinementProbe = async (context) => {
23
+ const initialState = context.session.getState();
24
+ const initialStateJson = JSON.stringify(initialState);
25
+ let probeTabId;
26
+ let probeFailed = false;
27
+ let probeError;
23
28
  let originHits = 0;
24
29
  const fixture = await listenOnUnsupportedPort(new Set(context.proxy.allowedTargetPorts), () => { originHits += 1; });
25
- const closeFixture = async () => new Promise((resolve) => {
26
- fixture.server.close(() => resolve());
30
+ const closeFixture = async () => new Promise((resolve, reject) => {
31
+ fixture.server.close((error) => error ? reject(error) : resolve());
27
32
  });
28
33
  try {
34
+ const probeTab = await context.session.createTab({ activate: false }, { signal: context.signal });
35
+ probeTabId = probeTab.id;
29
36
  const beforeLoopback = context.proxy.getStats();
30
- await context.session.navigate({ url: `http://127.0.0.1:${fixture.port}/browser-runtime-probe`, timeoutMs: 3000 }, { signal: context.signal }).catch(() => undefined);
37
+ await context.session.navigate({
38
+ url: `http://127.0.0.1:${fixture.port}/browser-runtime-probe`,
39
+ tabId: probeTab.id,
40
+ timeoutMs: 3000,
41
+ }, { signal: context.signal }).catch(() => undefined);
31
42
  const afterLoopback = context.proxy.getStats();
32
43
  if (originHits !== 0
33
44
  || afterLoopback.ordinaryRequests <= beforeLoopback.ordinaryRequests
@@ -35,7 +46,11 @@ export const runProductionConfinementProbe = async (context) => {
35
46
  throw new BrowserRuntimeError('CONFINEMENT_FAILED');
36
47
  }
37
48
  const beforeInvalid = context.proxy.getStats();
38
- await context.session.navigate({ url: 'http://browser-runtime-confinement.invalid/', timeoutMs: 3000 }, { signal: context.signal }).catch(() => undefined);
49
+ await context.session.navigate({
50
+ url: 'http://browser-runtime-confinement.invalid/',
51
+ tabId: probeTab.id,
52
+ timeoutMs: 3000,
53
+ }, { signal: context.signal }).catch(() => undefined);
39
54
  const afterInvalid = context.proxy.getStats();
40
55
  if (afterInvalid.ordinaryRequests <= beforeInvalid.ordinaryRequests
41
56
  || afterInvalid.rejectedRequests <= beforeInvalid.rejectedRequests) {
@@ -48,7 +63,7 @@ export const runProductionConfinementProbe = async (context) => {
48
63
  pc.createDataChannel('probe');
49
64
  try { await pc.setLocalDescription(await pc.createOffer()); } catch {}
50
65
  setTimeout(() => { pc.close(); resolve({ candidateEmitted: emitted }); }, 1000);
51
- })`, { timeoutMs: 2500, maxOutputBytes: 1024 }, { signal: context.signal });
66
+ })`, { tabId: probeTab.id, timeoutMs: 2500, maxOutputBytes: 1024 }, { signal: context.signal });
52
67
  if (!result
53
68
  || typeof result !== 'object'
54
69
  || Array.isArray(result)
@@ -56,8 +71,34 @@ export const runProductionConfinementProbe = async (context) => {
56
71
  throw new BrowserRuntimeError('CONFINEMENT_FAILED');
57
72
  }
58
73
  }
74
+ catch (error) {
75
+ probeFailed = true;
76
+ probeError = error instanceof Error ? error : new BrowserRuntimeError('CONFINEMENT_FAILED');
77
+ }
59
78
  finally {
60
- await closeFixture();
79
+ const cleanupErrors = [];
80
+ if (probeTabId) {
81
+ await context.session.closeTab(probeTabId).catch((error) => cleanupErrors.push(error));
82
+ }
83
+ await closeFixture().catch((error) => cleanupErrors.push(error));
84
+ try {
85
+ if (JSON.stringify(context.session.getState()) !== initialStateJson) {
86
+ cleanupErrors.push(new BrowserRuntimeError('CONFINEMENT_FAILED'));
87
+ }
88
+ }
89
+ catch (error) {
90
+ cleanupErrors.push(error);
91
+ }
92
+ if (probeFailed && cleanupErrors.length > 0) {
93
+ throw new AggregateError([probeError, ...cleanupErrors], 'Browser confinement probe and cleanup failed.');
94
+ }
95
+ if (cleanupErrors.length === 1)
96
+ throw cleanupErrors[0];
97
+ if (cleanupErrors.length > 1) {
98
+ throw new AggregateError(cleanupErrors, 'Browser confinement probe cleanup failed.');
99
+ }
61
100
  }
101
+ if (probeFailed)
102
+ throw probeError;
62
103
  };
63
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmluZW1lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9jb25maW5lbWVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUV4QyxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFFbEQsTUFBTSx1QkFBdUIsR0FBRyxLQUFLLEVBQ25DLFlBQWlDLEVBQ2pDLFNBQXFCLEVBQ21DLEVBQUU7SUFDMUQsS0FBSyxJQUFJLE9BQU8sR0FBRyxDQUFDLEVBQUUsT0FBTyxHQUFHLENBQUMsRUFBRSxPQUFPLElBQUksQ0FBQyxFQUFFLENBQUM7UUFDaEQsTUFBTSxNQUFNLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQyxRQUFRLEVBQUUsUUFBUSxFQUFFLEVBQUU7WUFDOUQsU0FBUyxFQUFFLENBQUM7WUFDWixRQUFRLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBQ3hCLFFBQVEsQ0FBQyxHQUFHLEVBQUUsQ0FBQztRQUNqQixDQUFDLENBQUMsQ0FBQztRQUNILE1BQU0sSUFBSSxPQUFPLENBQU8sQ0FBQyxPQUFPLEVBQUUsTUFBTSxFQUFFLEVBQUU7WUFDMUMsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsTUFBTSxDQUFDLENBQUM7WUFDN0IsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUUsV0FBVyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQ3pDLENBQUMsQ0FBQyxDQUFDO1FBQ0gsTUFBTSxPQUFPLEdBQUcsTUFBTSxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ2pDLElBQUksT0FBTyxJQUFJLE9BQU8sT0FBTyxLQUFLLFFBQVEsSUFBSSxDQUFDLFlBQVksQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7WUFDOUUsT0FBTyxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUsT0FB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
104
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmluZW1lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9jb25maW5lbWVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUV4QyxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFFbEQsTUFBTSx1QkFBdUIsR0FBRyxLQUFLLEVBQ25DLFlBQWlDLEVBQ2pDLFNBQXFCLEVBQ21DLEVBQUU7SUFDMUQsS0FBSyxJQUFJLE9BQU8sR0FBRyxDQUFDLEVBQUUsT0FBTyxHQUFHLENBQUMsRUFBRSxPQUFPLElBQUksQ0FBQyxFQUFFLENBQUM7UUFDaEQsTUFBTSxNQUFNLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQyxRQUFRLEVBQUUsUUFBUSxFQUFFLEVBQUU7WUFDOUQsU0FBUyxFQUFFLENBQUM7WUFDWixRQUFRLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBQ3hCLFFBQVEsQ0FBQyxHQUFHLEVBQUUsQ0FBQztRQUNqQixDQUFDLENBQUMsQ0FBQztRQUNILE1BQU0sSUFBSSxPQUFPLENBQU8sQ0FBQyxPQUFPLEVBQUUsTUFBTSxFQUFFLEVBQUU7WUFDMUMsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsTUFBTSxDQUFDLENBQUM7WUFDN0IsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUUsV0FBVyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQ3pDLENBQUMsQ0FBQyxDQUFDO1FBQ0gsTUFBTSxPQUFPLEdBQUcsTUFBTSxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ2pDLElBQUksT0FBTyxJQUFJLE9BQU8sT0FBTyxLQUFLLFFBQVEsSUFBSSxDQUFDLFlBQVksQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7WUFDOUUsT0FBTyxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUsT0FB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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@modelprofile.com/browser-runtime",
3
- "version": "2.1.0",
3
+ "version": "2.1.1",
4
4
  "private": false,
5
5
  "description": "Parent-owned, resource-centric Chromium runtime with revisioned attachment fencing, authenticated human and agent control, fail-closed egress, bounded artifacts, and Flex/MCP adapters.",
6
6
  "main": "dist_ts/index.js",
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@modelprofile.com/browser-runtime',
6
- version: '2.1.0',
6
+ version: '2.1.1',
7
7
  description: 'Parent-owned, resource-centric Chromium runtime with revisioned attachment fencing, authenticated human and agent control, fail-closed egress, bounded artifacts, and Flex/MCP adapters.'
8
8
  }
package/ts/confinement.ts CHANGED
@@ -28,18 +28,32 @@ const listenOnUnsupportedPort = async (
28
28
  export const runProductionConfinementProbe = async (
29
29
  context: IBrowserConfinementProbeContext,
30
30
  ): Promise<void> => {
31
+ const initialState = context.session.getState();
32
+ const initialStateJson = JSON.stringify(initialState);
33
+ let probeTabId: string | undefined;
34
+ let probeFailed = false;
35
+ let probeError: unknown;
31
36
  let originHits = 0;
32
37
  const fixture = await listenOnUnsupportedPort(
33
38
  new Set(context.proxy.allowedTargetPorts),
34
39
  () => { originHits += 1; },
35
40
  );
36
- const closeFixture = async (): Promise<void> => new Promise((resolve) => {
37
- fixture.server.close(() => resolve());
41
+ const closeFixture = async (): Promise<void> => new Promise((resolve, reject) => {
42
+ fixture.server.close((error) => error ? reject(error) : resolve());
38
43
  });
39
44
  try {
45
+ const probeTab = await context.session.createTab(
46
+ { activate: false },
47
+ { signal: context.signal },
48
+ );
49
+ probeTabId = probeTab.id;
40
50
  const beforeLoopback = context.proxy.getStats();
41
51
  await context.session.navigate(
42
- { url: `http://127.0.0.1:${fixture.port}/browser-runtime-probe`, timeoutMs: 3000 },
52
+ {
53
+ url: `http://127.0.0.1:${fixture.port}/browser-runtime-probe`,
54
+ tabId: probeTab.id,
55
+ timeoutMs: 3000,
56
+ },
43
57
  { signal: context.signal },
44
58
  ).catch(() => undefined);
45
59
  const afterLoopback = context.proxy.getStats();
@@ -53,7 +67,11 @@ export const runProductionConfinementProbe = async (
53
67
 
54
68
  const beforeInvalid = context.proxy.getStats();
55
69
  await context.session.navigate(
56
- { url: 'http://browser-runtime-confinement.invalid/', timeoutMs: 3000 },
70
+ {
71
+ url: 'http://browser-runtime-confinement.invalid/',
72
+ tabId: probeTab.id,
73
+ timeoutMs: 3000,
74
+ },
57
75
  { signal: context.signal },
58
76
  ).catch(() => undefined);
59
77
  const afterInvalid = context.proxy.getStats();
@@ -73,7 +91,7 @@ export const runProductionConfinementProbe = async (
73
91
  try { await pc.setLocalDescription(await pc.createOffer()); } catch {}
74
92
  setTimeout(() => { pc.close(); resolve({ candidateEmitted: emitted }); }, 1000);
75
93
  })`,
76
- { timeoutMs: 2500, maxOutputBytes: 1024 },
94
+ { tabId: probeTab.id, timeoutMs: 2500, maxOutputBytes: 1024 },
77
95
  { signal: context.signal },
78
96
  );
79
97
  if (
@@ -84,7 +102,32 @@ export const runProductionConfinementProbe = async (
84
102
  ) {
85
103
  throw new BrowserRuntimeError('CONFINEMENT_FAILED');
86
104
  }
105
+ } catch (error) {
106
+ probeFailed = true;
107
+ probeError = error instanceof Error ? error : new BrowserRuntimeError('CONFINEMENT_FAILED');
87
108
  } finally {
88
- await closeFixture();
109
+ const cleanupErrors: unknown[] = [];
110
+ if (probeTabId) {
111
+ await context.session.closeTab(probeTabId).catch((error) => cleanupErrors.push(error));
112
+ }
113
+ await closeFixture().catch((error) => cleanupErrors.push(error));
114
+ try {
115
+ if (JSON.stringify(context.session.getState()) !== initialStateJson) {
116
+ cleanupErrors.push(new BrowserRuntimeError('CONFINEMENT_FAILED'));
117
+ }
118
+ } catch (error) {
119
+ cleanupErrors.push(error);
120
+ }
121
+ if (probeFailed && cleanupErrors.length > 0) {
122
+ throw new AggregateError(
123
+ [probeError, ...cleanupErrors],
124
+ 'Browser confinement probe and cleanup failed.',
125
+ );
126
+ }
127
+ if (cleanupErrors.length === 1) throw cleanupErrors[0];
128
+ if (cleanupErrors.length > 1) {
129
+ throw new AggregateError(cleanupErrors, 'Browser confinement probe cleanup failed.');
130
+ }
89
131
  }
132
+ if (probeFailed) throw probeError;
90
133
  };