or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

assertions.mdcompartments.mdenvironment-hardening.mdindex.mdmodules.mdtools.md

compartments.mddocs/

0

# Compartments

1

2

Compartments provide isolated execution contexts for running untrusted code with controlled capabilities and communication channels. Each compartment has its own global object but shares frozen intrinsics with other compartments, enabling secure code execution without complete process isolation.

3

4

## Capabilities

5

6

### Compartment Constructor

7

8

Creates isolated execution contexts with configurable globals, module systems, and security policies.

9

10

```javascript { .api }

11

/**

12

* Creates a new compartment with isolated global scope

13

* @param options - Configuration options for the compartment

14

*/

15

class Compartment {

16

constructor(options?: CompartmentOptions & { __options__: true });

17

18

// Legacy constructor (deprecated)

19

constructor(

20

globals?: Record<PropertyKey, any> | undefined,

21

modules?: Record<string, ModuleDescriptor>,

22

options?: CompartmentOptions

23

);

24

}

25

```

26

27

**Usage Examples:**

28

29

```javascript

30

import 'ses';

31

32

lockdown();

33

34

// Basic compartment with minimal capabilities

35

const basicCompartment = new Compartment({

36

__options__: true

37

});

38

39

// Compartment with specific globals

40

const endowedCompartment = new Compartment({

41

globals: {

42

console: harden(console),

43

fetch: harden(fetch), // Provide specific capabilities

44

myAPI: harden({

45

getValue: () => "secure data"

46

})

47

},

48

__options__: true

49

});

50

51

// Named compartment for debugging

52

const namedCompartment = new Compartment({

53

name: "user-script-sandbox",

54

globals: { console: harden(console) },

55

__options__: true

56

});

57

```

58

59

### Code Evaluation

60

61

Evaluates JavaScript code within the compartment's isolated context.

62

63

```javascript { .api }

64

/**

65

* Evaluates JavaScript code in the compartment's context

66

* @param code - JavaScript code string to evaluate

67

* @param options - Evaluation configuration options

68

* @returns Result of code evaluation

69

*/

70

evaluate(code: string, options?: EvaluateOptions): any;

71

```

72

73

**Usage Examples:**

74

75

```javascript

76

import 'ses';

77

78

lockdown();

79

80

const compartment = new Compartment({

81

globals: { console: harden(console) },

82

__options__: true

83

});

84

85

// Basic evaluation

86

const result = compartment.evaluate(`

87

const data = { message: "Hello from compartment!" };

88

console.log("Compartment executing code");

89

data.message;

90

`);

91

console.log(result); // "Hello from compartment!"

92

93

// Evaluation with options

94

const sloppyResult = compartment.evaluate(`

95

// This would normally fail in strict mode

96

undeclaredVar = "sloppy mode";

97

undeclaredVar;

98

`, {

99

sloppyGlobalsMode: true

100

});

101

102

// Code transformation during evaluation

103

const transformedResult = compartment.evaluate(`

104

console.log("Original message");

105

`, {

106

transforms: [

107

(source) => source.replace(/Original/, 'Transformed')

108

]

109

});

110

```

111

112

### Module Import (Asynchronous)

113

114

Dynamically imports modules with promise-based loading.

115

116

```javascript { .api }

117

/**

118

* Dynamically imports a module asynchronously

119

* @param specifier - Module specifier to import

120

* @returns Promise resolving to module namespace object

121

*/

122

import(specifier: string | null): Promise<{ namespace: ModuleExportsNamespace }>;

123

```

124

125

**Usage Examples:**

126

127

```javascript

128

import 'ses';

129

130

lockdown();

131

132

const compartment = new Compartment({

133

importHook: async (specifier) => {

134

if (specifier === 'my-module') {

135

return {

136

source: `

137

export const greeting = "Hello";

138

export function sayHello(name) {

139

return greeting + ", " + name + "!";

140

}

141

`

142

};

143

}

144

throw new Error(`Module not found: ${specifier}`);

145

},

146

__options__: true

147

});

148

149

// Import module asynchronously

150

compartment.import('my-module').then(({ namespace }) => {

151

console.log(namespace.sayHello('World')); // "Hello, World!"

152

});

153

```

154

155

### Module Import (Synchronous)

156

157

Synchronously imports modules for use cases where async loading is not suitable.

158

159

```javascript { .api }

160

/**

161

* Synchronously imports a module that's already loaded or can be loaded synchronously

162

* @param specifier - Module specifier to import

163

* @returns Module namespace object

164

*/

165

importNow(specifier: string): ModuleExportsNamespace;

166

```

167

168

**Usage Examples:**

169

170

```javascript

171

import 'ses';

172

173

lockdown();

174

175

const compartment = new Compartment({

176

modules: {

177

'math-utils': {

178

source: `

179

export const add = (a, b) => a + b;

180

export const multiply = (a, b) => a * b;

181

`

182

}

183

},

184

importNowHook: (specifier) => {

185

if (specifier === 'runtime-module') {

186

return {

187

source: `export const runtime = true;`

188

};

189

}

190

},

191

__options__: true

192

});

193

194

// Import pre-loaded module

195

const mathUtils = compartment.importNow('math-utils');

196

console.log(mathUtils.add(2, 3)); // 5

197

198

// Import via importNowHook

199

const runtimeMod = compartment.importNow('runtime-module');

200

console.log(runtimeMod.runtime); // true

201

```

202

203

### Module Loading

204

205

Preloads modules without importing them into the current scope.

206

207

```javascript { .api }

208

/**

209

* Preloads a module without importing it

210

* @param specifier - Module specifier to load

211

* @returns Promise that resolves when module is loaded

212

*/

213

load(specifier: string): Promise<void>;

214

```

215

216

### Module Access

217

218

Accesses already loaded module namespaces.

219

220

```javascript { .api }

221

/**

222

* Gets the namespace of an already loaded module

223

* @param specifier - Module specifier

224

* @returns Module namespace object

225

*/

226

module(specifier: string): ModuleExportsNamespace;

227

```

228

229

### Compartment Properties

230

231

Access to compartment metadata and global object.

232

233

```javascript { .api }

234

/**

235

* The compartment's global object

236

*/

237

get globalThis(): Record<PropertyKey, any>;

238

239

/**

240

* The compartment's name for debugging

241

*/

242

get name(): string;

243

```

244

245

**Usage Examples:**

246

247

```javascript

248

import 'ses';

249

250

lockdown();

251

252

const compartment = new Compartment({

253

name: 'test-compartment',

254

globals: { customGlobal: 'test value' },

255

__options__: true

256

});

257

258

// Access compartment properties

259

console.log(compartment.name); // 'test-compartment'

260

console.log(compartment.globalThis.customGlobal); // 'test value'

261

262

// Each compartment has its own global object

263

const anotherCompartment = new Compartment({ __options__: true });

264

console.log(compartment.globalThis !== anotherCompartment.globalThis); // true

265

266

// But they share the same intrinsics

267

console.log(compartment.globalThis.Array === anotherCompartment.globalThis.Array); // true

268

```

269

270

## Configuration Options

271

272

### CompartmentOptions Interface

273

274

Comprehensive configuration for compartment behavior, module loading, and security policies.

275

276

```javascript { .api }

277

interface CompartmentOptions {

278

/** Compartment name for debugging purposes */

279

name?: string;

280

281

/** Initial global variables for the compartment */

282

globals?: Map<string, any>;

283

284

/** Static module map for pre-loaded modules */

285

modules?: Map<string, ModuleDescriptor>;

286

287

/** Source transformation functions applied to evaluated code */

288

transforms?: Array<Transform>;

289

290

/** Internal shim-specific transforms */

291

__shimTransforms__?: Array<Transform>;

292

293

/** Module resolution hook for converting import specifiers */

294

resolveHook?: ResolveHook;

295

296

/** Async module loading hook */

297

importHook?: ImportHook;

298

299

/** Sync module loading hook */

300

importNowHook?: ImportNowHook;

301

302

/** Dynamic module mapping hook */

303

moduleMapHook?: ModuleMapHook;

304

305

/** Hook for customizing import.meta objects */

306

importMetaHook?: ImportMetaHook;

307

308

/** Use native compartment implementation if available */

309

__native__?: boolean;

310

311

/** Control namespace boxing behavior */

312

__noNamespaceBox__?: boolean;

313

314

/** Fail fast on first module loading error */

315

noAggregateLoadErrors?: boolean;

316

}

317

```

318

319

### EvaluateOptions Interface

320

321

Options for controlling code evaluation behavior.

322

323

```javascript { .api }

324

interface EvaluateOptions {

325

/** Source transformation functions for this evaluation */

326

transforms?: Array<Transform>;

327

328

/** Allow sloppy mode for legacy code compatibility */

329

sloppyGlobalsMode?: boolean;

330

331

/** Internal module shim lexical bindings */

332

__moduleShimLexicals__?: Record<string, any>;

333

334

/** Evade HTML comment test for browser compatibility */

335

__evadeHtmlCommentTest__?: boolean;

336

337

/** Reject some direct eval expressions for security */

338

__rejectSomeDirectEvalExpressions__?: boolean;

339

}

340

```

341

342

## Advanced Usage Patterns

343

344

### Cross-Compartment Communication

345

346

Secure communication between compartments using hardened objects:

347

348

```javascript

349

import 'ses';

350

351

lockdown();

352

353

// Create a shared communication channel

354

const createChannel = () => {

355

const listeners = [];

356

return harden({

357

send: (message) => {

358

listeners.forEach(listener => listener(message));

359

},

360

listen: (callback) => {

361

listeners.push(callback);

362

}

363

});

364

};

365

366

const channel = createChannel();

367

368

// Compartment A - sender

369

const senderCompartment = new Compartment({

370

globals: { channel },

371

__options__: true

372

});

373

374

// Compartment B - receiver

375

const receiverCompartment = new Compartment({

376

globals: {

377

channel,

378

console: harden(console)

379

},

380

__options__: true

381

});

382

383

// Set up receiver

384

receiverCompartment.evaluate(`

385

channel.listen((message) => {

386

console.log('Received:', message);

387

});

388

`);

389

390

// Send message from sender

391

senderCompartment.evaluate(`

392

channel.send({ type: 'greeting', data: 'Hello from sender!' });

393

`);

394

```

395

396

### Module Federation

397

398

Sharing modules between compartments:

399

400

```javascript

401

import 'ses';

402

403

lockdown();

404

405

// Shared module compartment

406

const moduleCompartment = new Compartment({

407

modules: {

408

'shared-utils': {

409

source: `

410

export const utilities = {

411

format: (str) => str.toUpperCase(),

412

validate: (data) => typeof data === 'string'

413

};

414

`

415

}

416

},

417

__options__: true

418

});

419

420

// Consumer compartments that reference the shared module

421

const consumerA = new Compartment({

422

modules: {

423

'shared-utils': {

424

namespace: 'shared-utils',

425

compartment: moduleCompartment

426

}

427

},

428

__options__: true

429

});

430

431

const consumerB = new Compartment({

432

modules: {

433

'shared-utils': {

434

namespace: 'shared-utils',

435

compartment: moduleCompartment

436

}

437

},

438

__options__: true

439

});

440

441

// Both compartments can use the shared module

442

const utilsA = consumerA.importNow('shared-utils');

443

const utilsB = consumerB.importNow('shared-utils');

444

445

console.log(utilsA.utilities === utilsB.utilities); // true - same object

446

```

447

448

### Capability-Based Security

449

450

Implementing fine-grained permissions using object capabilities:

451

452

```javascript

453

import 'ses';

454

455

lockdown();

456

457

// Create capability objects

458

const createFileCapability = (allowedPaths) => harden({

459

readFile: (path) => {

460

if (!allowedPaths.includes(path)) {

461

throw new Error(`Access denied: ${path}`);

462

}

463

return `Content of ${path}`;

464

}

465

});

466

467

const createNetworkCapability = (allowedHosts) => harden({

468

fetch: (url) => {

469

const hostname = new URL(url).hostname;

470

if (!allowedHosts.includes(hostname)) {

471

throw new Error(`Network access denied: ${hostname}`);

472

}

473

return Promise.resolve(`Response from ${url}`);

474

}

475

});

476

477

// Create compartment with specific capabilities

478

const sandboxedCompartment = new Compartment({

479

globals: {

480

fileSystem: createFileCapability(['/public/data.txt']),

481

network: createNetworkCapability(['api.example.com']),

482

console: harden(console)

483

},

484

__options__: true

485

});

486

487

// Code in compartment can only access granted capabilities

488

sandboxedCompartment.evaluate(`

489

try {

490

const data = fileSystem.readFile('/public/data.txt'); // Allowed

491

console.log('File access:', data);

492

} catch (error) {

493

console.log('File error:', error.message);

494

}

495

496

try {

497

const data = fileSystem.readFile('/private/secret.txt'); // Denied

498

console.log('Should not reach here');

499

} catch (error) {

500

console.log('Security error:', error.message);

501

}

502

`);

503

```