Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 50 additions & 20 deletions docs/kernel-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,27 +155,56 @@ Only names in the vat's `globals` array are installed in the vat's compartment.

The kernel ships with the following set, sourced from `@metamask/snaps-execution-environments`:

| Name | Category | Notes |
| ----------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `setTimeout` | Timer (attenuated) | Isolated per vat. Cancelled automatically on vat termination. |
| `clearTimeout` | Timer (attenuated) | Only clears timers created by the same vat. |
| `setInterval` | Timer (attenuated) | Isolated per vat. Cancelled automatically on vat termination. |
| `clearInterval` | Timer (attenuated) | Only clears intervals created by the same vat. |
| `Date` | Attenuated | Each `Date.now()` read adds up to 1 ms of random jitter, clamped monotonic non-decreasing; precise sub-millisecond timing cannot leak through. |
| `Math` | Attenuated | `Math.random()` is sourced from `crypto.getRandomValues`. **Not a CSPRNG** per the upstream NOTE — defends against stock-RNG timing side channels only. |
| `crypto` | Web Crypto | Hardened Web Crypto API. |
| `SubtleCrypto` | Web Crypto | Hardened Web Crypto API. |
| `TextEncoder` | Text codec | Plain hardened. |
| `TextDecoder` | Text codec | Plain hardened. |
| `URL` | URL | Plain hardened. |
| `URLSearchParams` | URL | Plain hardened. |
| `atob` | Base64 | Plain hardened. |
| `btoa` | Base64 | Plain hardened. |
| `AbortController` | Abort | Plain hardened. |
| `AbortSignal` | Abort | Plain hardened. |
| Name | Category | Notes |
| ----------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `setTimeout` | Timer (attenuated) | Isolated per vat. Cancelled automatically on vat termination. |
| `clearTimeout` | Timer (attenuated) | Only clears timers created by the same vat. |
| `setInterval` | Timer (attenuated) | Isolated per vat. Cancelled automatically on vat termination. |
| `clearInterval` | Timer (attenuated) | Only clears intervals created by the same vat. |
| `Date` | Attenuated | Each `Date.now()` read adds up to 1 ms of random jitter, clamped monotonic non-decreasing; precise sub-millisecond timing cannot leak through. |
| `Math` | Attenuated | `Math.random()` is sourced from `crypto.getRandomValues`. **Not a CSPRNG** per the upstream NOTE — defends against stock-RNG timing side channels only. |
| `crypto` | Web Crypto | Hardened Web Crypto API. |
| `SubtleCrypto` | Web Crypto | Hardened Web Crypto API. |
| `fetch` | Network (attenuated) | Wrapped by the Snaps network factory; teardown aborts in-flight requests and cancels open body streams on vat termination. **Requires `network.allowedHosts`** — see [Network endowment](#network-endowment). |
| `Request` | Network | Hardened constructor surfaced alongside `fetch` so vat code can build requests before calling it. |
| `Headers` | Network | Hardened constructor. |
| `Response` | Network | Hardened constructor; overrides `[Symbol.hasInstance]` so wrapped fetch results still pass `instanceof Response`. |
| `TextEncoder` | Text codec | Plain hardened. |
| `TextDecoder` | Text codec | Plain hardened. |
| `URL` | URL | Plain hardened. |
| `URLSearchParams` | URL | Plain hardened. |
| `atob` | Base64 | Plain hardened. |
| `btoa` | Base64 | Plain hardened. |
| `AbortController` | Abort | Plain hardened. |
| `AbortSignal` | Abort | Plain hardened. |

"Plain hardened" means the value is the host's implementation wrapped with `harden()` — it behaves identically to the browser/Node version. "Attenuated" means the value is a deliberate reimplementation with different semantics; the Notes column flags the relevant differences. The canonical list lives in [`endowments.ts`](../packages/ocap-kernel/src/vats/endowments.ts).

### Network endowment

`fetch`, `Request`, `Headers`, and `Response` are only available when the vat also declares a per-vat host allowlist in `VatConfig.network.allowedHosts`:

```ts
await kernel.launchSubcluster({
bootstrap: 'worker',
vats: {
worker: {
bundleSpec: '...',
globals: ['fetch', 'Request', 'Headers', 'Response'],
network: { allowedHosts: ['api.example.com', 'api.github.com'] },
},
},
});
```

Requesting `'fetch'` without an `allowedHosts` entry (or with an absent `network` block) fails `initVat` with `Vat "<id>" requested "fetch" but no network.allowedHosts was specified`. There is no implicit allow-all; an empty `allowedHosts: []` is legal but rejects every outbound host. Host matching is a case-sensitive exact comparison against `URL.hostname` — ports and schemes are not considered, so `allowedHosts: ['api.example.com']` accepts both `http://api.example.com` and `https://api.example.com:8443`. `file://` URLs are **rejected** by fetch — use the `fs` platform capability for filesystem access.

Lifecycle notes:

- The network factory reads `globalThis.fetch` at call time — host applications that need to stub it (e.g., tests) should override the global before constructing the `VatSupervisor`.
- Teardown cancels in-flight requests and open body streams. It runs as part of `VatSupervisor.terminate()` alongside timer teardown.
- `fetch` returns a `ResponseWrapper` rather than the raw `Response`; the endowed `Response` constructor is patched so `instanceof Response` still returns `true` for wrapper instances.

### Restricting or replacing the allowed set

Two levers, applied at different layers:
Expand Down Expand Up @@ -536,8 +565,9 @@ type VatConfig = {
bundleName?: string; // Name of a pre-registered bundle
creationOptions?: Record<string, Json>; // Options for vat creation
parameters?: Record<string, Json>; // Static parameters passed to buildRootObject
platformConfig?: Partial<PlatformConfig>; // Platform-specific configuration
globals?: string[]; // Host/Web API globals the vat requests — see [Vat Endowments](#vat-endowments)
platformConfig?: Partial<PlatformConfig>; // Platform-specific configuration (currently `fs` only)
globals?: AllowedGlobalName[]; // Host/Web API globals the vat requests — see [Vat Endowments](#vat-endowments)
network?: { allowedHosts: string[] }; // Host allowlist required when requesting `fetch`
};

// Configuration for a system subcluster
Expand Down
15 changes: 15 additions & 0 deletions docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,21 @@ A vat can also request host/Web API globals (timers, `Date`, `crypto`, `URL`,
}
```

Network access is a special case: requesting `fetch` (and optionally `Request`/`Headers`/`Response`) also requires a per-vat host allowlist under `network.allowedHosts`. Without it, `initVat` rejects the vat.

```json
{
"bootstrap": "alice",
"vats": {
"alice": {
"bundleSpec": "http://localhost:3000/sample-vat.bundle",
"globals": ["fetch", "Request", "Headers", "Response"],
"network": { "allowedHosts": ["api.example.com"] }
}
}
}
```

See [Vat Endowments](./kernel-guide.md#vat-endowments) in the kernel guide for the full list and for how to narrow the set with `Kernel.make({ allowedGlobalNames })`.

## Kernel API
Expand Down
4 changes: 2 additions & 2 deletions packages/evm-wallet-experiment/docs/setup-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -472,8 +472,8 @@ yarn ocap daemon exec launchSubcluster '{
},
"provider": {
"bundleSpec": "packages/evm-wallet-experiment/src/vats/provider-vat.bundle",
"globals": ["TextEncoder", "TextDecoder"],
"platformConfig": { "fetch": { "allowedHosts": ["<chain>.infura.io", "api.pimlico.io", "swap.api.cx.metamask.io"] } }
"globals": ["TextEncoder", "TextDecoder", "fetch", "Request", "Headers", "Response"],
"network": { "allowedHosts": ["<chain>.infura.io", "api.pimlico.io", "swap.api.cx.metamask.io"] }
},
"delegation": {
"bundleSpec": "packages/evm-wallet-experiment/src/vats/delegation-vat.bundle",
Expand Down
15 changes: 11 additions & 4 deletions packages/evm-wallet-experiment/src/cluster-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,17 @@ export function makeWalletClusterConfig(
},
provider: {
bundleSpec: `${bundleBaseUrl}/provider-vat.bundle`,
globals: ['TextEncoder', 'TextDecoder'],
platformConfig: {
fetch: allowedHosts ? { allowedHosts } : {},
},
globals: allowedHosts
? [
'TextEncoder',
'TextDecoder',
'fetch',
'Request',
'Headers',
'Response',
]
: ['TextEncoder', 'TextDecoder'],
...(allowedHosts ? { network: { allowedHosts } } : {}),
},
...auxiliaryVat,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,15 @@ export function launchWalletSubcluster(
},
provider: {
bundleSpec: `${BUNDLE_BASE}/provider-vat.bundle`,
globals: ['TextEncoder', 'TextDecoder'],
platformConfig: { fetch: { allowedHosts } },
globals: [
'TextEncoder',
'TextDecoder',
'fetch',
'Request',
'Headers',
'Response',
],
network: { allowedHosts },
},
...auxiliaryVat,
},
Expand Down
5 changes: 5 additions & 0 deletions packages/kernel-node-runtime/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Changed

- **BREAKING:** Drop `platformOptions.fetch` from `makeNodeJsVatSupervisor` ([#942](https://github.com/MetaMask/ocap-kernel/pull/942))
- `fetch` is now a vat endowment; stub `globalThis.fetch` directly if needed

## [0.1.0]

### Added
Expand Down
1 change: 0 additions & 1 deletion packages/kernel-node-runtime/src/vat/vat-worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ async function main(): Promise<void> {
const { logger: streamLogger } = await makeNodeJsVatSupervisor(
vatId,
LOG_TAG,
{ fetch: { fromFetch: fetch } },
);
logger = streamLogger;
logger.debug('vat-worker main');
Expand Down
5 changes: 5 additions & 0 deletions packages/kernel-platforms/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Removed

- **BREAKING:** Remove the `fetch` platform capability and its exports (`fetchConfigStruct`, `FetchCapability`, `FetchConfig`, `makeHostCaveat`, `makeCaveatedFetch`) ([#942](https://github.com/MetaMask/ocap-kernel/pull/942))
- `fetch` is now a vat endowment in `@metamask/ocap-kernel`; see its changelog for the migration

## [0.1.0]

### Added
Expand Down
2 changes: 0 additions & 2 deletions packages/kernel-platforms/src/browser.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { capabilityFactory as fetchCapabilityFactory } from './capabilities/fetch/browser.ts';
import { capabilityFactory as fsCapabilityFactory } from './capabilities/fs/browser.ts';
import { makePlatformFactory } from './factory.ts';

export const makePlatform = makePlatformFactory({
fetch: fetchCapabilityFactory,
fs: fsCapabilityFactory,
});

This file was deleted.

12 changes: 0 additions & 12 deletions packages/kernel-platforms/src/capabilities/fetch/browser.ts

This file was deleted.

93 changes: 0 additions & 93 deletions packages/kernel-platforms/src/capabilities/fetch/nodejs.test.ts

This file was deleted.

Loading
Loading