CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-ses

Hardened JavaScript for fearless cooperation through secure execution contexts and object-capability security

Pending
Overview
Eval results
Files

compartments.mddocs/

Compartments

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.

Capabilities

Compartment Constructor

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

/**
 * Creates a new compartment with isolated global scope
 * @param options - Configuration options for the compartment
 */
class Compartment {
  constructor(options?: CompartmentOptions & { __options__: true });
  
  // Legacy constructor (deprecated)
  constructor(
    globals?: Record<PropertyKey, any> | undefined,
    modules?: Record<string, ModuleDescriptor>,
    options?: CompartmentOptions
  );
}

Usage Examples:

import 'ses';

lockdown();

// Basic compartment with minimal capabilities
const basicCompartment = new Compartment({
  __options__: true
});

// Compartment with specific globals
const endowedCompartment = new Compartment({
  globals: {
    console: harden(console),
    fetch: harden(fetch), // Provide specific capabilities
    myAPI: harden({
      getValue: () => "secure data"
    })
  },
  __options__: true
});

// Named compartment for debugging
const namedCompartment = new Compartment({
  name: "user-script-sandbox",
  globals: { console: harden(console) },
  __options__: true
});

Code Evaluation

Evaluates JavaScript code within the compartment's isolated context.

/**
 * Evaluates JavaScript code in the compartment's context
 * @param code - JavaScript code string to evaluate
 * @param options - Evaluation configuration options
 * @returns Result of code evaluation
 */
evaluate(code: string, options?: EvaluateOptions): any;

Usage Examples:

import 'ses';

lockdown();

const compartment = new Compartment({
  globals: { console: harden(console) },
  __options__: true
});

// Basic evaluation
const result = compartment.evaluate(`
  const data = { message: "Hello from compartment!" };
  console.log("Compartment executing code");
  data.message;
`);
console.log(result); // "Hello from compartment!"

// Evaluation with options
const sloppyResult = compartment.evaluate(`
  // This would normally fail in strict mode
  undeclaredVar = "sloppy mode";
  undeclaredVar;
`, {
  sloppyGlobalsMode: true
});

// Code transformation during evaluation
const transformedResult = compartment.evaluate(`
  console.log("Original message");
`, {
  transforms: [
    (source) => source.replace(/Original/, 'Transformed')
  ]
});

Module Import (Asynchronous)

Dynamically imports modules with promise-based loading.

/**
 * Dynamically imports a module asynchronously
 * @param specifier - Module specifier to import
 * @returns Promise resolving to module namespace object
 */
import(specifier: string | null): Promise<{ namespace: ModuleExportsNamespace }>;

Usage Examples:

import 'ses';

lockdown();

const compartment = new Compartment({
  importHook: async (specifier) => {
    if (specifier === 'my-module') {
      return {
        source: `
          export const greeting = "Hello";
          export function sayHello(name) {
            return greeting + ", " + name + "!";
          }
        `
      };
    }
    throw new Error(`Module not found: ${specifier}`);
  },
  __options__: true
});

// Import module asynchronously
compartment.import('my-module').then(({ namespace }) => {
  console.log(namespace.sayHello('World')); // "Hello, World!"
});

Module Import (Synchronous)

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

/**
 * Synchronously imports a module that's already loaded or can be loaded synchronously
 * @param specifier - Module specifier to import
 * @returns Module namespace object
 */
importNow(specifier: string): ModuleExportsNamespace;

Usage Examples:

import 'ses';

lockdown();

const compartment = new Compartment({
  modules: {
    'math-utils': {
      source: `
        export const add = (a, b) => a + b;
        export const multiply = (a, b) => a * b;
      `
    }
  },
  importNowHook: (specifier) => {
    if (specifier === 'runtime-module') {
      return {
        source: `export const runtime = true;`
      };
    }
  },
  __options__: true
});

// Import pre-loaded module
const mathUtils = compartment.importNow('math-utils');
console.log(mathUtils.add(2, 3)); // 5

// Import via importNowHook
const runtimeMod = compartment.importNow('runtime-module');  
console.log(runtimeMod.runtime); // true

Module Loading

Preloads modules without importing them into the current scope.

/**
 * Preloads a module without importing it
 * @param specifier - Module specifier to load
 * @returns Promise that resolves when module is loaded
 */
load(specifier: string): Promise<void>;

Module Access

Accesses already loaded module namespaces.

/**
 * Gets the namespace of an already loaded module
 * @param specifier - Module specifier
 * @returns Module namespace object
 */
module(specifier: string): ModuleExportsNamespace;

Compartment Properties

Access to compartment metadata and global object.

/**
 * The compartment's global object
 */
get globalThis(): Record<PropertyKey, any>;

/**
 * The compartment's name for debugging
 */
get name(): string;

Usage Examples:

import 'ses';

lockdown();

const compartment = new Compartment({
  name: 'test-compartment',
  globals: { customGlobal: 'test value' },
  __options__: true
});

// Access compartment properties
console.log(compartment.name); // 'test-compartment'
console.log(compartment.globalThis.customGlobal); // 'test value'

// Each compartment has its own global object
const anotherCompartment = new Compartment({ __options__: true });
console.log(compartment.globalThis !== anotherCompartment.globalThis); // true

// But they share the same intrinsics
console.log(compartment.globalThis.Array === anotherCompartment.globalThis.Array); // true

Configuration Options

CompartmentOptions Interface

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

interface CompartmentOptions {
  /** Compartment name for debugging purposes */
  name?: string;
  
  /** Initial global variables for the compartment */
  globals?: Map<string, any>;
  
  /** Static module map for pre-loaded modules */
  modules?: Map<string, ModuleDescriptor>;
  
  /** Source transformation functions applied to evaluated code */
  transforms?: Array<Transform>;
  
  /** Internal shim-specific transforms */
  __shimTransforms__?: Array<Transform>;
  
  /** Module resolution hook for converting import specifiers */
  resolveHook?: ResolveHook;
  
  /** Async module loading hook */
  importHook?: ImportHook;
  
  /** Sync module loading hook */
  importNowHook?: ImportNowHook;
  
  /** Dynamic module mapping hook */
  moduleMapHook?: ModuleMapHook;
  
  /** Hook for customizing import.meta objects */
  importMetaHook?: ImportMetaHook;
  
  /** Use native compartment implementation if available */
  __native__?: boolean;
  
  /** Control namespace boxing behavior */
  __noNamespaceBox__?: boolean;
  
  /** Fail fast on first module loading error */
  noAggregateLoadErrors?: boolean;
}

EvaluateOptions Interface

Options for controlling code evaluation behavior.

interface EvaluateOptions {
  /** Source transformation functions for this evaluation */
  transforms?: Array<Transform>;
  
  /** Allow sloppy mode for legacy code compatibility */
  sloppyGlobalsMode?: boolean;
  
  /** Internal module shim lexical bindings */
  __moduleShimLexicals__?: Record<string, any>;
  
  /** Evade HTML comment test for browser compatibility */
  __evadeHtmlCommentTest__?: boolean;
  
  /** Reject some direct eval expressions for security */
  __rejectSomeDirectEvalExpressions__?: boolean;
}

Advanced Usage Patterns

Cross-Compartment Communication

Secure communication between compartments using hardened objects:

import 'ses';

lockdown();

// Create a shared communication channel
const createChannel = () => {
  const listeners = [];
  return harden({
    send: (message) => {
      listeners.forEach(listener => listener(message));
    },
    listen: (callback) => {
      listeners.push(callback);
    }
  });
};

const channel = createChannel();

// Compartment A - sender
const senderCompartment = new Compartment({
  globals: { channel },
  __options__: true
});

// Compartment B - receiver  
const receiverCompartment = new Compartment({
  globals: { 
    channel,
    console: harden(console)
  },
  __options__: true
});

// Set up receiver
receiverCompartment.evaluate(`
  channel.listen((message) => {
    console.log('Received:', message);
  });
`);

// Send message from sender
senderCompartment.evaluate(`
  channel.send({ type: 'greeting', data: 'Hello from sender!' });
`);

Module Federation

Sharing modules between compartments:

import 'ses';

lockdown();

// Shared module compartment
const moduleCompartment = new Compartment({
  modules: {
    'shared-utils': {
      source: `
        export const utilities = {
          format: (str) => str.toUpperCase(),
          validate: (data) => typeof data === 'string'
        };
      `
    }
  },
  __options__: true
});

// Consumer compartments that reference the shared module
const consumerA = new Compartment({
  modules: {
    'shared-utils': {
      namespace: 'shared-utils',
      compartment: moduleCompartment
    }
  },
  __options__: true
});

const consumerB = new Compartment({
  modules: {
    'shared-utils': {
      namespace: 'shared-utils', 
      compartment: moduleCompartment
    }
  },
  __options__: true
});

// Both compartments can use the shared module
const utilsA = consumerA.importNow('shared-utils');
const utilsB = consumerB.importNow('shared-utils');

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

Capability-Based Security

Implementing fine-grained permissions using object capabilities:

import 'ses';

lockdown();

// Create capability objects
const createFileCapability = (allowedPaths) => harden({
  readFile: (path) => {
    if (!allowedPaths.includes(path)) {
      throw new Error(`Access denied: ${path}`);
    }
    return `Content of ${path}`;
  }
});

const createNetworkCapability = (allowedHosts) => harden({
  fetch: (url) => {
    const hostname = new URL(url).hostname;
    if (!allowedHosts.includes(hostname)) {
      throw new Error(`Network access denied: ${hostname}`);
    }
    return Promise.resolve(`Response from ${url}`);
  }
});

// Create compartment with specific capabilities
const sandboxedCompartment = new Compartment({
  globals: {
    fileSystem: createFileCapability(['/public/data.txt']),
    network: createNetworkCapability(['api.example.com']),
    console: harden(console)
  },
  __options__: true
});

// Code in compartment can only access granted capabilities
sandboxedCompartment.evaluate(`
  try {
    const data = fileSystem.readFile('/public/data.txt'); // Allowed
    console.log('File access:', data);
  } catch (error) {
    console.log('File error:', error.message);
  }
  
  try {
    const data = fileSystem.readFile('/private/secret.txt'); // Denied
    console.log('Should not reach here');
  } catch (error) {
    console.log('Security error:', error.message);
  }
`);

Install with Tessl CLI

npx tessl i tessl/npm-ses

docs

assertions.md

compartments.md

environment-hardening.md

index.md

modules.md

tools.md

tile.json