Skip to content

Commit 09f3e01

Browse files
sirtimidclaude
andcommitted
feat(ocap-kernel): plumb allowedGlobalNames from Kernel.make() to VatSupervisor
Add allowedGlobalNames option to Kernel.make() so the kernel owner can restrict which globals are available to vats. The names flow through VatManager → VatHandle → initVat RPC to VatSupervisor, which filters DEFAULT_ALLOWED_GLOBALS by the received names. When omitted, all defaults remain available. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 8100815 commit 09f3e01

5 files changed

Lines changed: 51 additions & 5 deletions

File tree

packages/ocap-kernel/src/Kernel.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ export class Kernel {
103103
* @param options.keySeed - Optional seed for libp2p key generation.
104104
* @param options.mnemonic - Optional BIP39 mnemonic for deriving the kernel identity.
105105
* @param options.ioChannelFactory - Optional factory for creating IO channels.
106+
* @param options.allowedGlobalNames - Optional list of allowed global names for vat endowments.
106107
*/
107108
// eslint-disable-next-line no-restricted-syntax
108109
private constructor(
@@ -114,6 +115,7 @@ export class Kernel {
114115
keySeed?: string | undefined;
115116
mnemonic?: string | undefined;
116117
ioChannelFactory?: IOChannelFactory;
118+
allowedGlobalNames?: string[];
117119
} = {},
118120
) {
119121
this.#platformServices = platformServices;
@@ -145,6 +147,7 @@ export class Kernel {
145147
kernelStore: this.#kernelStore,
146148
kernelQueue: this.#kernelQueue,
147149
logger: this.#logger.subLogger({ tags: ['VatManager'] }),
150+
allowedGlobalNames: options.allowedGlobalNames,
148151
});
149152

150153
this.#remoteManager = new RemoteManager({
@@ -229,6 +232,7 @@ export class Kernel {
229232
* @param options.mnemonic - Optional BIP39 mnemonic for deriving the kernel identity.
230233
* @param options.ioChannelFactory - Optional factory for creating IO channels.
231234
* @param options.systemSubclusters - Optional array of system subcluster configurations.
235+
* @param options.allowedGlobalNames - Optional list of allowed global names for vat endowments. When set, only these names from DEFAULT_ALLOWED_GLOBALS are available to vats.
232236
* @returns A promise for the new kernel instance.
233237
*/
234238
static async make(
@@ -241,6 +245,7 @@ export class Kernel {
241245
mnemonic?: string | undefined;
242246
ioChannelFactory?: IOChannelFactory;
243247
systemSubclusters?: SystemSubclusterConfig[];
248+
allowedGlobalNames?: string[];
244249
} = {},
245250
): Promise<Kernel> {
246251
const kernel = new Kernel(platformServices, kernelDatabase, options);

packages/ocap-kernel/src/rpc/vat/initVat.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
import type { MethodSpec, Handler } from '@metamask/kernel-rpc-methods';
2-
import { array, object, string, tuple } from '@metamask/superstruct';
2+
import {
3+
array,
4+
exactOptional,
5+
object,
6+
string,
7+
tuple,
8+
} from '@metamask/superstruct';
39
import type { Infer } from '@metamask/superstruct';
410

511
import { VatDeliveryResultStruct } from './shared.ts';
@@ -9,6 +15,7 @@ import type { VatConfig, VatDeliveryResult } from '../../types.ts';
915
const paramsStruct = object({
1016
vatConfig: VatConfigStruct,
1117
state: array(tuple([string(), string()])),
18+
allowedGlobalNames: exactOptional(array(string())),
1219
});
1320

1421
type Params = Infer<typeof paramsStruct>;
@@ -28,6 +35,7 @@ export const initVatSpec: InitVatSpec = {
2835
export type InitVat = (
2936
vatConfig: VatConfig,
3037
state: Map<string, string>,
38+
allowedGlobalNames: string[] | undefined,
3139
) => Promise<VatDeliveryResult>;
3240

3341
type InitVatHooks = {
@@ -45,6 +53,10 @@ export const initVatHandler: InitVatHandler = {
4553
...initVatSpec,
4654
hooks: { initVat: true },
4755
implementation: async ({ initVat }, params) => {
48-
return await initVat(params.vatConfig, new Map(params.state));
56+
return await initVat(
57+
params.vatConfig,
58+
new Map(params.state),
59+
params.allowedGlobalNames,
60+
);
4961
},
5062
};

packages/ocap-kernel/src/vats/VatHandle.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ type VatConstructorProps = {
4545
kernelStore: KernelStore;
4646
kernelQueue: KernelQueue;
4747
logger?: Logger | undefined;
48+
allowedGlobalNames?: string[] | undefined;
4849
};
4950

5051
/**
@@ -63,6 +64,9 @@ export class VatHandle implements EndpointHandle {
6364
/** Logger for outputting messages (such as errors) to the console */
6465
readonly #logger: Logger | undefined;
6566

67+
/** Optional list of allowed global names for vat endowments */
68+
readonly #allowedGlobalNames: string[] | undefined;
69+
6670
/** Storage holding the kernel's persistent state */
6771
readonly #kernelStore: KernelStore;
6872

@@ -89,6 +93,7 @@ export class VatHandle implements EndpointHandle {
8993
* @param params.kernelStore - The kernel's persistent state store.
9094
* @param params.kernelQueue - The kernel's queue.
9195
* @param params.logger - Optional logger for error and diagnostic output.
96+
* @param params.allowedGlobalNames - Optional list of allowed global names for vat endowments.
9297
*/
9398
// eslint-disable-next-line no-restricted-syntax
9499
private constructor({
@@ -98,10 +103,12 @@ export class VatHandle implements EndpointHandle {
98103
kernelStore,
99104
kernelQueue,
100105
logger,
106+
allowedGlobalNames,
101107
}: VatConstructorProps) {
102108
this.vatId = vatId;
103109
this.config = vatConfig;
104110
this.#logger = logger;
111+
this.#allowedGlobalNames = allowedGlobalNames;
105112
this.#vatStream = vatStream;
106113
this.#kernelStore = kernelStore;
107114
this.#vatStore = kernelStore.makeVatStore(vatId);
@@ -171,6 +178,9 @@ export class VatHandle implements EndpointHandle {
171178
params: {
172179
vatConfig: this.config,
173180
state: this.#vatStore.getKVData(),
181+
...(this.#allowedGlobalNames
182+
? { allowedGlobalNames: this.#allowedGlobalNames }
183+
: {}),
174184
},
175185
});
176186
}

packages/ocap-kernel/src/vats/VatManager.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ type VatManagerOptions = {
2525
kernelStore: KernelStore;
2626
kernelQueue: KernelQueue;
2727
logger?: Logger;
28+
allowedGlobalNames?: string[] | undefined;
2829
};
2930

3031
/**
@@ -46,6 +47,9 @@ export class VatManager {
4647
/** Logger for outputting messages (such as errors) to the console */
4748
readonly #logger: Logger;
4849

50+
/** Optional list of allowed global names for vat endowments */
51+
readonly #allowedGlobalNames: string[] | undefined;
52+
4953
/**
5054
* Creates a new VatManager instance.
5155
*
@@ -54,18 +58,21 @@ export class VatManager {
5458
* @param options.kernelStore - The kernel's persistent state store.
5559
* @param options.kernelQueue - The kernel's message queue for scheduling deliveries.
5660
* @param options.logger - Logger instance for debugging and diagnostics.
61+
* @param options.allowedGlobalNames - Optional list of allowed global names for vat endowments.
5762
*/
5863
constructor({
5964
platformServices,
6065
kernelStore,
6166
kernelQueue,
6267
logger,
68+
allowedGlobalNames,
6369
}: VatManagerOptions) {
6470
this.#vats = new Map();
6571
this.#platformServices = platformServices;
6672
this.#kernelStore = kernelStore;
6773
this.#kernelQueue = kernelQueue;
6874
this.#logger = logger ?? new Logger('VatManager');
75+
this.#allowedGlobalNames = allowedGlobalNames;
6976
harden(this);
7077
}
7178

@@ -134,6 +141,7 @@ export class VatManager {
134141
kernelStore: this.#kernelStore,
135142
kernelQueue: this.#kernelQueue,
136143
logger: vatLogger,
144+
allowedGlobalNames: this.#allowedGlobalNames,
137145
});
138146
this.#vats.set(vatId, vat);
139147
}

packages/ocap-kernel/src/vats/VatSupervisor.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -263,12 +263,13 @@ export class VatSupervisor {
263263
*
264264
* @param vatConfig - Configuration object describing the vat to be intialized.
265265
* @param state - A Map representing the current persistent state of the vat.
266-
*
266+
* @param allowedGlobalNames - Optional list of allowed global names to restrict the available endowments.
267267
* @returns a promise for a checkpoint of the new vat.
268268
*/
269269
async #initVat(
270270
vatConfig: VatConfig,
271271
state: Map<string, string>,
272+
allowedGlobalNames: string[] | undefined,
272273
): Promise<VatDeliveryResult> {
273274
if (this.#loaded) {
274275
throw Error(
@@ -306,12 +307,22 @@ export class VatSupervisor {
306307

307308
const { bundleSpec, parameters, platformConfig, globals } = vatConfig;
308309

310+
// If the kernel specified a restricted set of allowed global names,
311+
// filter the full allowlist down to only those names.
312+
const effectiveAllowedGlobals = allowedGlobalNames
313+
? Object.fromEntries(
314+
allowedGlobalNames
315+
.filter((name) => hasProperty(this.#allowedGlobals, name))
316+
.map((name) => [name, this.#allowedGlobals[name]]),
317+
)
318+
: this.#allowedGlobals;
319+
309320
// Build additional endowments from globals list
310321
const requestedGlobals: Record<string, unknown> = {};
311322
if (globals) {
312323
for (const name of globals) {
313-
if (hasProperty(this.#allowedGlobals, name)) {
314-
requestedGlobals[name] = this.#allowedGlobals[name];
324+
if (hasProperty(effectiveAllowedGlobals, name)) {
325+
requestedGlobals[name] = effectiveAllowedGlobals[name];
315326
} else {
316327
this.#logger.warn(
317328
`Vat "${this.id}" requested unknown global "${name}"`,

0 commit comments

Comments
 (0)