@ai-ecoverse/slicc-browsers 1.8.4 → 1.8.5

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 CHANGED
@@ -94,7 +94,7 @@ Every feature builds for `wasm32-wasip1`.
94
94
  - `discardExceptions`: where the site pattern and the extra origins' hosts go, as a `list` of strings or as a `chrome-time-map`, a map from site to the time it was added (microseconds since 1601-01-01 UTC, as a decimal string);
95
95
  - `cleanExit`: values that mark the last exit clean;
96
96
  - `form` says where a key comes from: `six` (SLICC six's keys) or `chrome-154` (what Chrome 154 reads).
97
- - `protectedOrigins`: what browser control must never reach, see [Protected origins](#protected-origins). `domains` (`sliccy.ai`), `hosts` (`vault.sliccy.ai`), `schemes` (`https`, `http`), `innerSchemes` (`blob`, `filesystem`, `view-source`), `anySchemes` (`devtools`), `protectedSchemes` (`chrome`, `chrome-untrusted`, `chrome-extension`, `devtools`, `edge`, `brave`, `opera`, `vivaldi`, `arc`, `file`) with `schemeExceptions` (`chrome://newtab`, `chrome://new-tab-page`, `chrome-untrusted://new-tab-page`, `edge://newtab`, `brave://newtab`, `opera://startpage`), `aboutScheme` (`chrome`), `targetTypes` (`browser_ui`), `inheriting` (`about:blank`, `about:srcdoc`), and `refusal`, the text of a refusal.
97
+ - `protectedOrigins`: what browser control must never reach, see [Protected origins](#protected-origins). `domains` (`sliccy.ai`), `hosts` (`vault.sliccy.ai`), `schemes` (`https`, `http`), `innerSchemes` (`blob`, `filesystem`, `view-source`), `anySchemes` (`devtools`), `protectedSchemes` (`chrome`, `chrome-untrusted`, `chrome-search`, `chrome-native`, `chrome-distiller`, `chrome-experimental-site-token-provider`, `isolated-app`, `externalfile`, `content`, `chrome-extension`, `devtools`, `edge`, `brave`, `opera`, `vivaldi`, `arc`, `file`) with `schemeExceptions` (`chrome://newtab`, `chrome://new-tab-page`, `chrome-untrusted://new-tab-page`, `edge://newtab`, `brave://newtab`, `opera://startpage`), `aboutScheme` (`chrome`), `targetTypes` (`browser_ui`), `inheriting` (`about:blank`, `about:srcdoc`), and `refusal`, the text of a refusal.
98
98
  - `profiles`: SLICC profiles live in `<config dir>/<root>/<name>`, and a snap's in `~/snap/<snap>/common/<snapRoot>/<name>`. `legacyRoot` is the old root, never scanned; on macOS's case-insensitive volume it is SLICC six's root too. `sixProfilePattern` matches six's profile names, case-insensitively. `namePattern` is a valid profile name. `six` describes SLICC six's Chrome profiles (see [SLICC six's profiles](#slicc-sixs-profiles)):
99
99
  - `roots`: six's profile root per OS (`macos`, `linux`, `windows`), a `base` location followed by the `path` segments. The base is its `env` when that is set and not empty (any value, as six takes it), else `home` under the home dir.
100
100
  - `defaultName` (`browser-coding-agent-chrome`), `defaultPort` (5710) and `portSuffix` (`-{port}`): six's profile for its serve port `<port>` is `<root>/<defaultName>`, with `portSuffix` added for any port other than `defaultPort`.
@@ -120,8 +120,35 @@ Browser control must never navigate to, open or attach to a target on seven's ow
120
120
 
121
121
  This is wider than the rule for finding seven (`seven.originHostPattern`, which leaves out the `excludedLabels` and `excludedLabelPrefixes`—`www`, `vault`, `vault-preview`, `get`, `mcpcat`, `echo`, and any `vault-*` prefix). Every `sliccy.ai` host shares the `sliccy.ai` cookies, and cookies ignore the port and, without `Secure`, the scheme. SLICC six lives on `www.sliccy.ai` and the apex, and its cookies matter. `*.kernel.localhost` is not protected: each port is its own origin, and the agent's own servers live there. An extra origin is matched exactly, so `http://127.0.0.1:5710` doesn't protect `http://127.0.0.1:5711`.
122
122
 
123
+ **Chromium scheme audit.** Checked [content scheme registration](https://github.com/chromium/chromium/blob/d0bfaae35fa745d9dee525dc4ff6617b1551dbe7/content/common/url_schemes.cc) and [Chrome additional schemes](https://github.com/chromium/chromium/blob/d0bfaae35fa745d9dee525dc4ff6617b1551dbe7/chrome/common/chrome_content_client.cc), including platform-specific registrations:
124
+
125
+ | Scheme | Decision and reason |
126
+ | --- | --- |
127
+ | `chrome` | Protected: browser WebUI, with only the catalog's exact new-tab host exceptions. |
128
+ | `chrome-untrusted` | Protected: browser-owned isolated UI resources, except the exact `new-tab-page` host. |
129
+ | `chrome-search` | Protected: Instant/search-provider UI and profile resources, including `local-ntp`, `most-visited` and `remote-ntp`; hiding targets is not refusal. |
130
+ | `chrome-native` | Protected: browser UI rendered by platform-native widgets instead of HTML. |
131
+ | `chrome-distiller` | Protected: browser-generated reader-mode documents, which may contain content distilled from a protected document. |
132
+ | `chrome-error` | Not scheme-wide protected: generic network-error documents hold no protected document content; ordinary errors must remain readable and recoverable. |
133
+ | `isolated-app` | Protected: installed isolated web apps have app-specific storage and privileged capabilities outside ordinary web origins. |
134
+ | `devtools` | Protected already: a DevTools front end can inspect a protected target. |
135
+ | `chrome-extension` | Protected already: extension documents and workers can contain credentials and browser privileges. |
136
+ | `chrome-experimental-site-token-provider` | Protected: an internal data source issues site-specific tokens. |
137
+ | `externalfile` | Protected: ChromeOS local/external file access must not bypass the `file` fence. |
138
+ | `file` | Protected already: local files must not bypass the agent's file-system fence. |
139
+ | `content` | Protected: Android local content-provider access must not bypass the `file` fence. |
140
+ | `android-app` | Not scheme-wide protected: Android app/referrer identity, not a browser UI document; extra-origin rules still apply. |
141
+ | `googlechrome` | Not scheme-wide protected: an external launch alias, not registered as a privileged document scheme by these entry points. |
142
+ | `view-source`, `blob`, `filesystem` | Not blindly scheme-wide protected: existing recursive inner-origin rules protect what they wrap. |
143
+ | `about` | Not blindly scheme-wide protected: existing Chromium alias rewriting protects UI while retaining inheriting blank/srcdoc URLs. |
144
+ | `http`, `https`, `data`, `javascript`, `ws`, `wss`, `mailto`, `webcal` | Not scheme-wide protected: ordinary web, inline content, transport or external handlers, not privileged browser UI. |
145
+
146
+ A guard must refuse navigation, creation and attach on protected schemes, including protected frames of an otherwise ordinary tab, rather than merely hiding them from discovery. `chrome-error` is deliberately not a protected scheme: ordinary DNS, connection and certificate failures produce that same generic document, so scheme-wide refusal would prevent reattaching to an ordinary error tab. Error pages hold no secrets from the failed document. This does not permit opening or attaching to a protected origin: guards still fail protected navigations before commit and enforce protected-target provenance; C1–C5 observer-only `unreachableUrl`, history and network block evidence is unchanged.
147
+
123
148
  **New-tab checks (1.8.2).** In fresh default profiles on macOS, Chrome for Testing 156.0.8078.4 (Playwright build 1248) and Chrome 155.0.8059.82 commit `chrome://newtab/` to `chrome://new-tab-page/` and embed `chrome-untrusted://new-tab-page/one-google-bar?paramsencoded=` as an out-of-process frame. Direct `chrome://new-tab-page/` also commits as itself. Edge 155.0.4283.60 commits `edge://newtab/` to `https://ntp.msn.com/edge/ntp` with an `about:blank` child and no internal-scheme child observed; directly opening `edge://ntp/` returns `ERR_INVALID_URL`. These observations are for fresh default profiles, not every browser configuration. Brave, Opera and Vivaldi were not installed locally, and this repository's CI installs only Chromium, so their redirects and internal frames were not verified and no additional exceptions are inferred. Incognito Chrome and Edge new tabs omit the ordinary new tab's frame tree; the reachability vector therefore uses the default context.
124
149
 
150
+ **Privileged-scheme follow-up checks.** With the expanded catalog, fresh default-profile Chrome for Testing 156.0.8078.4 on macOS again committed both NTP entry points to `chrome://new-tab-page/`, with an `about:blank` background child and only `chrome-untrusted://new-tab-page/one-google-bar?paramsencoded=` as its internal-scheme OOPIF. `C8.newtab` passed both attach and ordinary-navigation legs; no `chrome-search` exceptions are added or inferred for other profile/search-provider configurations. Direct `Page.navigate` to `chrome-search://most-visited/` returned `net::ERR_INVALID_URL` and committed `chrome-error://chromewebdata/` with that exact `unreachableUrl`, confirming why `C8.chrome-search` distinguishes a browser response from a guard refusal rather than requiring a successful search-document commit. The catalog-adopting emulator passed every C8 protection row; plain clients failed them, and removing only `chrome-search` from the adopted catalog failed the new row. C1.href, C2.302, C3.popup-self-nav, all tested C4 iframe process layouts and C5.document passed their guarded and control legs with the expanded schemes; plain clients passed controls and failed protection expectations. Those HTTP fixtures deliberately protect only the seven host, leaving their same-site control host ordinary, while adopting every internal-scheme rule unchanged.
151
+
125
152
  **The vault.** `vault.sliccy.ai` is in `hosts` by name, and vault branch previews (`vault-preview.sliccy.ai`, `vault-*.sliccy.ai`) are covered by the `sliccy.ai` domain rule. `sliccy.ai` already covers them all, but vault must stay protected even if `domains` ever changes: the vault must never be a CDP target for agent tools. The one exception is slicc-cli's own pairing attach for the vault, which is the CLI's own connection and not browser control handed to the agent.
126
153
 
127
154
  **Targets.** A target whose `TargetInfo.type` is one of `targetTypes` (`browser_ui`, Chrome's own UI such as `chrome://omnibox-popup.top-chrome/`) is always protected, whatever its URL. Otherwise a target's effective origin is its URL's (`TargetInfo.url`), except when the URL inherits the origin of whoever made the document: the empty URL, and `inheriting` with any query or fragment. Such a target is protected when it was protected before this URL (a seven tab that went to `about:blank` keeps seven's origin), or when its opener (`openerId`, else `openerFrameId`) is protected or unknown, for an opener closed before the program saw it. The URL, `openerFrameId` and `browserContextId` alone can't tell: a blank popup that seven opens has seven's origin and the URL `about:blank`. A program that holds a session to the target also has the document's real origin: the main frame's `securityOrigin` in `Page.frameNavigated`, and the default context's `origin` in `Runtime.executionContextCreated`. When one of those is protected, the target is protected too, until a URL with an origin of its own replaces it.
@@ -143,16 +170,20 @@ Every CDP guard runs the vectors in `guard-vectors.json` (schema `schema/guard-v
143
170
  - slicc-cdp's `test/integration/guard-vectors.json` at `4907a45`, where its `E1`, `E2`, `E3`, `E5` and `B2` are renamed `E1.onload`, `E2.binding`, `E3.bypass-csp`, `E5.console` and `B2.headers`;
144
171
  - the cert lane's E and B rows;
145
172
  - `C5.continue-request` and `C5.continue-response`, added next to `C5.document`;
146
- - the `C8` rows for privileged pages: `C8.navigate` (a page navigates to `chrome://settings`, `chrome://password-manager`, an extension page or `file:///`; refused), `C8.view-source` (the same through `view-source:`; refused), `C8.create` (`Target.createTarget` straight on those pages; refused), `C8.browser-ui-listed` (`Target.getTargets` lists no `browser_ui` target) and `C8.browser-ui-attach` (`Target.attachToTarget` by a `browser_ui` target's id; refused). All four have an unguarded control, since the guard refuses them only on the privileged target. Two cases aren't rows, because Chrome itself blocks them, so an unguarded client can't tell a guard from none: a page's `window.open('chrome://settings')`, and an `about:` alias such as `about:settings`, which `Page.navigate` and `Target.createTarget` both turn into `about:blank#blocked`. The `about:` aliases are in `protected.json` instead.
173
+ - the `C8` rows for privileged pages: `C8.navigate` (a page navigates to `chrome://settings`, `chrome://password-manager`, an extension page or `file:///`; refused), `C8.view-source` (the same through `view-source:`; refused), `C8.create` (`Target.createTarget` straight on those pages; refused), `C8.browser-ui-listed` (`Target.getTargets` lists no `browser_ui` target) and `C8.browser-ui-attach` (`Target.attachToTarget` by a `browser_ui` target's id; refused). All five have an unguarded control, since the guard refuses them only on the privileged target. Two cases aren't rows, because Chrome itself blocks them, so an unguarded client can't tell a guard from none: a page's `window.open('chrome://settings')`, and an `about:` alias such as `about:settings`, which `Page.navigate` and `Target.createTarget` both turn into `about:blank#blocked`. The `about:` aliases are in `protected.json` instead.
174
+
175
+ `C8.chrome-search` requests `chrome-search://most-visited/` through `Page.navigate` and requires an explicit guard refusal. Its unguarded control requires a CDP response, not a successful document commit: Chrome can answer with `errorText` when that internal data source is unavailable outside an Instant process. Browser-side load failure is not a guard refusal, and merely hiding the target must fail this row.
176
+
177
+ The `C8.newtab` reachability control attaches through the guard to a settled ordinary new tab, including its internal frames, then navigates that same tab to an ordinary document. Both legs must succeed, including without a guard. It requires `chromeUrlsAttach`, so an extension transport reports it as `skip` with `not-supported:chromeUrlsAttach`. The C8 protection rows expect a refusal on the guarded leg and run their controls unguarded, so they don't require it and still run on extension transports. It uses the default browser context, since an incognito new tab omits the ordinary new tab's internal frames. It covers `chrome://newtab/` and directly opened `chrome://new-tab-page/`.
147
178
 
148
- The `C8.newtab` reachability control attaches through the guard to a settled ordinary new tab, including its internal frames, then navigates that same tab to an ordinary document. Both legs must succeed, including without a guard. It requires `chromeUrlsAttach`, so an extension transport reports it as `skip` with `not-supported:chromeUrlsAttach`. The other C8 rows expect a refusal on the guarded leg and run their controls unguarded, so they don't require it and still run on extension transports. It uses the default browser context, since an incognito new tab omits the ordinary new tab's internal frames. It covers `chrome://newtab/` and directly opened `chrome://new-tab-page/`.
179
+ `C8.network-error` and `C8.iframe-error` are ordinary-error reachability controls: request the configured `network-error` URL (default `http://nonexistent.invalid/`) directly or in an ordinary iframe, observe a failed Document request, reattach to the settled tab, evaluate and snapshot its document, then navigate the same tab to an ordinary document. Both control and guarded legs must pass. The failing URL is unchanged on the control, rather than replaced with a healthy origin, and the rows require `browserSession` but not `chromeUrlsAttach`. With Chrome for Testing 156.0.8078.4, scheme-wide `chrome-error` protection made the direct-error row fail both legs because reattachment was refused; removing it passed both rows, with readable DOM and successful recovery. The old emulator still allowed the cross-process iframe parent because the iframe TargetInfo kept the failing HTTP URL, but that layout-specific behavior is not grounds for protecting the error scheme. Plain-client controls and reachability legs also passed both rows.
149
180
 
150
181
  A client may register `Fetch.enable` patterns naming a protected origin in either of two conformant ways: the guard allows registration but never pauses or forwards protected requests to the client and refuses continue, fulfil or fail calls for request ids it did not hand out; or the guard refuses registration with its declared refusal text. Setup calls explicitly naming a protected placeholder are refusable with `refusal.onlyProtected: true`, and interception-dependent observations depend on that refusal. Wildcard and ordinary-only patterns do not receive this exemption. The ordinary-origin control still runs through the guard and must succeed.
151
182
 
152
183
  **Top level.**
153
184
  - `schemaVersion` (1): guards pin it.
154
185
  - `setVersion`: the package version. The release flow stamps it into the npm package and the crate (`scripts/set-crate-version.mjs`). In git, and so in the Go module, it reads `0.0.0`; Go code gets the version from the module.
155
- - `targets`: the names a runner maps to a scheme, host and port: `seven`, `vault`, `vault-x` (a vault branch preview), `apex`, `own` (the client page's origin, `{client}`), `ordinary`, `ordinary-same-site`, `chrome-newtab`, `chrome-new-tab-page`, `chrome-settings`, `chrome-passwords`, `chrome-extension-page` and `file-root`. Each has a `description` and, for the protected ones, a default `host`. `chrome-newtab` (`chrome://newtab/`), `chrome-new-tab-page` (`chrome://new-tab-page/`), `chrome-settings` (`chrome://settings/`), `chrome-passwords` (`chrome://password-manager/`), `chrome-extension-page` (a page of Chrome's built-in PDF viewer extension) and `file-root` (`file:///`) carry a `url`, which the runner uses unless `targets` maps the name to something else. No other URL in the file is one a runner must use.
186
+ - `targets`: the names a runner maps to a scheme, host and port: `seven`, `vault`, `vault-x` (a vault branch preview), `apex`, `own` (the client page's origin, `{client}`), `ordinary`, `ordinary-same-site`, `chrome-newtab`, `chrome-new-tab-page`, `chrome-settings`, `chrome-passwords`, `chrome-search`, `network-error`, `chrome-extension-page` and `file-root`. Each has a `description` and, for the protected ones, a default `host`. `chrome-newtab` (`chrome://newtab/`), `chrome-new-tab-page` (`chrome://new-tab-page/`), `chrome-settings` (`chrome://settings/`), `chrome-passwords` (`chrome://password-manager/`), `chrome-search` (`chrome-search://most-visited/`), `network-error` (`http://nonexistent.invalid/`), `chrome-extension-page` (a page of Chrome's built-in PDF viewer extension) and `file-root` (`file:///`) carry a `url`, which the runner uses unless `targets` maps the name to something else. No other URL in the file is one a runner must use.
156
187
  - `variants`: the detach variants in ms. `prompt` and `lagging` are documented; a runner may add others, such as `lagging-8s`, and reports the name it ran.
157
188
  - `capabilities`: what a transport may lack. `autoAttach` covers `Target.setAutoAttach`, `children` steps and child sessions; `browserSession` covers calls on the browser session; `browserContexts` covers `Target.createBrowserContext` and `Target.disposeBrowserContext`; `chromeUrlsAttach` means the transport can attach to and drive `chrome://` pages. CDP over a DevTools port can; `chrome.debugger` can't, since Chrome refuses it every `chrome://` page, even with `--extensions-on-chrome-urls`.
158
189
  - `placeholders`: every `{name}` used in the vectors, with what it stands for. `{client}` is the client page's origin, which the runner maps.
@@ -162,7 +193,7 @@ A client may register `Fetch.enable` patterns naming a protected origin in eithe
162
193
  - `kind`: `cdp` (runnable steps) or `text` (rows in words, which runners report as `not-run`, never `pass`);
163
194
  - `scope`: `any`, or the one guard the vector is for;
164
195
  - `setup` and `trigger`, both lists of steps;
165
- - `targets`: the protected targets it runs against;
196
+ - `targets`: the protected or reachability targets it runs against;
166
197
  - `requires?`: the capabilities it needs, the union of its steps' and observations' `requires`. A runner whose transport lacks one reports the vector as `skip` with the reason `not-supported:<capability>`. A row with a `page-or-browser` cookie step that would carry a `browserContextId` reports `not-supported:browserSession` without a browser session, because that parameter is only allowed on the browser target;
167
198
  - `observe?`: each observed name, as `{ "means", "dependsOn"?, "requires"?, "eitherWhen"? }`. `dependsOn` lists the refusals the observation depends on (see Refusals). `eitherWhen` is a check: when it holds on the guarded leg, that observation's expectation becomes `"either"` there (see Design-dependent outcomes);
168
199
  - `live`: the liveness check;
@@ -288,7 +319,7 @@ extension on `chrome.debugger` leaves it out, so `C8.newtab` is skipped with
288
319
  `not-supported:chromeUrlsAttach`. `capabilities.scope` selects owner-specific rows.
289
320
 
290
321
  Map `ordinary`, `ordinary-same-site`, `seven`, `vault`, `vault-x`, `apex`, `own`
291
- and `client` to origins. `chrome-newtab`, `chrome-new-tab-page`, `chrome-settings`, `chrome-passwords`, `chrome-extension-page` and `file-root` default to their `url`.
322
+ and `client` to origins. `chrome-newtab`, `chrome-new-tab-page`, `chrome-settings`, `chrome-passwords`, `chrome-search`, `network-error`, `chrome-extension-page` and `file-root` default to their `url`.
292
323
  `{browserUi}` is the id of one of Chrome's own `browser_ui` targets, which the runner looks up through
293
324
  its unguarded observer (or the client) before the row; a row that uses it fails when there is none.
294
325
  A vector with `"defaultContext": true` runs in the browser's default context even with the
@@ -540,7 +571,7 @@ for case in corpus().cases {
540
571
  Go 1.26, Rust stable with `wasm32-wasip1`, Node ≥ 24.
541
572
  - `npm run corpus` regenerates `corpus.json` from `corpus/`; the pre-commit hook and CI fail when it's stale.
542
573
  - `npm run validate` checks `catalog.json`, `corpus.json`, `protected.json` and `guard-vectors.json` against the schemas, runs the protected-origin vectors through `protected.mjs`, and checks what a schema can't say: unique ids, bundle ids and names, known Windows roots, rising tiers, compiling patterns, known tokens, tier order, `sevenOpen`, `tabs` (which holds no entry of `sevenTabs`), `six` and `auto` in each `expected.json`, and no port from 9222 to 9229.
543
- - Every gate prints one verdict line when it passes: `validate: PASS …`, `corpus: PASS <n> cases` (`node scripts/corpus.mjs --check`), `major-guard: PASS v<version> fits <module>`, and `guard-sweep: PASS 11 targets` (`npm run test:guard-sweep`). CI runs each through `scripts/gate.mjs --expect <regex> -- <command>`, which fails when the command exits non-zero or prints no matching line, so a silent or early exit never reads as a pass. `gate.mjs --expect <regex> --in <file>` checks a log instead; the release job uses it on semantic-release's log for the major-guard line. `npm run test:gates` tests the gates, including runs through a symlinked checkout and a symlinked script.
574
+ - Every gate prints one verdict line when it passes: `validate: PASS …`, `corpus: PASS <n> cases` (`node scripts/corpus.mjs --check`), `major-guard: PASS v<version> fits <module>`, and `guard-sweep: PASS 13 targets` (`npm run test:guard-sweep`). CI runs each through `scripts/gate.mjs --expect <regex> -- <command>`, which fails when the command exits non-zero or prints no matching line, so a silent or early exit never reads as a pass. `gate.mjs --expect <regex> --in <file>` checks a log instead; the release job uses it on semantic-release's log for the major-guard line. `npm run test:gates` tests the gates, including runs through a symlinked checkout and a symlinked script.
544
575
  - `npm run lint`: the slicc lint tools (Biome, no comments, no unit tests in git, `AGENTS.md`), `gofmt`, `go mod tidy -diff`, `go vet`, golangci-lint, `cargo fmt --check` and clippy.
545
576
  - `npm test`: `validate`, the Go tests in `test/integration/`, and `cargo test --all-features`.
546
577
  - `npm run build`: the Go module, the crate (also for `wasm32-wasip1`), and `npm pack --dry-run`.
package/catalog.json CHANGED
@@ -711,6 +711,13 @@
711
711
  "protectedSchemes": [
712
712
  "chrome",
713
713
  "chrome-untrusted",
714
+ "chrome-search",
715
+ "chrome-native",
716
+ "chrome-distiller",
717
+ "chrome-experimental-site-token-provider",
718
+ "isolated-app",
719
+ "externalfile",
720
+ "content",
714
721
  "chrome-extension",
715
722
  "devtools",
716
723
  "edge",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "setVersion": "1.8.4",
3
+ "setVersion": "1.8.5",
4
4
  "sources": [
5
5
  {
6
6
  "repo": "ai-ecoverse/slicc-cli",
@@ -61,6 +61,14 @@
61
61
  "url": "chrome://settings/",
62
62
  "description": "Chrome's settings page, a privileged chrome: page"
63
63
  },
64
+ "network-error": {
65
+ "url": "http://nonexistent.invalid/",
66
+ "description": "an ordinary URL with a failing DNS lookup, used on both reachability legs"
67
+ },
68
+ "chrome-search": {
69
+ "url": "chrome-search://most-visited/",
70
+ "description": "Chrome's internal search UI, including NTP search-provider resources"
71
+ },
64
72
  "chrome-passwords": {
65
73
  "url": "chrome://password-manager/",
66
74
  "description": "Chrome's password manager, a privileged chrome: page"
@@ -94,6 +102,7 @@
94
102
  "own": "the own target's origin, which is {client}",
95
103
  "ordinary": "the ordinary origin the run starts from",
96
104
  "ordinary-same-site": "the ordinary-same-site origin",
105
+ "network-error": "the ordinary failing-network URL, unchanged on the control",
97
106
  "client": "the client page's origin, which the runner maps",
98
107
  "cross": "another ordinary origin, cross-site with {ordinary}",
99
108
  "plain": "an ordinary destination origin, the control target",
@@ -12451,6 +12460,376 @@
12451
12460
  "observer": "unguarded"
12452
12461
  }
12453
12462
  },
12463
+ {
12464
+ "id": "C8.network-error",
12465
+ "family": "C",
12466
+ "kind": "cdp",
12467
+ "scope": "any",
12468
+ "setup": [
12469
+ {
12470
+ "text": "an ordinary tab hits a network error; the error document must remain readable, attachable and navigable"
12471
+ },
12472
+ {
12473
+ "page": "tab",
12474
+ "url": "{ordinary}/doc?tag={tag}"
12475
+ },
12476
+ {
12477
+ "cdp": "Page.enable"
12478
+ },
12479
+ {
12480
+ "cdp": "Network.enable"
12481
+ }
12482
+ ],
12483
+ "trigger": [
12484
+ {
12485
+ "page": "navigate",
12486
+ "url": "{network-error}"
12487
+ },
12488
+ {
12489
+ "settle": {
12490
+ "ms": 2500
12491
+ }
12492
+ },
12493
+ {
12494
+ "cdp": "Target.attachToTarget",
12495
+ "params": {
12496
+ "targetId": "{pageTarget}",
12497
+ "flatten": true
12498
+ },
12499
+ "session": "browser",
12500
+ "as": "attach",
12501
+ "requires": ["browserSession"]
12502
+ },
12503
+ {
12504
+ "page": "eval",
12505
+ "expression": "Boolean(document.body)",
12506
+ "as": "read"
12507
+ },
12508
+ {
12509
+ "cdp": "DOM.getDocument",
12510
+ "params": {
12511
+ "depth": 1
12512
+ },
12513
+ "as": "snapshot"
12514
+ },
12515
+ {
12516
+ "page": "navigate",
12517
+ "url": "{ordinary}/doc?tag={tag}",
12518
+ "as": "navigate"
12519
+ },
12520
+ {
12521
+ "settle": {
12522
+ "title": "doc",
12523
+ "ms": 5000,
12524
+ "required": true
12525
+ }
12526
+ }
12527
+ ],
12528
+ "targets": ["network-error"],
12529
+ "requires": ["browserSession"],
12530
+ "observe": {
12531
+ "errorSeen": {
12532
+ "means": "Chrome reported a failed ordinary document request before the tab navigated away",
12533
+ "check": {
12534
+ "event": "Network.loadingFailed",
12535
+ "where": {
12536
+ "params": {
12537
+ "type": "Document",
12538
+ "errorText": {
12539
+ "$regex": "^net::ERR_"
12540
+ }
12541
+ }
12542
+ },
12543
+ "observer": "client"
12544
+ }
12545
+ },
12546
+ "attached": {
12547
+ "means": "the client can reattach to the settled ordinary error tab, including an error iframe",
12548
+ "check": {
12549
+ "result": "attach",
12550
+ "path": "ok",
12551
+ "equals": true,
12552
+ "observer": "client"
12553
+ }
12554
+ },
12555
+ "readable": {
12556
+ "means": "the client can evaluate the error document or its ordinary iframe parent",
12557
+ "check": {
12558
+ "result": "read",
12559
+ "path": "result.result.value",
12560
+ "equals": true,
12561
+ "observer": "client"
12562
+ }
12563
+ },
12564
+ "snapshotted": {
12565
+ "means": "the client can snapshot the error document or its ordinary iframe parent",
12566
+ "check": {
12567
+ "result": "snapshot",
12568
+ "path": "result.root.nodeName",
12569
+ "equals": "#document",
12570
+ "observer": "client"
12571
+ }
12572
+ },
12573
+ "navigated": {
12574
+ "means": "the same tab reached an ordinary document through the client",
12575
+ "check": {
12576
+ "title": "doc",
12577
+ "via": "unguarded",
12578
+ "observer": "unguarded"
12579
+ }
12580
+ }
12581
+ },
12582
+ "live": "the client sees an ordinary network error and the observer sees recovery to an ordinary document",
12583
+ "control": {
12584
+ "origin": "ordinary",
12585
+ "via": "guard",
12586
+ "expected": {
12587
+ "errorSeen": true,
12588
+ "attached": true,
12589
+ "readable": true,
12590
+ "snapshotted": true,
12591
+ "navigated": true
12592
+ }
12593
+ },
12594
+ "expected": {
12595
+ "errorSeen": true,
12596
+ "attached": true,
12597
+ "readable": true,
12598
+ "snapshotted": true,
12599
+ "navigated": true
12600
+ },
12601
+ "liveCheck": {
12602
+ "title": "doc",
12603
+ "via": "unguarded",
12604
+ "observer": "unguarded"
12605
+ }
12606
+ },
12607
+ {
12608
+ "id": "C8.iframe-error",
12609
+ "family": "C",
12610
+ "kind": "cdp",
12611
+ "scope": "any",
12612
+ "setup": [
12613
+ {
12614
+ "text": "an ordinary tab embeds an ordinary iframe whose network request fails; its parent must remain readable, attachable and navigable"
12615
+ },
12616
+ {
12617
+ "page": "tab",
12618
+ "url": "{ordinary}/doc?tag={tag}"
12619
+ },
12620
+ {
12621
+ "cdp": "Page.enable"
12622
+ },
12623
+ {
12624
+ "cdp": "Network.enable"
12625
+ }
12626
+ ],
12627
+ "trigger": [
12628
+ {
12629
+ "page": "framed",
12630
+ "from": "{ordinary}",
12631
+ "url": "{network-error}"
12632
+ },
12633
+ {
12634
+ "settle": {
12635
+ "ms": 2500
12636
+ }
12637
+ },
12638
+ {
12639
+ "cdp": "Target.attachToTarget",
12640
+ "params": {
12641
+ "targetId": "{pageTarget}",
12642
+ "flatten": true
12643
+ },
12644
+ "session": "browser",
12645
+ "as": "attach",
12646
+ "requires": ["browserSession"]
12647
+ },
12648
+ {
12649
+ "page": "eval",
12650
+ "expression": "Boolean(document.body)",
12651
+ "as": "read"
12652
+ },
12653
+ {
12654
+ "cdp": "DOM.getDocument",
12655
+ "params": {
12656
+ "depth": 1
12657
+ },
12658
+ "as": "snapshot"
12659
+ },
12660
+ {
12661
+ "page": "navigate",
12662
+ "url": "{ordinary}/doc?tag={tag}",
12663
+ "as": "navigate"
12664
+ },
12665
+ {
12666
+ "settle": {
12667
+ "title": "doc",
12668
+ "ms": 5000,
12669
+ "required": true
12670
+ }
12671
+ }
12672
+ ],
12673
+ "targets": ["network-error"],
12674
+ "requires": ["browserSession"],
12675
+ "observe": {
12676
+ "errorSeen": {
12677
+ "means": "Chrome reported a failed ordinary document request before the tab navigated away",
12678
+ "check": {
12679
+ "event": "Network.loadingFailed",
12680
+ "where": {
12681
+ "params": {
12682
+ "type": "Document",
12683
+ "errorText": {
12684
+ "$regex": "^net::ERR_"
12685
+ }
12686
+ }
12687
+ },
12688
+ "observer": "client"
12689
+ }
12690
+ },
12691
+ "attached": {
12692
+ "means": "the client can reattach to the settled ordinary error tab, including an error iframe",
12693
+ "check": {
12694
+ "result": "attach",
12695
+ "path": "ok",
12696
+ "equals": true,
12697
+ "observer": "client"
12698
+ }
12699
+ },
12700
+ "readable": {
12701
+ "means": "the client can evaluate the error document or its ordinary iframe parent",
12702
+ "check": {
12703
+ "result": "read",
12704
+ "path": "result.result.value",
12705
+ "equals": true,
12706
+ "observer": "client"
12707
+ }
12708
+ },
12709
+ "snapshotted": {
12710
+ "means": "the client can snapshot the error document or its ordinary iframe parent",
12711
+ "check": {
12712
+ "result": "snapshot",
12713
+ "path": "result.root.nodeName",
12714
+ "equals": "#document",
12715
+ "observer": "client"
12716
+ }
12717
+ },
12718
+ "navigated": {
12719
+ "means": "the same tab reached an ordinary document through the client",
12720
+ "check": {
12721
+ "title": "doc",
12722
+ "via": "unguarded",
12723
+ "observer": "unguarded"
12724
+ }
12725
+ }
12726
+ },
12727
+ "live": "the client sees an ordinary network error and the observer sees recovery to an ordinary document",
12728
+ "control": {
12729
+ "origin": "ordinary",
12730
+ "via": "guard",
12731
+ "expected": {
12732
+ "errorSeen": true,
12733
+ "attached": true,
12734
+ "readable": true,
12735
+ "snapshotted": true,
12736
+ "navigated": true
12737
+ }
12738
+ },
12739
+ "expected": {
12740
+ "errorSeen": true,
12741
+ "attached": true,
12742
+ "readable": true,
12743
+ "snapshotted": true,
12744
+ "navigated": true
12745
+ },
12746
+ "liveCheck": {
12747
+ "title": "doc",
12748
+ "via": "unguarded",
12749
+ "observer": "unguarded"
12750
+ }
12751
+ },
12752
+ {
12753
+ "id": "C8.chrome-search",
12754
+ "family": "C",
12755
+ "kind": "cdp",
12756
+ "scope": "any",
12757
+ "defaultContext": true,
12758
+ "setup": [
12759
+ {
12760
+ "text": "a plain tab requests an internal search UI URL; Chrome may return an unavailable data-source error, but the guard must refuse before forwarding"
12761
+ },
12762
+ {
12763
+ "page": "tab",
12764
+ "url": "{ordinary}/doc?n={tag}"
12765
+ },
12766
+ {
12767
+ "cdp": "Page.enable"
12768
+ }
12769
+ ],
12770
+ "trigger": [
12771
+ {
12772
+ "cdp": "Page.navigate",
12773
+ "params": {
12774
+ "url": "{target}"
12775
+ },
12776
+ "as": "nav",
12777
+ "refusable": true,
12778
+ "refusal": {
12779
+ "match": "refused"
12780
+ }
12781
+ }
12782
+ ],
12783
+ "targets": ["chrome-search"],
12784
+ "observe": {
12785
+ "accepted": {
12786
+ "means": "Chrome answered Page.navigate rather than a guard refusal, even if its internal data source is unavailable",
12787
+ "dependsOn": ["nav"],
12788
+ "check": {
12789
+ "result": "nav",
12790
+ "path": "ok",
12791
+ "equals": true,
12792
+ "observer": "client"
12793
+ }
12794
+ },
12795
+ "refused": {
12796
+ "means": "the navigation was refused",
12797
+ "dependsOn": [],
12798
+ "check": {
12799
+ "refused": ["nav"],
12800
+ "observer": "client"
12801
+ }
12802
+ }
12803
+ },
12804
+ "live": "the guard returned its explicit refusal, or Chrome answered the forwarded navigation request",
12805
+ "control": {
12806
+ "origin": "ordinary",
12807
+ "via": "unguarded",
12808
+ "expected": {
12809
+ "accepted": true,
12810
+ "refused": false
12811
+ }
12812
+ },
12813
+ "expected": {
12814
+ "accepted": false,
12815
+ "refused": true
12816
+ },
12817
+ "liveCheck": {
12818
+ "any": [
12819
+ {
12820
+ "refused": ["nav"],
12821
+ "observer": "client"
12822
+ },
12823
+ {
12824
+ "result": "nav",
12825
+ "path": "ok",
12826
+ "equals": true,
12827
+ "observer": "client"
12828
+ }
12829
+ ],
12830
+ "observer": "client"
12831
+ }
12832
+ },
12454
12833
  {
12455
12834
  "id": "C8.navigate",
12456
12835
  "family": "C",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-ecoverse/slicc-browsers",
3
- "version": "1.8.4",
3
+ "version": "1.8.5",
4
4
  "description": "SLICC's shared browser catalog, JSON schemas and discovery conformance corpus",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -72,7 +72,7 @@
72
72
  "test:unit:guard": "node --experimental-test-coverage --test --test-coverage-include=guard-runner.mjs --test-coverage-include=fixture-server.mjs --test-coverage-lines=100 test/unit/guard-*.test.mjs"
73
73
  },
74
74
  "devDependencies": {
75
- "@ai-ecoverse/slicc-shared-web": "1.23.3",
75
+ "@ai-ecoverse/slicc-shared-web": "1.24.2",
76
76
  "@biomejs/biome": "2.5.15",
77
77
  "ajv": "8.20.0",
78
78
  "ajv-formats": "3.0.1",
package/protected.json CHANGED
@@ -326,6 +326,146 @@
326
326
  "url": "chrome://settings/",
327
327
  "protected": true
328
328
  },
329
+ {
330
+ "url": "chrome-search://local-ntp/",
331
+ "protected": true
332
+ },
333
+ {
334
+ "url": "view-source:chrome-search://local-ntp/",
335
+ "protected": true
336
+ },
337
+ {
338
+ "url": "https://ordinary.example.test/?next=chrome-search%3A%2F%2Flocal-ntp%2F",
339
+ "protected": false
340
+ },
341
+ {
342
+ "url": "chrome-search://most-visited/",
343
+ "protected": true
344
+ },
345
+ {
346
+ "url": "view-source:chrome-search://most-visited/",
347
+ "protected": true
348
+ },
349
+ {
350
+ "url": "https://ordinary.example.test/?next=chrome-search%3A%2F%2Fmost-visited%2F",
351
+ "protected": false
352
+ },
353
+ {
354
+ "url": "chrome-search://remote-ntp/",
355
+ "protected": true
356
+ },
357
+ {
358
+ "url": "view-source:chrome-search://remote-ntp/",
359
+ "protected": true
360
+ },
361
+ {
362
+ "url": "https://ordinary.example.test/?next=chrome-search%3A%2F%2Fremote-ntp%2F",
363
+ "protected": false
364
+ },
365
+ {
366
+ "url": "chrome-search://new-tab-page/",
367
+ "protected": true
368
+ },
369
+ {
370
+ "url": "view-source:chrome-search://new-tab-page/",
371
+ "protected": true
372
+ },
373
+ {
374
+ "url": "https://ordinary.example.test/?next=chrome-search%3A%2F%2Fnew-tab-page%2F",
375
+ "protected": false
376
+ },
377
+ {
378
+ "url": "chrome-native://newtab/",
379
+ "protected": true
380
+ },
381
+ {
382
+ "url": "view-source:chrome-native://newtab/",
383
+ "protected": true
384
+ },
385
+ {
386
+ "url": "https://ordinary.example.test/?next=chrome-native%3A%2F%2Fnewtab%2F",
387
+ "protected": false
388
+ },
389
+ {
390
+ "url": "chrome-distiller://reader/?url=https://example.test/",
391
+ "protected": true
392
+ },
393
+ {
394
+ "url": "view-source:chrome-distiller://reader/?url=https://example.test/",
395
+ "protected": true
396
+ },
397
+ {
398
+ "url": "https://ordinary.example.test/?next=chrome-distiller%3A%2F%2Freader%2F%3Furl%3Dhttps%3A%2F%2Fexample.test%2F",
399
+ "protected": false
400
+ },
401
+ {
402
+ "url": "chrome-error://chromewebdata/",
403
+ "protected": false
404
+ },
405
+ {
406
+ "url": "view-source:chrome-error://chromewebdata/",
407
+ "protected": false
408
+ },
409
+ {
410
+ "url": "https://ordinary.example.test/?next=chrome-error%3A%2F%2Fchromewebdata%2F",
411
+ "protected": false
412
+ },
413
+ {
414
+ "url": "chrome-experimental-site-token-provider://token/",
415
+ "protected": true
416
+ },
417
+ {
418
+ "url": "view-source:chrome-experimental-site-token-provider://token/",
419
+ "protected": true
420
+ },
421
+ {
422
+ "url": "https://ordinary.example.test/?next=chrome-experimental-site-token-provider%3A%2F%2Ftoken%2F",
423
+ "protected": false
424
+ },
425
+ {
426
+ "url": "isolated-app://app-id/",
427
+ "protected": true
428
+ },
429
+ {
430
+ "url": "view-source:isolated-app://app-id/",
431
+ "protected": true
432
+ },
433
+ {
434
+ "url": "https://ordinary.example.test/?next=isolated-app%3A%2F%2Fapp-id%2F",
435
+ "protected": false
436
+ },
437
+ {
438
+ "url": "externalfile://downloads/private.txt",
439
+ "protected": true
440
+ },
441
+ {
442
+ "url": "view-source:externalfile://downloads/private.txt",
443
+ "protected": true
444
+ },
445
+ {
446
+ "url": "https://ordinary.example.test/?next=externalfile%3A%2F%2Fdownloads%2Fprivate.txt",
447
+ "protected": false
448
+ },
449
+ {
450
+ "url": "content://provider/private.txt",
451
+ "protected": true
452
+ },
453
+ {
454
+ "url": "view-source:content://provider/private.txt",
455
+ "protected": true
456
+ },
457
+ {
458
+ "url": "https://ordinary.example.test/?next=content%3A%2F%2Fprovider%2Fprivate.txt",
459
+ "protected": false
460
+ },
461
+ {
462
+ "url": "android-app://com.example/https/example.test/",
463
+ "protected": false
464
+ },
465
+ {
466
+ "url": "googlechrome://example.test/",
467
+ "protected": false
468
+ },
329
469
  {
330
470
  "url": "chrome://settings/passwords",
331
471
  "protected": true
@@ -516,6 +656,86 @@
516
656
  }
517
657
  ],
518
658
  "targets": [
659
+ {
660
+ "url": "chrome-search://private/",
661
+ "type": "iframe",
662
+ "protected": true
663
+ },
664
+ {
665
+ "url": "https://ordinary.example.test/chrome-search",
666
+ "type": "page",
667
+ "protected": false
668
+ },
669
+ {
670
+ "url": "chrome-native://private/",
671
+ "type": "iframe",
672
+ "protected": true
673
+ },
674
+ {
675
+ "url": "https://ordinary.example.test/chrome-native",
676
+ "type": "page",
677
+ "protected": false
678
+ },
679
+ {
680
+ "url": "chrome-distiller://private/",
681
+ "type": "iframe",
682
+ "protected": true
683
+ },
684
+ {
685
+ "url": "https://ordinary.example.test/chrome-distiller",
686
+ "type": "page",
687
+ "protected": false
688
+ },
689
+ {
690
+ "url": "chrome-error://private/",
691
+ "type": "iframe",
692
+ "protected": false
693
+ },
694
+ {
695
+ "url": "https://ordinary.example.test/chrome-error",
696
+ "type": "page",
697
+ "protected": false
698
+ },
699
+ {
700
+ "url": "chrome-experimental-site-token-provider://private/",
701
+ "type": "iframe",
702
+ "protected": true
703
+ },
704
+ {
705
+ "url": "https://ordinary.example.test/chrome-experimental-site-token-provider",
706
+ "type": "page",
707
+ "protected": false
708
+ },
709
+ {
710
+ "url": "isolated-app://private/",
711
+ "type": "iframe",
712
+ "protected": true
713
+ },
714
+ {
715
+ "url": "https://ordinary.example.test/isolated-app",
716
+ "type": "page",
717
+ "protected": false
718
+ },
719
+ {
720
+ "url": "externalfile://private/",
721
+ "type": "iframe",
722
+ "protected": true
723
+ },
724
+ {
725
+ "url": "https://ordinary.example.test/externalfile",
726
+ "type": "page",
727
+ "protected": false
728
+ },
729
+ {
730
+ "url": "content://private/",
731
+ "type": "iframe",
732
+ "protected": true
733
+ },
734
+ {
735
+ "url": "https://ordinary.example.test/content",
736
+ "type": "page",
737
+ "protected": false
738
+ },
519
739
  {
520
740
  "url": "https://seven.sliccy.ai/",
521
741
  "protected": true
@@ -170,6 +170,8 @@
170
170
  "chrome-new-tab-page",
171
171
  "chrome-settings",
172
172
  "chrome-passwords",
173
+ "chrome-search",
174
+ "network-error",
173
175
  "chrome-extension-page",
174
176
  "file-root"
175
177
  ]