matchlock-sdk 0.2.9 → 0.2.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -85,6 +85,31 @@ const sandbox = new Sandbox("alpine:latest").withNetworkInterception({
85
85
  - Port forwarding API parity (`portForward`, `portForwardWithAddresses`)
86
86
  - Lifecycle control (`close`, `remove`, `vmId`)
87
87
 
88
+ ## Mounts
89
+
90
+ Mount host directories or use in-memory/snapshot filesystems:
91
+
92
+ ```ts
93
+ import { Client, Sandbox, MountConfig } from "matchlock-sdk";
94
+
95
+ const sandbox = new Sandbox("alpine:latest")
96
+ .mountHostDir("/workspace/src", "/home/user/project/src")
97
+ .mountHostDirReadonly("/workspace/config", "/home/user/project/config")
98
+ .mountMemory("/workspace/tmp")
99
+ .mountOverlay("/workspace/data", "/home/user/project/data")
100
+ // Or use the generic mount() method:
101
+ .mount("/workspace/custom", { type: "host_fs", hostPath: "/tmp/custom" });
102
+ ```
103
+
104
+ Pass `ownerUID` and/or `ownerGID` to have all files in the mount appear owned by a specific user inside the VM. This is useful when the sandbox runs as a non-root user (via `.withUser()`):
105
+
106
+ ```ts
107
+ const sandbox = new Sandbox("alpine:latest")
108
+ .withUser("1000:1000")
109
+ .mountHostDir("/workspace/src", "/home/user/project/src", { ownerUID: 1000, ownerGID: 1000 })
110
+ .mountHostDirReadonly("/workspace/config", "/home/user/project/config", { ownerUID: 1000 });
111
+ ```
112
+
88
113
  ## Development
89
114
 
90
115
  ```bash
package/dist/builder.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { CreateOptions, ImageConfig, MountConfig, NetworkInterceptionConfig, VFSInterceptionConfig } from "./types";
1
+ import type { CreateOptions, ImageConfig, MountConfig, MountOwnerOptions, NetworkInterceptionConfig, VFSInterceptionConfig } from "./types";
2
2
  export declare function cloneCreateOptions(opts: CreateOptions): CreateOptions;
3
3
  export declare class Sandbox {
4
4
  private readonly opts;
@@ -29,8 +29,8 @@ export declare class Sandbox {
29
29
  withPortForward(localPort: number, remotePort: number): Sandbox;
30
30
  withPortForwardAddresses(...addresses: string[]): Sandbox;
31
31
  mount(guestPath: string, config: MountConfig): Sandbox;
32
- mountHostDir(guestPath: string, hostPath: string): Sandbox;
33
- mountHostDirReadonly(guestPath: string, hostPath: string): Sandbox;
32
+ mountHostDir(guestPath: string, hostPath: string, opts?: MountOwnerOptions): Sandbox;
33
+ mountHostDirReadonly(guestPath: string, hostPath: string, opts?: MountOwnerOptions): Sandbox;
34
34
  mountMemory(guestPath: string): Sandbox;
35
35
  mountOverlay(guestPath: string, hostPath: string): Sandbox;
36
36
  withUser(user: string): Sandbox;
package/dist/builder.js CHANGED
@@ -188,11 +188,13 @@ class Sandbox {
188
188
  this.opts.mounts[guestPath] = { ...config };
189
189
  return this;
190
190
  }
191
- mountHostDir(guestPath, hostPath) {
192
- return this.mount(guestPath, { type: "host_fs", hostPath });
191
+ mountHostDir(guestPath, hostPath, opts) {
192
+ const { ownerUID, ownerGID } = validatedMountOwnerOptions(opts);
193
+ return this.mount(guestPath, { type: "host_fs", hostPath, ownerUID, ownerGID });
193
194
  }
194
- mountHostDirReadonly(guestPath, hostPath) {
195
- return this.mount(guestPath, { type: "host_fs", hostPath, readonly: true });
195
+ mountHostDirReadonly(guestPath, hostPath, opts) {
196
+ const { ownerUID, ownerGID } = validatedMountOwnerOptions(opts);
197
+ return this.mount(guestPath, { type: "host_fs", hostPath, readonly: true, ownerUID, ownerGID });
196
198
  }
197
199
  mountMemory(guestPath) {
198
200
  return this.mount(guestPath, { type: "memory" });
@@ -240,3 +242,16 @@ exports.Sandbox = Sandbox;
240
242
  function createSandbox(image) {
241
243
  return new Sandbox(image);
242
244
  }
245
+ function validatedMountOwnerOptions(opts) {
246
+ if (!opts) {
247
+ return {};
248
+ }
249
+ validateID("ownerUID", opts.ownerUID);
250
+ validateID("ownerGID", opts.ownerGID);
251
+ return opts;
252
+ }
253
+ function validateID(name, id) {
254
+ if (id !== undefined && (!Number.isInteger(id) || id < 0 || id > 0xffffffff)) {
255
+ throw new RangeError(`${name} must be an integer in [0, 4294967295], got ${id}`);
256
+ }
257
+ }
@@ -56,6 +56,12 @@ function buildCreateParams(options, wireVFS, wireNetworkInterception) {
56
56
  if (config.readonly) {
57
57
  mount.readonly = true;
58
58
  }
59
+ if (config.ownerUID !== undefined) {
60
+ mount.owner_uid = config.ownerUID;
61
+ }
62
+ if (config.ownerGID !== undefined) {
63
+ mount.owner_gid = config.ownerGID;
64
+ }
59
65
  mounts[guestPath] = mount;
60
66
  }
61
67
  vfs.mounts = mounts;
package/dist/index.d.ts CHANGED
@@ -2,4 +2,4 @@ export { Client, defaultConfig } from "./client";
2
2
  export { Sandbox, createSandbox } from "./builder";
3
3
  export { MatchlockError, RPCError } from "./errors";
4
4
  export { NETWORK_HOOK_ACTION_ALLOW, NETWORK_HOOK_ACTION_BLOCK, NETWORK_HOOK_ACTION_MUTATE, NETWORK_HOOK_PHASE_AFTER, NETWORK_HOOK_PHASE_BEFORE, VFS_HOOK_ACTION_ALLOW, VFS_HOOK_ACTION_BLOCK, VFS_HOOK_OP_STAT, VFS_HOOK_OP_READDIR, VFS_HOOK_OP_OPEN, VFS_HOOK_OP_CREATE, VFS_HOOK_OP_MKDIR, VFS_HOOK_OP_CHMOD, VFS_HOOK_OP_REMOVE, VFS_HOOK_OP_REMOVE_ALL, VFS_HOOK_OP_RENAME, VFS_HOOK_OP_SYMLINK, VFS_HOOK_OP_READLINK, VFS_HOOK_OP_READ, VFS_HOOK_OP_WRITE, VFS_HOOK_OP_CLOSE, VFS_HOOK_OP_SYNC, VFS_HOOK_OP_TRUNCATE, VFS_HOOK_PHASE_BEFORE, VFS_HOOK_PHASE_AFTER, } from "./types";
5
- export type { BinaryLike, Config, CreateOptions, ExecInteractiveOptions, ExecInteractiveResult, ExecOptions, ExecPipeOptions, ExecPipeResult, ExecResult, ExecStreamOptions, ExecStreamResult, FileInfo, VolumeInfo, HostIPMapping, ImageConfig, LogStreamOptions, MountConfig, NetworkBodyTransform, NetworkHookFunc, NetworkHookRequest, NetworkHookRequestMutation, NetworkHookResponseMutation, NetworkHookResult, NetworkHookAction, NetworkHookPhase, NetworkHookRule, NetworkInterceptionConfig, PortForward, PortForwardBinding, RequestOptions, Secret, TTYSize, StreamWriter, StreamReader, VFSActionHookFunc, VFSActionRequest, VFSDangerousHookFunc, VFSHookAction, VFSHookEvent, VFSHookFunc, VFSHookOp, VFSHookPhase, VFSHookRule, VFSInterceptionConfig, VFSMutateHookFunc, VFSMutateRequest, } from "./types";
5
+ export type { BinaryLike, Config, CreateOptions, ExecInteractiveOptions, ExecInteractiveResult, ExecOptions, ExecPipeOptions, ExecPipeResult, ExecResult, ExecStreamOptions, ExecStreamResult, FileInfo, VolumeInfo, HostIPMapping, ImageConfig, LogStreamOptions, MountConfig, MountOwnerOptions, NetworkBodyTransform, NetworkHookFunc, NetworkHookRequest, NetworkHookRequestMutation, NetworkHookResponseMutation, NetworkHookResult, NetworkHookAction, NetworkHookPhase, NetworkHookRule, NetworkInterceptionConfig, PortForward, PortForwardBinding, RequestOptions, Secret, TTYSize, StreamWriter, StreamReader, VFSActionHookFunc, VFSActionRequest, VFSDangerousHookFunc, VFSHookAction, VFSHookEvent, VFSHookFunc, VFSHookOp, VFSHookPhase, VFSHookRule, VFSInterceptionConfig, VFSMutateHookFunc, VFSMutateRequest, } from "./types";
package/dist/types.d.ts CHANGED
@@ -41,6 +41,15 @@ export interface MountConfig {
41
41
  type?: string;
42
42
  hostPath?: string;
43
43
  readonly?: boolean;
44
+ ownerUID?: number;
45
+ ownerGID?: number;
46
+ }
47
+ /** Options accepted by {@link Sandbox.mountHostDir} and {@link Sandbox.mountHostDirReadonly}. */
48
+ export interface MountOwnerOptions {
49
+ /** UID reported for all files in this mount inside the VM. Must be in [0, 4294967295]. */
50
+ ownerUID?: number;
51
+ /** GID reported for all files in this mount inside the VM. Must be in [0, 4294967295]. */
52
+ ownerGID?: number;
44
53
  }
45
54
  export interface Secret {
46
55
  name: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "matchlock-sdk",
3
- "version": "0.2.9",
3
+ "version": "0.2.11",
4
4
  "description": "TypeScript SDK for Matchlock sandboxes",
5
5
  "license": "MIT",
6
6
  "repository": {