import { type SandboxEnvironmentFact } from "./environment-facts.ts"; import { SandboxBlobStorageError, type SandboxBlobStorageErrorCode } from "./host-process.ts"; import { createMemoryFileSystem } from "./memory-fs.ts"; import type { HostBlobStorageProvider, HostBlobVolumeOptions } from "./spawn-options.ts"; import type { Request, Response } from "undici"; export type { SandboxCommandEnvironmentFact, SandboxDistroEnvironmentFact, SandboxDistroVersion, SandboxDistroVersionEnvironmentFact, SandboxEnvironmentCommand, SandboxEnvironmentFact, SandboxEnvironmentFactSource, SandboxNetworkEgressEnvironmentFact, SandboxPackageManagerEnvironmentFact, SandboxRootfsEnvironmentFact, SandboxRootfsImageEnvironmentFact, SandboxShellEnvironmentFact, } from "./environment-facts.ts"; export { Request, Response } from "undici"; export type SandboxFileType = "file" | "directory" | "symlink"; export type SandboxFileStat = { readonly type: SandboxFileType; readonly sizeBytes: number | null; readonly mediaType: string | null; readonly modifiedAtMs: number | null; readonly writable?: boolean; }; export { SandboxBlobStorageError, type SandboxBlobStorageErrorCode }; export type SandboxDirectoryEntry = { readonly name: string; readonly type: SandboxFileType; }; export interface SandboxFileSystem { stat(path: string): Promise; list(path: string): Promise; read(input: { readonly path: string; readonly range?: { readonly offset: number; readonly length: number; }; readonly signal: AbortSignal; }): Promise; } export interface SandboxWritableFileSystem extends SandboxFileSystem { createFile(path: string): Promise; write(input: { readonly path: string; readonly offset: number; readonly contents: Uint8Array; }): Promise; truncate(path: string, size: number): Promise; } export interface SandboxPosixFileSystem extends SandboxWritableFileSystem { mkdir(path: string): Promise; unlink(path: string): Promise; rmdir(path: string): Promise; rename(from: string, to: string, flags?: number): Promise; link(from: string, to: string): Promise; symlink(target: string, path: string): Promise; readlink(path: string): Promise; setxattr(path: string, name: string, value: Uint8Array, flags?: number): Promise; getxattr(path: string, name: string): Promise; listxattr(path: string): Promise; removexattr(path: string, name: string): Promise; } export interface MemoryFileSystemOptions { readonly files?: Readonly>; } /** * HTTP request metadata exposed to HTTP network policy middleware. * * The request is already classified as HTTP or HTTPS and can be inspected or * mutated before it is forwarded upstream. */ export interface SandboxHttpRequest { /** HTTP version used by the intercepted request. */ readonly protocol: "http/1.1" | "h2"; /** Absolute URL reconstructed from the request target and destination metadata. */ readonly url: URL; /** HTTP method exactly as received from the guest. */ readonly method: string; /** Mutable request headers. Changes are applied before forwarding upstream. */ readonly headers: Headers; /** IP-layer addressing observed for the connection carrying this request. */ readonly destination: { /** Guest source IP address for the connection carrying this request. */ readonly sourceIp: string; /** Guest source port for the connection carrying this request. */ readonly sourcePort: number; /** Original destination IP address before host-side routing or proxying. */ readonly originalIp: string; /** Original destination port before host-side routing or proxying. */ readonly originalPort: number; /** * Hostname pinned by trusted connection metadata, when known. * * For cleartext HTTP this is populated only from the sandbox DNS answer * that resolved the destination IP. For HTTPS, use `tls.sni` for the * client-provided server name. The HTTP `Host` header is not trusted for * this field. */ readonly hostname?: string; }; /** TLS metadata when the request was carried over HTTPS. */ readonly tls?: { /** Server Name Indication sent by the guest, when present. */ readonly sni?: string; /** Negotiated ALPN protocol, when present. */ readonly alpn?: string; }; } /** * Plain-data descriptor for an immutable QCOW2 root filesystem image. * * Image packages export this shape directly and remain runtime-independent * from the core Sandbox package. */ export type RootfsImageConfig = { readonly kind: "rootfs-image"; readonly name: string; readonly path: string; readonly format: "qcow2"; readonly architecture: NodeJS.Architecture; readonly digest: `sha256:${string}`; readonly sizeBytes: bigint; readonly facts: readonly SandboxEnvironmentFact[]; }; export type ComposedRootfsConfig = { readonly kind: "composed-rootfs"; readonly base: RootfsImageConfig; readonly overlay: SandboxBlockStore | SandboxBlobOverlay; }; export type CowRootfsConfig = { readonly kind: "cow-rootfs"; readonly source: ComposedRootfsConfig; readonly maxDirtyBytes?: number; }; export type EphemeralRootfsConfig = { readonly kind: "ephemeral-rootfs"; readonly base: RootfsImageConfig; readonly maxDirtyBytes?: number; }; export type PersistentRootfsConfig = { readonly kind: "persistent-rootfs"; readonly base: RootfsImageConfig; readonly path: string; }; export type Rootfs = RootfsImageConfig | CowRootfsConfig | EphemeralRootfsConfig | PersistentRootfsConfig; export type Qcow2RootfsImage = { readonly kind: "flattened-rootfs-image"; readonly format: "qcow2"; readonly sizeBytes: bigint; }; export type SandboxFileSystemSource = { readonly kind: "virtual-fs"; readonly fileSystem: SandboxFileSystem; }; export type SandboxWritableFileSystemSource = { readonly kind: "virtual-fs"; readonly fileSystem: SandboxPosixFileSystem; }; export type SandboxHostDirectoryMaskStorageSource = { readonly kind: "host-directory"; readonly source: string; readonly access: "rw"; }; export type SandboxReadOnlyHostDirectoryMask = { readonly paths: readonly string[]; }; export type SandboxReadWriteHostDirectoryMask = { readonly paths: readonly string[]; readonly storage: SandboxHostDirectoryMaskStorageSource; }; export type SandboxReadOnlyHostDirectorySource = { readonly kind: "host-directory"; readonly source: string; readonly access: "ro"; readonly mask?: SandboxReadOnlyHostDirectoryMask; }; export type SandboxReadWriteHostDirectorySource = { readonly kind: "host-directory"; readonly source: string; readonly access: "rw"; readonly mask?: SandboxReadWriteHostDirectoryMask; }; export type SandboxHostDirectorySource = SandboxReadOnlyHostDirectorySource | SandboxReadWriteHostDirectorySource; export type SandboxBlobStorageProvider = HostBlobStorageProvider; /** A declarative, object-backed writable rootfs overlay. */ export interface SandboxBlobOverlay { readonly kind: "blob-overlay"; } /** A declarative, object-backed guest block device. */ export interface SandboxBlobBlockDevice { readonly kind: "blob-block-device"; } export type SandboxBlobOverlayOptions = Omit; export type SandboxBlobBlockOptions = HostBlobVolumeOptions; export type SandboxMountSource = SandboxFileSystemSource | SandboxHostDirectorySource | SandboxBlobBlockDevice; export type SandboxBlockRange = { readonly start: bigint; readonly count: number; }; export type SandboxBlockChunk = { readonly start: bigint; readonly data: Uint8Array; }; export type SandboxBlockStoreContext = { readonly base: string; }; export interface SandboxBlockStore { readonly blockSize: number; list(context: SandboxBlockStoreContext): Promise; read(range: SandboxBlockRange, context: SandboxBlockStoreContext): Promise; /** * Receives block bytes owned by the block store. Sandbox will not mutate * chunk data after calling write(), so stores may retain those arrays. */ write(chunks: readonly SandboxBlockChunk[], context: SandboxBlockStoreContext): Promise; flush?(context: SandboxBlockStoreContext): Promise; } /** Object storage declarations resolved and owned by Sandbox during boot. */ export declare const storage: { readonly blob: { overlay(options: SandboxBlobOverlayOptions): SandboxBlobOverlay; block(options: SandboxBlobBlockOptions): SandboxBlobBlockDevice; }; }; /** * Middleware invoked for an HTTP request allowed by a network policy. * * Middleware may mutate `request.headers` to add, replace, or remove outbound * request headers before the request leaves the sandbox boundary. */ export type HttpRequestMiddleware = (request: SandboxHttpRequest) => void | Promise; /** * Opaque grant returned by `conn.accept()`. * * Grants intentionally carry no public fields today. They reserve a stable * extension point for future instance-local grant state. */ export interface NetworkGrant { } /** * Opaque grant returned by `conn.acceptHttp(...)`. * * HTTP grants are distinct from generic network grants so future HTTP-specific * policy state can remain type-safe. */ export interface HttpNetworkGrant extends NetworkGrant { } /** IP transport observed by the network policy hook. */ export type NetworkTransport = "tcp" | "udp"; /** Endpoint accepted by transport match helpers. */ export type NetworkEndpointSpec = `${string}:${number}` | { /** Numeric destination IP address. */ readonly ip: string; /** Destination transport port. */ readonly port: number; }; /** Upstream DNS resolver used to answer an accepted DNS flow. */ export type DnsUpstreamResolver = string | { /** Numeric upstream resolver IP address. */ readonly ip: string; /** Upstream resolver port. Defaults to 53. */ readonly port?: number; }; /** Options for accepting a matched DNS flow. */ export interface DnsAcceptOptions { /** * Ordered upstream resolvers used to answer this DNS query. Omit to use the * host environment resolver. */ readonly resolvers?: readonly DnsUpstreamResolver[]; } /** HTTP authority accepted by HTTP match helpers. */ export type HttpAuthoritySpec = string | { /** Trusted HTTP authority hostname. */ readonly hostname: string; /** Trusted HTTP authority port. Omit to match any port. */ readonly port?: number; }; /** Synchronous predicate used by protocol-specific match helpers. */ export type NetworkMatchPredicate = (candidate: TMatch) => boolean; /** * Source or destination endpoint for a network policy event. * * Endpoint helpers classify the IP address only. They do not use DNS names, * HTTP host headers, TLS SNI, or any other application-layer metadata. */ export interface NetworkEndpoint { /** Numeric IP address observed at the sandbox network boundary. */ readonly ip: string; /** Transport-layer port observed at the sandbox network boundary. */ readonly port: number; /** True for IPv4 and IPv6 loopback addresses. */ isLoopback(): boolean; /** True for private-use address ranges such as RFC 1918 and IPv6 ULA. */ isPrivate(): boolean; /** True for link-local address ranges. */ isLinkLocal(): boolean; /** True for multicast address ranges. */ isMulticast(): boolean; /** True for the IPv4 limited broadcast address. */ isBroadcast(): boolean; /** True for documentation and example address ranges. */ isDocumentation(): boolean; /** True for reserved or otherwise non-public address ranges. */ isReserved(): boolean; /** True when the address is not classified as local, private, reserved, or documentation. */ isPublicInternet(): boolean; } /** * Capability returned when a DNS flow matches a policy predicate. * * DNS matching normalizes DNS over UDP and DNS over TCP. `accept()` permits the * matched DNS flow using the transport semantics observed by the runtime. */ export interface DnsConnectionMatch { /** Source endpoint observed at the sandbox network boundary. */ readonly src: NetworkEndpoint; /** Internal DNS endpoint observed at the sandbox network boundary. */ readonly dst: NetworkEndpoint; /** IP transport carrying this DNS flow. */ readonly transport: NetworkTransport; /** Accepts this matched DNS flow. */ accept(options?: DnsAcceptOptions): NetworkGrant; } /** * Capability returned when a raw TCP endpoint matches a policy predicate. */ export interface TcpConnectionMatch { /** Source endpoint observed at the sandbox network boundary. */ readonly src: TcpNetworkEndpoint; /** Destination endpoint observed at the sandbox network boundary. */ readonly dst: TcpNetworkEndpoint; /** Accepts this matched TCP flow without protocol-specific enforcement. */ accept(): NetworkGrant; } /** * Capability returned when a raw UDP endpoint matches a policy predicate. */ export interface UdpConnectionMatch { /** Source endpoint observed at the sandbox network boundary. */ readonly src: UdpNetworkEndpoint; /** Destination endpoint observed at the sandbox network boundary. */ readonly dst: UdpNetworkEndpoint; /** Accepts this matched UDP flow. */ accept(): NetworkGrant; } /** * Capability returned when trusted connection metadata matches an HTTP * authority predicate. * * This match does not trust the HTTP `Host` header. `accept(...)` still routes * the TCP flow through Sandbox's HTTP-family enforcement path, so non-HTTP * traffic fails closed even if its destination metadata matched. */ export interface HttpConnectionMatch { /** Source endpoint observed at the sandbox network boundary. */ readonly src: TcpNetworkEndpoint; /** Destination endpoint observed at the sandbox network boundary. */ readonly dst: TcpNetworkEndpoint; /** Trusted hostname for the HTTP authority. */ readonly hostname: string; /** Destination port for the HTTP authority. */ readonly port: number; /** Accepts this matched HTTP-family flow with optional request middleware. */ accept(middleware?: HttpRequestMiddleware): HttpNetworkGrant; } /** TCP endpoint for a TCP network policy event. */ export interface TcpNetworkEndpoint extends NetworkEndpoint { readonly port: number; } /** UDP endpoint for a UDP network policy event. */ export interface UdpNetworkEndpoint extends NetworkEndpoint { readonly port: number; } /** * Common fields shared by all network policy events. * * `transport` is the only stable discriminant. Higher-level protocol semantics * are opt-in through protocol-specific accept helpers. */ export interface NetworkConnectionRequestBase { /** IP transport that carried this event. Narrows TCP vs UDP request shapes. */ readonly transport: TTransport; /** Source endpoint observed at the sandbox network boundary. */ readonly src: NetworkEndpoint; /** Destination endpoint observed at the sandbox network boundary. */ readonly dst: NetworkEndpoint; /** * Accepts this observed connection, request, or flow using transport-level * semantics. */ accept(): NetworkGrant; /** * Returns a DNS capability when this policy event is DNS traffic. */ matchDns(): DnsConnectionMatch | undefined; /** * Returns an HTTP capability when this TCP connection has trusted destination * metadata matching the authority predicate. Returns `undefined` for non-TCP * policy events. * * This helper does not classify arbitrary bytes as HTTP and does not inspect * the HTTP `Host` header. Use the returned capability's `accept(...)` method * to enter HTTP-family enforcement. */ matchHttp(matcher: HttpAuthoritySpec | NetworkMatchPredicate): HttpConnectionMatch | undefined; } /** * TCP transport policy event. * * This event grants or denies TCP reachability for the observed flow. */ export interface TcpNetworkConnectionRequest extends NetworkConnectionRequestBase<"tcp"> { readonly src: TcpNetworkEndpoint; readonly dst: TcpNetworkEndpoint; /** * Accepts this TCP flow only through Sandbox's HTTP-family enforcement path. * * If the flow is not HTTP or HTTPS, the connection fails closed. Plain * `accept()` leaves bytes untouched and never enters HTTP middleware or MITM. */ acceptHttp(middleware?: HttpRequestMiddleware): HttpNetworkGrant; /** * Returns a raw TCP capability when this connection matches the endpoint * predicate. */ matchTcp(matcher: NetworkEndpointSpec | NetworkMatchPredicate): TcpConnectionMatch | undefined; } /** * UDP transport policy event. * * UDP is connectionless, so `accept()` permits the observed UDP flow according * to the runtime's flow-tracking semantics rather than establishing a stream. */ export interface UdpNetworkConnectionRequest extends NetworkConnectionRequestBase<"udp"> { readonly src: UdpNetworkEndpoint; readonly dst: UdpNetworkEndpoint; /** * Returns a raw UDP capability when this datagram flow matches the endpoint * predicate. */ matchUdp(matcher: NetworkEndpointSpec | NetworkMatchPredicate): UdpConnectionMatch | undefined; } /** * Network policy event passed to `network.policy(...)`. * * Use `transport` to branch on TCP vs UDP. Protocol-specific behavior is only * entered through explicit helpers such as `acceptHttp(...)`. */ export type NetworkConnectionRequest = TcpNetworkConnectionRequest | UdpNetworkConnectionRequest; /** Callback invoked whenever the sandbox asks user policy to allow network egress. */ export type NetworkConnectionRequestHandler = (connection: NetworkConnectionRequest) => void | Promise; declare const networkPolicyHandler: unique symbol; export type NetworkPolicy = { /** Identifies this value as a network policy definition. */ readonly kind: "network-policy"; readonly [networkPolicyHandler]: NetworkConnectionRequestHandler; }; export interface SandboxDefinitionOptions { readonly rootfs: Rootfs; readonly resources?: SandboxResourceLimits; readonly network?: NetworkPolicy; } export interface SandboxResourceLimits { readonly cpus?: number; readonly memoryMiB?: number; } export interface SandboxBootOptions { readonly mounts?: Readonly>; readonly cwd?: string; readonly hostname?: string; } export interface SandboxDefinition { /** * Returns facts recoverable from sandbox configuration without launching a VM. */ environmentFacts(): readonly SandboxEnvironmentFact[]; boot(options?: SandboxBootOptions): Promise; } export interface SandboxExecOptions { readonly cwd?: string; readonly env?: Record; /** * Maximum wall-clock runtime for the guest process. When the timeout expires, * Sandbox terminates the guest process group and returns exit code 124. */ readonly timeoutMs?: number; readonly signal?: AbortSignal; } export interface SandboxSpawnOptions { readonly cwd?: string; readonly env?: Record; /** * Unique file descriptors, numbered 3 or above, to expose as full-duplex * channels in both the guest process and `SandboxProcess.pipes`. */ readonly pipes?: readonly number[]; readonly signal?: AbortSignal; } export interface SandboxPtyOptions { readonly cwd?: string; readonly env?: Record; readonly size: SandboxPtySize; readonly signal?: AbortSignal; } export interface SandboxPtySize { readonly rows: number; readonly cols: number; } export interface SandboxExecResult { readonly exitCode: number; readonly stdout: string; readonly stderr: string; } export interface SandboxProcess { readonly stdin: WritableStream; readonly stdout: ReadableStream; readonly stderr: ReadableStream; /** Full-duplex channels keyed by the descriptors requested at spawn. */ readonly pipes: ReadonlyMap; readonly ready: Promise; readonly exit: Promise; kill(signal?: SandboxSignal): void; } export interface SandboxProcessPipe { readonly input: WritableStream; readonly output: ReadableStream; } export interface SandboxPty { readonly input: WritableStream; readonly output: ReadableStream; readonly ready: Promise; readonly exit: Promise; resize(size: SandboxPtySize): void; kill(signal?: SandboxSignal): void; } export interface SandboxProcessExit { readonly exitCode: number | null; readonly signal: SandboxSignal | null; } export type SandboxSignal = "SIGHUP" | "SIGINT" | "SIGQUIT" | "SIGTERM" | "SIGKILL"; export type SandboxFsEntryType = "file" | "directory" | "symlink" | "other"; export type SandboxFsStat = { readonly type: SandboxFsEntryType; readonly sizeBytes: number; readonly modifiedAtMs: number; }; export type SandboxFsDirectoryEntry = { /** * UTF-8 filename for ordinary entries. If the guest filename is not valid * UTF-8, replacement characters are used and `nameBytes` remains exact. */ readonly name: string; /** * Exact filename bytes as reported by the guest directory entry. */ readonly nameBytes: Uint8Array; readonly stat: SandboxFsStat; }; export interface SandboxReadFileOptions { readonly range?: { readonly offset: number; readonly length: number; }; } export interface SandboxWriteFileOptions { readonly createParents?: boolean; } export interface SandboxMkdirOptions { readonly recursive?: boolean; } export interface SandboxRemoveOptions { readonly recursive?: boolean; readonly force?: boolean; } export interface SandboxGuestFileSystem { /** * Returns metadata for an absolute guest path without following symlinks. */ stat(path: string): Promise; /** * Lists a directory and includes metadata for each entry in the same guest * round trip. */ readDir(path: string): Promise; /** * Reads a full file, or the byte range selected by `options.range`. */ readFile(path: string, options?: SandboxReadFileOptions): Promise; /** * Creates or replaces a file. `createParents` creates missing parent * directories before writing. */ writeFile(path: string, contents: string | Uint8Array, options?: SandboxWriteFileOptions): Promise; /** * Creates a directory. `recursive` matches `mkdir -p` semantics. */ mkdir(path: string, options?: SandboxMkdirOptions): Promise; /** * Removes a file, symlink, or directory. `recursive` permits non-empty * directory trees. `force` suppresses missing-target errors only. */ remove(path: string, options?: SandboxRemoveOptions): Promise; /** * Renames a path in one guest operation. Parent directories are not created; * the target parent must already exist. */ rename(from: string, to: string): Promise; } export declare class SandboxFileSystemError extends Error { readonly code?: string; constructor(message: string, code?: string); } export interface SandboxInstance { readonly fs: SandboxGuestFileSystem; /** * Performs an HTTP request through the guest runtime and its network policy. */ fetch(request: Request): Promise; /** * Returns config-derived facts plus facts observed from the running guest. */ environmentFacts(): Promise; exec(command: string, args?: readonly string[], options?: SandboxExecOptions): Promise; spawn(command: string, args?: readonly string[], options?: SandboxSpawnOptions): SandboxProcess; pty(command: string, options: SandboxPtyOptions): SandboxPty; pty(command: string, args: readonly string[] | undefined, options: SandboxPtyOptions): SandboxPty; close(): Promise; [Symbol.asyncDispose](): Promise; } export declare const rootfs: { compose(options: { readonly base: RootfsImageConfig; readonly overlay: SandboxBlockStore | SandboxBlobOverlay; }): ComposedRootfsConfig; cow(options: { readonly source: ComposedRootfsConfig; readonly maxDirtyBytes?: number; } | { readonly base: RootfsImageConfig; readonly writable: SandboxBlockStore | SandboxBlobOverlay; readonly maxDirtyBytes?: number; }): Rootfs; ephemeral(options: { readonly base: RootfsImageConfig; readonly maxDirtyBytes?: number; }): Rootfs; persistent(options: { readonly base: RootfsImageConfig; readonly path: string; }): Rootfs; flatten(options: { readonly format: "qcow2"; readonly source: RootfsImageConfig | ComposedRootfsConfig; readonly dest: SandboxBlockStore; readonly clusterSize?: number; }): Promise; bytes(image: RootfsImageConfig | Qcow2RootfsImage, options?: { readonly chunkSize?: number; readonly signal?: AbortSignal; }): AsyncIterable; }; declare function virtualFs(fileSystem: SandboxPosixFileSystem): SandboxWritableFileSystemSource; declare function virtualFs(fileSystem: SandboxFileSystem): SandboxFileSystemSource; /** * Describes a native host-directory bind. On macOS, the sandbox-host effective * identity appears as guest root while unrelated host IDs appear as 65534. * Guest-owned Linux metadata is persisted privately without changing host * ownership or mode. The descriptor is pure; backing-volume checks occur at * boot. */ declare function bindHostDirectory(options: { readonly source: string; readonly access: "ro"; readonly mask?: SandboxReadOnlyHostDirectoryMask; }): SandboxReadOnlyHostDirectorySource; declare function bindHostDirectory(options: { readonly source: string; readonly access: "rw"; readonly mask?: SandboxReadWriteHostDirectoryMask; }): SandboxReadWriteHostDirectorySource; declare function bindHostDirectory(options: { readonly source: string; readonly access: "ro" | "rw"; }): SandboxHostDirectorySource; export declare const fs: { memory: typeof createMemoryFileSystem; virtual: typeof virtualFs; bind: typeof bindHostDirectory; }; export declare const network: { policy(onConnectionRequest: NetworkConnectionRequestHandler): NetworkPolicy; }; export declare function defineSandbox(options: SandboxDefinitionOptions): SandboxDefinition; //# sourceMappingURL=index.d.ts.map