@mastra/docker 0.1.0 → 0.2.0-alpha.0
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/CHANGELOG.md +23 -0
- package/dist/index.cjs +249 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +249 -1
- package/dist/index.js.map +1 -1
- package/dist/provider.d.ts +25 -0
- package/dist/provider.d.ts.map +1 -1
- package/dist/sandbox/index.d.ts +46 -0
- package/dist/sandbox/index.d.ts.map +1 -1
- package/package.json +9 -9
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# @mastra/docker
|
|
2
2
|
|
|
3
|
+
## 0.2.0-alpha.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Docker sandbox containers now support resource limits and security hardening through Docker HostConfig options. Configure memory, CPU quota, process IDs, capabilities, security options, read-only root filesystems, and tmpfs mounts. ([#16577](https://github.com/mastra-ai/mastra/pull/16577))
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
const sandbox = new DockerSandbox({
|
|
11
|
+
memory: 512 * 1024 * 1024,
|
|
12
|
+
memorySwap: 512 * 1024 * 1024,
|
|
13
|
+
cpuQuota: 100_000,
|
|
14
|
+
pidsLimit: 256,
|
|
15
|
+
readonlyRootfs: true,
|
|
16
|
+
capDrop: ['ALL'],
|
|
17
|
+
securityOpt: ['no-new-privileges:true'],
|
|
18
|
+
});
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Patch Changes
|
|
22
|
+
|
|
23
|
+
- Updated dependencies [[`fceae1f`](https://github.com/mastra-ai/mastra/commit/fceae1f5f5db4722cb078a663c6eb4bd22944123), [`bf02acb`](https://github.com/mastra-ai/mastra/commit/bf02acbb8a6110f638ac844e89f1ebf04cb7fe74), [`0fd3fbe`](https://github.com/mastra-ai/mastra/commit/0fd3fbe40fb63657aedd72f6e7b38c8e8ee6940d), [`fed0475`](https://github.com/mastra-ai/mastra/commit/fed0475ccfea31e4fc251469ac05640d0742c1f0), [`522f44d`](https://github.com/mastra-ai/mastra/commit/522f44d947214bfc06cff50599bae1ef3494880d)]:
|
|
24
|
+
- @mastra/core@1.34.0-alpha.1
|
|
25
|
+
|
|
3
26
|
## 0.1.0
|
|
4
27
|
|
|
5
28
|
### Minor Changes
|
package/dist/index.cjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var util = require('util');
|
|
3
4
|
var workspace = require('@mastra/core/workspace');
|
|
4
5
|
var Docker = require('dockerode');
|
|
5
6
|
|
|
@@ -275,6 +276,19 @@ var DockerSandbox = class extends workspace.MastraSandbox {
|
|
|
275
276
|
_volumes;
|
|
276
277
|
_network;
|
|
277
278
|
_privileged;
|
|
279
|
+
_privilegedWasSet;
|
|
280
|
+
_memory;
|
|
281
|
+
_memorySwap;
|
|
282
|
+
_cpuShares;
|
|
283
|
+
_cpuQuota;
|
|
284
|
+
_cpuPeriod;
|
|
285
|
+
_pidsLimit;
|
|
286
|
+
_readonlyRootfs;
|
|
287
|
+
_capDrop;
|
|
288
|
+
_capAdd;
|
|
289
|
+
_securityOpt;
|
|
290
|
+
_ulimits;
|
|
291
|
+
_tmpfs;
|
|
278
292
|
_workingDir;
|
|
279
293
|
_labels;
|
|
280
294
|
_instructionsOverride;
|
|
@@ -295,6 +309,19 @@ var DockerSandbox = class extends workspace.MastraSandbox {
|
|
|
295
309
|
this._volumes = options.volumes ?? {};
|
|
296
310
|
this._network = options.network;
|
|
297
311
|
this._privileged = options.privileged ?? false;
|
|
312
|
+
this._privilegedWasSet = options.privileged !== void 0;
|
|
313
|
+
this._memory = options.memory;
|
|
314
|
+
this._memorySwap = options.memorySwap;
|
|
315
|
+
this._cpuShares = options.cpuShares;
|
|
316
|
+
this._cpuQuota = options.cpuQuota;
|
|
317
|
+
this._cpuPeriod = options.cpuPeriod;
|
|
318
|
+
this._pidsLimit = options.pidsLimit;
|
|
319
|
+
this._readonlyRootfs = options.readonlyRootfs;
|
|
320
|
+
this._capDrop = options.capDrop;
|
|
321
|
+
this._capAdd = options.capAdd;
|
|
322
|
+
this._securityOpt = options.securityOpt;
|
|
323
|
+
this._ulimits = options.ulimits;
|
|
324
|
+
this._tmpfs = options.tmpfs;
|
|
298
325
|
this._workingDir = options.workingDir ?? "/workspace";
|
|
299
326
|
this._labels = {
|
|
300
327
|
...options.labels,
|
|
@@ -324,6 +351,8 @@ var DockerSandbox = class extends workspace.MastraSandbox {
|
|
|
324
351
|
this.logger.debug(`${LOG_PREFIX} Found existing container ${existing.Id}`);
|
|
325
352
|
this._container = this._docker.getContainer(existing.Id);
|
|
326
353
|
const info = await this._container.inspect();
|
|
354
|
+
this._warnOnPrivilegedHardeningConflict(info.HostConfig?.Privileged ?? this._privileged);
|
|
355
|
+
this._warnOnReconnectedHostConfigMismatch(existing.Id, info.HostConfig);
|
|
327
356
|
const actualState = info.State?.Running ? "running" : "stopped";
|
|
328
357
|
if (actualState !== "running") {
|
|
329
358
|
this.logger.debug(`${LOG_PREFIX} Container exists but not running (${actualState}), starting...`);
|
|
@@ -333,6 +362,7 @@ var DockerSandbox = class extends workspace.MastraSandbox {
|
|
|
333
362
|
this.logger.debug(`${LOG_PREFIX} Reconnected to container ${existing.Id}`);
|
|
334
363
|
return;
|
|
335
364
|
}
|
|
365
|
+
this._warnOnPrivilegedHardeningConflict(this._privileged);
|
|
336
366
|
await this._ensureImage();
|
|
337
367
|
const envArray = Object.entries(this._env).map(([k, v]) => `${k}=${v}`);
|
|
338
368
|
const binds = Object.entries(this._volumes).map(([host, container]) => `${host}:${container}`);
|
|
@@ -346,7 +376,19 @@ var DockerSandbox = class extends workspace.MastraSandbox {
|
|
|
346
376
|
HostConfig: {
|
|
347
377
|
Binds: binds.length > 0 ? binds : void 0,
|
|
348
378
|
NetworkMode: this._network,
|
|
349
|
-
Privileged: this._privileged
|
|
379
|
+
Privileged: this._privileged,
|
|
380
|
+
Memory: this._memory,
|
|
381
|
+
MemorySwap: this._memorySwap,
|
|
382
|
+
CpuShares: this._cpuShares,
|
|
383
|
+
CpuQuota: this._cpuQuota,
|
|
384
|
+
CpuPeriod: this._cpuPeriod,
|
|
385
|
+
PidsLimit: this._pidsLimit,
|
|
386
|
+
ReadonlyRootfs: this._readonlyRootfs,
|
|
387
|
+
CapDrop: this._capDrop,
|
|
388
|
+
CapAdd: this._capAdd,
|
|
389
|
+
SecurityOpt: this._securityOpt,
|
|
390
|
+
Ulimits: this._ulimits?.map(toDockerUlimit),
|
|
391
|
+
Tmpfs: this._tmpfs
|
|
350
392
|
},
|
|
351
393
|
// Keep stdin open for interactive use
|
|
352
394
|
OpenStdin: true,
|
|
@@ -356,6 +398,64 @@ var DockerSandbox = class extends workspace.MastraSandbox {
|
|
|
356
398
|
this.processes.setContainer(this._container);
|
|
357
399
|
this.logger.debug(`${LOG_PREFIX} Container started: ${this._container.id}`);
|
|
358
400
|
}
|
|
401
|
+
_warnOnPrivilegedHardeningConflict(effectivePrivileged) {
|
|
402
|
+
if (!effectivePrivileged) return;
|
|
403
|
+
const conflictedHostConfigFields = [
|
|
404
|
+
this._capDrop && this._capDrop.length > 0 ? "CapDrop" : void 0,
|
|
405
|
+
this._capAdd && this._capAdd.length > 0 ? "CapAdd" : void 0,
|
|
406
|
+
this._securityOpt && this._securityOpt.length > 0 ? "SecurityOpt" : void 0
|
|
407
|
+
].filter((field) => field !== void 0);
|
|
408
|
+
if (conflictedHostConfigFields.length === 0) return;
|
|
409
|
+
const optionNames = conflictedHostConfigFields.map(toDockerSandboxOptionName);
|
|
410
|
+
this.logger.warn(
|
|
411
|
+
`${LOG_PREFIX} Privileged containers can bypass some requested hardening controls: ${optionNames.join(", ")}`,
|
|
412
|
+
{ fields: optionNames, hostConfigFields: conflictedHostConfigFields }
|
|
413
|
+
);
|
|
414
|
+
}
|
|
415
|
+
_warnOnReconnectedHostConfigMismatch(containerId, hostConfig) {
|
|
416
|
+
if (!hostConfig) return;
|
|
417
|
+
const mismatchedHostConfigFields = this._requestedHardeningHostConfigEntries(hostConfig).filter(([field, requestedValue]) => !isHostConfigValueEqual(field, hostConfig[field], requestedValue)).map(([field]) => field);
|
|
418
|
+
if (mismatchedHostConfigFields.length === 0) return;
|
|
419
|
+
if (!this._privilegedWasSet && hostConfig.Privileged === true && mismatchedHostConfigFields.includes("Privileged")) {
|
|
420
|
+
this.logger.warn(
|
|
421
|
+
`${LOG_PREFIX} Reconnected to existing container ${containerId}; the existing container is privileged, but this DockerSandbox did not request privileged mode. Destroy and recreate the sandbox to apply the default non-privileged mode.`,
|
|
422
|
+
{ containerId, fields: ["privileged"], hostConfigFields: ["Privileged"] }
|
|
423
|
+
);
|
|
424
|
+
}
|
|
425
|
+
const remainingMismatchedHostConfigFields = mismatchedHostConfigFields.filter(
|
|
426
|
+
(field) => field !== "Privileged" || this._privilegedWasSet
|
|
427
|
+
);
|
|
428
|
+
if (remainingMismatchedHostConfigFields.length === 0) return;
|
|
429
|
+
const mismatchedOptions = remainingMismatchedHostConfigFields.map(toDockerSandboxOptionName);
|
|
430
|
+
this.logger.warn(
|
|
431
|
+
`${LOG_PREFIX} Reconnected to existing container ${containerId}; requested Docker option(s) ${mismatchedOptions.join(
|
|
432
|
+
", "
|
|
433
|
+
)} differ from inspected HostConfig field(s) ${remainingMismatchedHostConfigFields.join(
|
|
434
|
+
", "
|
|
435
|
+
)} and cannot be applied to the existing container. Destroy and recreate the sandbox to apply them.`,
|
|
436
|
+
{ containerId, fields: mismatchedOptions, hostConfigFields: remainingMismatchedHostConfigFields }
|
|
437
|
+
);
|
|
438
|
+
}
|
|
439
|
+
_requestedHardeningHostConfigEntries(hostConfig) {
|
|
440
|
+
const entries = [
|
|
441
|
+
["Memory", this._memory],
|
|
442
|
+
["MemorySwap", this._memorySwap],
|
|
443
|
+
["CpuShares", this._cpuShares],
|
|
444
|
+
["CpuQuota", this._cpuQuota],
|
|
445
|
+
["CpuPeriod", this._cpuPeriod],
|
|
446
|
+
["PidsLimit", this._pidsLimit],
|
|
447
|
+
["ReadonlyRootfs", this._readonlyRootfs],
|
|
448
|
+
["CapDrop", this._capDrop],
|
|
449
|
+
["CapAdd", this._capAdd],
|
|
450
|
+
["SecurityOpt", this._securityOpt],
|
|
451
|
+
["Ulimits", this._ulimits],
|
|
452
|
+
["Tmpfs", this._tmpfs]
|
|
453
|
+
];
|
|
454
|
+
if (this._privilegedWasSet || hostConfig?.Privileged === true) {
|
|
455
|
+
entries.unshift(["Privileged", this._privileged]);
|
|
456
|
+
}
|
|
457
|
+
return entries.filter((entry) => isPresentHostConfigValue(entry[1]));
|
|
458
|
+
}
|
|
359
459
|
async stop() {
|
|
360
460
|
const container = await this._resolveContainer();
|
|
361
461
|
if (!container) return;
|
|
@@ -517,6 +617,92 @@ function isImageNotFoundError(error) {
|
|
|
517
617
|
}
|
|
518
618
|
return false;
|
|
519
619
|
}
|
|
620
|
+
function isHostConfigValueEqual(field, actual, expected) {
|
|
621
|
+
return util.isDeepStrictEqual(normalizeHostConfigValue(field, actual), normalizeHostConfigValue(field, expected));
|
|
622
|
+
}
|
|
623
|
+
function normalizeHostConfigValue(field, value) {
|
|
624
|
+
if (value == null) return void 0;
|
|
625
|
+
if ((field === "CapAdd" || field === "CapDrop") && Array.isArray(value)) {
|
|
626
|
+
if (value.length === 0) return void 0;
|
|
627
|
+
return value.map(normalizeCapability).sort();
|
|
628
|
+
}
|
|
629
|
+
if (field === "SecurityOpt" && Array.isArray(value)) {
|
|
630
|
+
if (value.length === 0) return void 0;
|
|
631
|
+
return value.map(normalizeSecurityOpt).sort();
|
|
632
|
+
}
|
|
633
|
+
if (field === "Tmpfs" && value && typeof value === "object" && !Array.isArray(value)) {
|
|
634
|
+
if (Object.keys(value).length === 0) return void 0;
|
|
635
|
+
return Object.fromEntries(
|
|
636
|
+
Object.entries(value).sort(([a], [b]) => a.localeCompare(b)).map(([path, options]) => [path, typeof options === "string" ? normalizeTmpfsOptions(options) : options])
|
|
637
|
+
);
|
|
638
|
+
}
|
|
639
|
+
if (Array.isArray(value)) {
|
|
640
|
+
if (field === "Ulimits" && value.length === 0) return void 0;
|
|
641
|
+
return value.map((nestedValue) => normalizeHostConfigValue(field, nestedValue)).sort((a, b) => JSON.stringify(a).localeCompare(JSON.stringify(b)));
|
|
642
|
+
}
|
|
643
|
+
if (field === "Ulimits" && value && typeof value === "object") {
|
|
644
|
+
return normalizeUlimit(value);
|
|
645
|
+
}
|
|
646
|
+
if (value && typeof value === "object") {
|
|
647
|
+
return Object.fromEntries(
|
|
648
|
+
Object.entries(value).sort(([a], [b]) => a.localeCompare(b)).map(([key, nestedValue]) => [key, normalizeHostConfigValue(field, nestedValue)])
|
|
649
|
+
);
|
|
650
|
+
}
|
|
651
|
+
return value;
|
|
652
|
+
}
|
|
653
|
+
function isPresentHostConfigValue(value) {
|
|
654
|
+
if (value == null) return false;
|
|
655
|
+
if (Array.isArray(value)) return value.length > 0;
|
|
656
|
+
if (value && typeof value === "object") return Object.keys(value).length > 0;
|
|
657
|
+
return true;
|
|
658
|
+
}
|
|
659
|
+
function normalizeCapability(capability) {
|
|
660
|
+
return typeof capability === "string" ? capability.toUpperCase().replace(/^CAP_/, "") : capability;
|
|
661
|
+
}
|
|
662
|
+
function normalizeTmpfsOptions(options) {
|
|
663
|
+
return options.split(",").map((option) => option.trim()).filter(Boolean).sort().join(",");
|
|
664
|
+
}
|
|
665
|
+
function normalizeSecurityOpt(option) {
|
|
666
|
+
if (typeof option !== "string") return option;
|
|
667
|
+
const noNewPrivileges = option.match(/^no-new-privileges[:=](.+)$/i);
|
|
668
|
+
if (noNewPrivileges) {
|
|
669
|
+
return `no-new-privileges=${noNewPrivileges[1]}`;
|
|
670
|
+
}
|
|
671
|
+
return option;
|
|
672
|
+
}
|
|
673
|
+
function normalizeUlimit(value) {
|
|
674
|
+
const record = value;
|
|
675
|
+
return {
|
|
676
|
+
name: record.name ?? record.Name,
|
|
677
|
+
soft: record.soft ?? record.Soft,
|
|
678
|
+
hard: record.hard ?? record.Hard
|
|
679
|
+
};
|
|
680
|
+
}
|
|
681
|
+
function toDockerUlimit(ulimit) {
|
|
682
|
+
return {
|
|
683
|
+
Name: ulimit.name,
|
|
684
|
+
Soft: ulimit.soft,
|
|
685
|
+
Hard: ulimit.hard
|
|
686
|
+
};
|
|
687
|
+
}
|
|
688
|
+
function toDockerSandboxOptionName(field) {
|
|
689
|
+
const optionNames = {
|
|
690
|
+
Privileged: "privileged",
|
|
691
|
+
Memory: "memory",
|
|
692
|
+
MemorySwap: "memorySwap",
|
|
693
|
+
CpuShares: "cpuShares",
|
|
694
|
+
CpuQuota: "cpuQuota",
|
|
695
|
+
CpuPeriod: "cpuPeriod",
|
|
696
|
+
PidsLimit: "pidsLimit",
|
|
697
|
+
ReadonlyRootfs: "readonlyRootfs",
|
|
698
|
+
CapDrop: "capDrop",
|
|
699
|
+
CapAdd: "capAdd",
|
|
700
|
+
SecurityOpt: "securityOpt",
|
|
701
|
+
Ulimits: "ulimits",
|
|
702
|
+
Tmpfs: "tmpfs"
|
|
703
|
+
};
|
|
704
|
+
return optionNames[field] ?? String(field);
|
|
705
|
+
}
|
|
520
706
|
|
|
521
707
|
// src/provider.ts
|
|
522
708
|
var dockerSandboxProvider = {
|
|
@@ -559,6 +745,68 @@ var dockerSandboxProvider = {
|
|
|
559
745
|
type: "boolean",
|
|
560
746
|
description: "Run in privileged mode",
|
|
561
747
|
default: false
|
|
748
|
+
},
|
|
749
|
+
memory: {
|
|
750
|
+
type: "number",
|
|
751
|
+
description: "Memory limit in bytes"
|
|
752
|
+
},
|
|
753
|
+
memorySwap: {
|
|
754
|
+
type: "number",
|
|
755
|
+
description: "Total memory plus swap in bytes"
|
|
756
|
+
},
|
|
757
|
+
cpuShares: {
|
|
758
|
+
type: "number",
|
|
759
|
+
description: "CPU shares relative weight"
|
|
760
|
+
},
|
|
761
|
+
cpuQuota: {
|
|
762
|
+
type: "number",
|
|
763
|
+
description: "CPU quota in microseconds per period"
|
|
764
|
+
},
|
|
765
|
+
cpuPeriod: {
|
|
766
|
+
type: "number",
|
|
767
|
+
description: "CPU period in microseconds"
|
|
768
|
+
},
|
|
769
|
+
pidsLimit: {
|
|
770
|
+
type: "number",
|
|
771
|
+
description: "Maximum number of PIDs in the container"
|
|
772
|
+
},
|
|
773
|
+
readonlyRootfs: {
|
|
774
|
+
type: "boolean",
|
|
775
|
+
description: "Mount the container root filesystem as read-only"
|
|
776
|
+
},
|
|
777
|
+
capDrop: {
|
|
778
|
+
type: "array",
|
|
779
|
+
description: "Linux capabilities to drop",
|
|
780
|
+
items: { type: "string" }
|
|
781
|
+
},
|
|
782
|
+
capAdd: {
|
|
783
|
+
type: "array",
|
|
784
|
+
description: "Linux capabilities to add",
|
|
785
|
+
items: { type: "string" }
|
|
786
|
+
},
|
|
787
|
+
securityOpt: {
|
|
788
|
+
type: "array",
|
|
789
|
+
description: "Docker security options",
|
|
790
|
+
items: { type: "string" }
|
|
791
|
+
},
|
|
792
|
+
ulimits: {
|
|
793
|
+
type: "array",
|
|
794
|
+
description: "Ulimit entries for Docker HostConfig.Ulimits",
|
|
795
|
+
items: {
|
|
796
|
+
type: "object",
|
|
797
|
+
required: ["name", "soft", "hard"],
|
|
798
|
+
additionalProperties: false,
|
|
799
|
+
properties: {
|
|
800
|
+
name: { type: "string" },
|
|
801
|
+
soft: { type: "number" },
|
|
802
|
+
hard: { type: "number" }
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
},
|
|
806
|
+
tmpfs: {
|
|
807
|
+
type: "object",
|
|
808
|
+
description: "tmpfs mount paths with options",
|
|
809
|
+
additionalProperties: { type: "string" }
|
|
562
810
|
}
|
|
563
811
|
}
|
|
564
812
|
},
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/sandbox/process-manager.ts","../src/sandbox/index.ts","../src/provider.ts"],"names":["ProcessHandle","SandboxProcessManager","MastraSandbox","Docker","SandboxNotReadyError","error","SandboxError"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Docker Process Manager\n *\n * Implements SandboxProcessManager for Docker containers.\n * Uses `container.exec()` to run commands inside a long-lived container.\n * Each spawned process gets a dedicated exec instance with separate\n * stdout/stderr streams.\n */\n\nimport { ProcessHandle, SandboxProcessManager } from '@mastra/core/workspace';\nimport type { CommandResult, ProcessInfo, SpawnProcessOptions } from '@mastra/core/workspace';\nimport type { Container, Exec, ExecInspectInfo } from 'dockerode';\n\n// =============================================================================\n// Docker Process Handle\n// =============================================================================\n\n/**\n * Wraps a Docker exec instance to conform to Mastra's ProcessHandle.\n * Not exported — internal to this module.\n *\n * Listener dispatch is handled by the base class. The manager's spawn()\n * method wires Docker stream callbacks to handle.emitStdout/emitStderr.\n */\nclass DockerProcessHandle extends ProcessHandle {\n readonly pid: string;\n\n private readonly _exec: Exec;\n private readonly _container: Container;\n private readonly _startTime: number;\n private _exitCode: number | undefined;\n /** @internal Set by kill() and timeout to distinguish forced termination from natural exit */\n _killed = false;\n private _waitPromise: Promise<CommandResult> | null = null;\n private _stdinStream: NodeJS.WritableStream | null = null;\n private _execStream: NodeJS.ReadWriteStream | null = null;\n\n constructor(\n exec: Exec,\n container: Container,\n startTime: number,\n stdinStream: NodeJS.WritableStream | null,\n options?: SpawnProcessOptions,\n ) {\n super(options);\n this.pid = exec.id;\n this._exec = exec;\n this._container = container;\n this._startTime = startTime;\n this._stdinStream = stdinStream;\n }\n\n get exitCode(): number | undefined {\n return this._exitCode;\n }\n\n /** @internal Set exit code when stream closes */\n _setExitCode(code: number): void {\n this._exitCode = code;\n }\n\n /** @internal Set the wait promise from spawn */\n _setWaitPromise(p: Promise<CommandResult>): void {\n this._waitPromise = p;\n }\n\n /** @internal Set the exec stream so kill() can destroy it */\n _setExecStream(stream: NodeJS.ReadWriteStream): void {\n this._execStream = stream;\n }\n\n async wait(): Promise<CommandResult> {\n if (this._waitPromise) {\n return this._waitPromise;\n }\n\n // If no wait promise set yet, poll exec inspect\n const info = await this._inspectExec();\n return {\n success: (info.ExitCode ?? 1) === 0,\n exitCode: info.ExitCode ?? 1,\n stdout: this.stdout,\n stderr: this.stderr,\n executionTimeMs: Date.now() - this._startTime,\n };\n }\n\n async kill(): Promise<boolean> {\n if (this._exitCode !== undefined) return false;\n\n try {\n // Get the PID inside the container from exec inspect.\n // Single retry with 50ms delay — Docker may not have assigned a PID yet\n // if kill() is called immediately after spawn(). A polling loop with\n // backoff would be more robust under heavy load, but overkill in practice.\n let info = await this._inspectExec();\n if (!info.Running || !info.Pid) {\n await new Promise(r => setTimeout(r, 50));\n info = await this._inspectExec();\n }\n\n if (!info.Running) {\n this._killed = true;\n this._destroyStream();\n return false;\n }\n\n const pid = info.Pid;\n if (!pid) {\n this._killed = true;\n this._destroyStream();\n return false;\n }\n\n // Kill the process group (negative PID), fall back to direct PID\n const killExec = await this._container.exec({\n Cmd: ['sh', '-c', `kill -9 -${pid} 2>/dev/null || kill -9 ${pid}`],\n AttachStdout: false,\n AttachStderr: false,\n });\n await killExec.start({});\n\n // Mark as killed and destroy stream so wait() resolves.\n // Docker exec streams don't close automatically when the process is killed externally.\n this._killed = true;\n this._destroyStream();\n return true;\n } catch (error: unknown) {\n this._killed = true;\n this._destroyStream();\n // ESRCH / \"no such process\" is expected if the process exited between inspect and kill\n const msg = error instanceof Error ? error.message.toLowerCase() : '';\n if (!msg.includes('no such process') && !msg.includes('esrch')) {\n // Unexpected error — not fatal but worth noting for debugging\n console.warn(`[DockerProcessManager] kill(${this.pid}) failed unexpectedly:`, error);\n }\n return false;\n }\n }\n\n async sendStdin(data: string): Promise<void> {\n if (this._exitCode !== undefined) {\n throw new Error(`Process ${this.pid} has already exited with code ${this._exitCode}`);\n }\n if (!this._stdinStream) {\n throw new Error(`Process ${this.pid} was not started with stdin support`);\n }\n this._stdinStream.write(data);\n }\n\n /** @internal Force-close the exec stream to unblock wait(). */\n _destroyStream(): void {\n const stream = this._execStream as unknown as { destroy?: () => void } | null;\n if (stream && typeof stream.destroy === 'function') {\n stream.destroy();\n this._execStream = null;\n }\n }\n\n private async _inspectExec(): Promise<ExecInspectInfo> {\n return this._exec.inspect();\n }\n}\n\n// =============================================================================\n// Docker Process Manager\n// =============================================================================\n\n/**\n * Docker implementation of SandboxProcessManager.\n * Uses `container.exec()` with stream-based I/O.\n */\nexport class DockerProcessManager extends SandboxProcessManager {\n private _container: Container | null = null;\n private readonly _defaultTimeout: number;\n\n constructor(options: { env: Record<string, string>; defaultTimeout?: number }) {\n super(options);\n this._defaultTimeout = options.defaultTimeout ?? 0;\n }\n\n /** @internal Called by DockerSandbox after container is ready */\n setContainer(container: Container): void {\n this._container = container;\n }\n\n /** Get the container, throwing if not set */\n private get container(): Container {\n if (!this._container) {\n throw new Error('Docker container not available. Has the sandbox been started?');\n }\n return this._container;\n }\n\n async spawn(command: string, options: SpawnProcessOptions = {}): Promise<ProcessHandle> {\n const container = this.container;\n\n // Merge default env with per-spawn env\n const mergedEnv = { ...this.env, ...options.env };\n const envArray = Object.entries(mergedEnv)\n .filter((entry): entry is [string, string] => entry[1] !== undefined)\n .map(([k, v]) => `${k}=${v}`);\n\n // Create exec instance\n const exec = await container.exec({\n Cmd: ['sh', '-c', command],\n AttachStdout: true,\n AttachStderr: true,\n AttachStdin: true,\n Tty: false,\n Env: envArray.length > 0 ? envArray : undefined,\n WorkingDir: options.cwd,\n });\n\n // Start exec and get the multiplexed stream\n const stream = await exec.start({ hijack: true, stdin: true });\n\n const startTime = Date.now();\n const handle = new DockerProcessHandle(exec, container, startTime, stream, options);\n handle._setExecStream(stream);\n\n // Create the wait promise that resolves when the stream ends\n const waitPromise = new Promise<CommandResult>(resolve => {\n // Demux the multiplexed stream into stdout/stderr\n // Docker multiplexes stdout/stderr into a single stream with 8-byte headers\n // when Tty is false. We need to parse these headers.\n const buffer: Buffer[] = [];\n\n stream.on('data', (chunk: Buffer) => {\n buffer.push(chunk);\n // Process all complete frames in the buffer\n let combined = Buffer.concat(buffer);\n buffer.length = 0;\n\n while (combined.length >= 8) {\n const type = combined[0]; // 1 = stdout, 2 = stderr\n const size = combined.readUInt32BE(4);\n\n if (combined.length < 8 + size) {\n // Incomplete frame, save for next chunk\n buffer.push(combined);\n break;\n }\n\n const payload = combined.subarray(8, 8 + size).toString('utf-8');\n if (type === 1) {\n handle.emitStdout(payload);\n } else if (type === 2) {\n handle.emitStderr(payload);\n }\n\n combined = combined.subarray(8 + size);\n }\n\n // Save any remaining partial data\n if (combined.length > 0 && buffer.length === 0) {\n buffer.push(combined);\n }\n });\n\n stream.on('end', async () => {\n // Get exit code from exec inspect\n try {\n const info = await exec.inspect();\n const exitCode = info.ExitCode ?? 1;\n handle._setExitCode(exitCode);\n resolve({\n success: exitCode === 0,\n exitCode,\n stdout: handle.stdout,\n stderr: handle.stderr,\n executionTimeMs: Date.now() - startTime,\n });\n } catch {\n handle._setExitCode(1);\n resolve({\n success: false,\n exitCode: 1,\n stdout: handle.stdout,\n stderr: handle.stderr,\n executionTimeMs: Date.now() - startTime,\n });\n }\n });\n\n // 'close' fires when stream.destroy() is called (e.g., from kill or timeout).\n // Only resolve with SIGKILL exit code when the process was explicitly killed;\n // natural stream close should be handled by the 'end' event above.\n // Note: Docker multiplexed streams always emit 'end' before 'close' for\n // natural exits, so the !_killed guard won't silently drop natural closes.\n stream.on('close', () => {\n if (handle.exitCode !== undefined) return; // Already resolved via 'end'\n if (!handle._killed) return; // Natural close — 'end' handles it\n handle._setExitCode(137); // SIGKILL\n resolve({\n success: false,\n exitCode: 137,\n stdout: handle.stdout,\n stderr: handle.stderr,\n executionTimeMs: Date.now() - startTime,\n });\n });\n\n stream.on('error', () => {\n if (handle.exitCode !== undefined) return; // Already resolved\n handle._setExitCode(1);\n resolve({\n success: false,\n exitCode: 1,\n stdout: handle.stdout,\n stderr: handle.stderr || 'Stream error',\n executionTimeMs: Date.now() - startTime,\n });\n });\n });\n\n // Wire up timeout: kill the process and destroy the stream after the timeout period.\n // Per-spawn timeout takes precedence; falls back to the sandbox-level default.\n const resolvedTimeout = options.timeout ?? this._defaultTimeout;\n if (resolvedTimeout > 0) {\n const timeoutMs = resolvedTimeout;\n const timer = setTimeout(() => {\n if (handle.exitCode === undefined) {\n handle._killed = true;\n handle.kill().catch(() => {});\n // Ensure stream is destroyed even if kill() fails (e.g., PID not found)\n handle._destroyStream();\n }\n }, timeoutMs);\n // Clear timer when process exits naturally\n void waitPromise.then(() => clearTimeout(timer));\n }\n\n handle._setWaitPromise(waitPromise);\n this._tracked.set(handle.pid, handle);\n return handle;\n }\n\n /** Clear all tracked process handles and release the container reference (e.g., after container stop/destroy) */\n reset(): void {\n this._tracked.clear();\n this._container = null;\n }\n\n async list(): Promise<ProcessInfo[]> {\n const results: ProcessInfo[] = [];\n\n for (const [pid, handle] of this._tracked) {\n results.push({\n pid,\n command: handle.command,\n running: handle.exitCode === undefined,\n exitCode: handle.exitCode,\n });\n }\n\n return results;\n }\n}\n","/**\n * Docker Sandbox Provider\n *\n * A Docker-based sandbox implementation that uses long-lived containers\n * with `docker exec` for command execution. Targets local development,\n * CI/CD, air-gapped deployments, and cost-sensitive scenarios where\n * cloud sandboxes are overkill.\n *\n * @see https://docs.docker.com/engine/api/\n */\n\nimport type { RequestContext } from '@mastra/core/di';\nimport type { SandboxInfo, ProviderStatus, MastraSandboxOptions } from '@mastra/core/workspace';\nimport { MastraSandbox, SandboxError, SandboxNotReadyError } from '@mastra/core/workspace';\nimport Docker from 'dockerode';\nimport type { Container, ContainerInfo } from 'dockerode';\nimport { DockerProcessManager } from './process-manager';\n\nconst LOG_PREFIX = '[DockerSandbox]';\n\n/**\n * Inlined from `@mastra/core/workspace` to avoid requiring a newer core peer dep.\n * Canonical type: packages/core/src/workspace/sandbox/mastra-sandbox.ts\n * TODO: Remove once minimum peer dep includes InstructionsOption export.\n */\ntype InstructionsOption = string | ((opts: { defaultInstructions: string; requestContext?: RequestContext }) => string);\n\n// =============================================================================\n// Docker Sandbox Options\n// =============================================================================\n\nexport interface DockerSandboxOptions extends Omit<MastraSandboxOptions, 'processes'> {\n /** Unique identifier for this sandbox instance. Used for container naming and reconnection. */\n id?: string;\n /** Docker image to use.\n * @default 'node:22-slim'\n */\n image?: string;\n /** Container entrypoint command. Must keep the container alive.\n * @default ['sleep', 'infinity']\n */\n command?: string[];\n /** Environment variables to set in the container */\n env?: Record<string, string>;\n /** Host-to-container bind mounts (e.g., `{ '/host/path': '/container/path' }`) */\n volumes?: Record<string, string>;\n /** Docker network to join */\n network?: string;\n /** Run in privileged mode\n * @default false\n */\n privileged?: boolean;\n /** Default command timeout in milliseconds\n * @default 300_000 // 5 minutes\n */\n timeout?: number;\n /** Working directory inside the container\n * @default '/workspace'\n */\n workingDir?: string;\n /** Container labels for filtering and identification */\n labels?: Record<string, string>;\n /** Pass-through dockerode connection options (socket path, host, TLS certs) */\n dockerOptions?: Docker.DockerOptions;\n /**\n * Custom instructions that override the default instructions\n * returned by `getInstructions()`.\n *\n * - `string` — Fully replaces the default instructions.\n * Pass an empty string to suppress instructions entirely.\n * - `(opts) => string` — Receives the default instructions and\n * optional request context so you can extend or customise per-request.\n */\n instructions?: InstructionsOption;\n}\n\n// =============================================================================\n// Docker Sandbox Implementation\n// =============================================================================\n\n/**\n * Docker sandbox implementation using long-lived containers.\n *\n * Features:\n * - Long-lived container with `docker exec` for commands\n * - Bind mount support via Docker volumes\n * - Reconnection to existing containers by ID/name\n * - Container label tracking for discovery\n *\n * @example Basic usage\n * ```typescript\n * import { Workspace } from '@mastra/core/workspace';\n * import { DockerSandbox } from '@mastra/docker';\n *\n * const sandbox = new DockerSandbox({\n * image: 'node:22-slim',\n * timeout: 60000,\n * });\n *\n * const workspace = new Workspace({ sandbox });\n * const result = await workspace.executeCode('console.log(\"Hello!\")');\n * ```\n *\n * @example With bind mounts\n * ```typescript\n * const sandbox = new DockerSandbox({\n * image: 'node:22-slim',\n * volumes: { '/my/project': '/workspace/project' },\n * });\n * ```\n */\nexport class DockerSandbox extends MastraSandbox {\n readonly id: string;\n readonly name = 'DockerSandbox';\n readonly provider = 'docker';\n status: ProviderStatus = 'pending';\n\n declare readonly processes: DockerProcessManager;\n\n /** Underlying Docker client */\n private readonly _docker: Docker;\n\n /** Container reference (set after start) */\n private _container: Container | null = null;\n\n /** Configuration */\n private readonly _image: string;\n private readonly _command: string[];\n private readonly _env: Record<string, string>;\n private readonly _volumes: Record<string, string>;\n private readonly _network?: string;\n private readonly _privileged: boolean;\n private readonly _workingDir: string;\n private readonly _labels: Record<string, string>;\n private readonly _instructionsOverride?: InstructionsOption;\n\n constructor(options: DockerSandboxOptions = {}) {\n const processManager = new DockerProcessManager({\n env: options.env ?? {},\n defaultTimeout: options.timeout ?? 300_000,\n });\n\n super({\n ...options,\n name: 'DockerSandbox',\n processes: processManager,\n });\n\n this.id = options.id ?? this._generateId();\n this._image = options.image ?? 'node:22-slim';\n this._command = options.command ?? ['sleep', 'infinity'];\n this._env = options.env ?? {};\n this._volumes = options.volumes ?? {};\n this._network = options.network;\n this._privileged = options.privileged ?? false;\n this._workingDir = options.workingDir ?? '/workspace';\n this._labels = {\n ...options.labels,\n 'mastra.sandbox': 'true',\n 'mastra.sandbox.id': this.id,\n };\n this._instructionsOverride = options.instructions;\n this._docker = new Docker(options.dockerOptions);\n }\n\n /**\n * Get the underlying Docker container for direct access.\n * @throws {SandboxNotReadyError} If the sandbox has not been started.\n */\n get container(): Container {\n if (!this._container) {\n throw new SandboxNotReadyError(this.id);\n }\n return this._container;\n }\n\n // ---------------------------------------------------------------------------\n // Lifecycle\n // ---------------------------------------------------------------------------\n\n async start(): Promise<void> {\n this.logger.debug(`${LOG_PREFIX} Starting sandbox ${this.id}...`);\n\n // Try to reconnect to existing container\n const existing = await this._findExistingContainer();\n if (existing) {\n this.logger.debug(`${LOG_PREFIX} Found existing container ${existing.Id}`);\n this._container = this._docker.getContainer(existing.Id);\n\n // Use inspect() to get authoritative container state — listContainers() state\n // can be stale immediately after stop() returns but before container fully exits\n const info = await this._container.inspect();\n const actualState = info.State?.Running ? 'running' : 'stopped';\n\n if (actualState !== 'running') {\n this.logger.debug(`${LOG_PREFIX} Container exists but not running (${actualState}), starting...`);\n await this._container.start();\n }\n\n // Provide container reference to process manager\n this.processes.setContainer(this._container);\n\n this.logger.debug(`${LOG_PREFIX} Reconnected to container ${existing.Id}`);\n return;\n }\n\n // Pull image if not available locally\n await this._ensureImage();\n\n // Build environment array for Docker API\n const envArray = Object.entries(this._env).map(([k, v]) => `${k}=${v}`);\n\n // Build bind mount array\n const binds = Object.entries(this._volumes).map(([host, container]) => `${host}:${container}`);\n\n // Create container\n this.logger.debug(`${LOG_PREFIX} Creating container with image ${this._image}...`);\n this._container = await this._docker.createContainer({\n Image: this._image,\n Cmd: this._command,\n Env: envArray,\n WorkingDir: this._workingDir,\n Labels: this._labels,\n HostConfig: {\n Binds: binds.length > 0 ? binds : undefined,\n NetworkMode: this._network,\n Privileged: this._privileged,\n },\n // Keep stdin open for interactive use\n OpenStdin: true,\n Tty: false,\n });\n\n // Start container\n await this._container.start();\n\n // Provide container reference to process manager\n this.processes.setContainer(this._container);\n\n this.logger.debug(`${LOG_PREFIX} Container started: ${this._container.id}`);\n }\n\n async stop(): Promise<void> {\n const container = await this._resolveContainer();\n if (!container) return;\n\n this.logger.debug(`${LOG_PREFIX} Stopping container ${container.id}...`);\n try {\n await container.stop({ t: 10 });\n } catch (error: unknown) {\n // Container may already be stopped\n if (!isContainerNotRunningError(error)) {\n throw error;\n }\n }\n this.processes.reset();\n this.logger.debug(`${LOG_PREFIX} Container stopped`);\n }\n\n async destroy(): Promise<void> {\n const container = await this._resolveContainer();\n if (!container) return;\n\n this.logger.debug(`${LOG_PREFIX} Destroying container ${container.id}...`);\n try {\n await container.remove({ force: true, v: true });\n } catch (error: unknown) {\n // Container may already be removed\n if (!isContainerNotFoundError(error)) {\n throw error;\n }\n }\n this.processes.reset();\n this._container = null;\n this.logger.debug(`${LOG_PREFIX} Container destroyed`);\n }\n\n // ---------------------------------------------------------------------------\n // Instructions\n // ---------------------------------------------------------------------------\n\n getInstructions(opts?: { requestContext?: RequestContext }): string {\n const defaultInstructions = [\n `You are working inside a Docker container (image: ${this._image}).`,\n `The working directory is ${this._workingDir}.`,\n 'You can execute shell commands using executeCommand().',\n 'You can spawn background processes using processes.spawn().',\n ].join('\\n');\n\n if (this._instructionsOverride === undefined) return defaultInstructions;\n if (typeof this._instructionsOverride === 'string') return this._instructionsOverride;\n return this._instructionsOverride({ defaultInstructions, requestContext: opts?.requestContext });\n }\n\n // ---------------------------------------------------------------------------\n // Info\n // ---------------------------------------------------------------------------\n\n async getInfo(): Promise<SandboxInfo> {\n const info: SandboxInfo = {\n id: this.id,\n name: this.name,\n provider: this.provider,\n status: this.status,\n createdAt: new Date(),\n metadata: {\n image: this._image,\n workingDir: this._workingDir,\n labels: this._labels,\n },\n };\n\n if (this._container) {\n try {\n const inspect = await this._container.inspect();\n info.createdAt = new Date(inspect.Created);\n info.metadata = {\n ...info.metadata,\n containerId: inspect.Id,\n containerName: inspect.Name,\n state: inspect.State.Status,\n };\n } catch {\n // Container may have been removed\n }\n }\n\n return info;\n }\n\n // ---------------------------------------------------------------------------\n // Private helpers\n // ---------------------------------------------------------------------------\n\n private _generateId(): string {\n return `docker-sandbox-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;\n }\n\n /**\n * Resolve the container reference, looking up by label if `_container` is unset.\n * This ensures `stop()` and `destroy()` work even when the instance was created\n * with an existing container's ID but `start()` was never called.\n */\n private async _resolveContainer(): Promise<Container | null> {\n if (this._container) return this._container;\n const existing = await this._findExistingContainer();\n if (!existing) return null;\n this._container = this._docker.getContainer(existing.Id);\n return this._container;\n }\n\n /**\n * Find an existing container matching this sandbox's ID via labels.\n */\n private async _findExistingContainer(): Promise<ContainerInfo | null> {\n try {\n const containers = await this._docker.listContainers({\n all: true,\n filters: {\n label: [`mastra.sandbox.id=${this.id}`],\n },\n });\n return containers[0] ?? null;\n } catch (error) {\n // Log and re-throw infrastructure errors (daemon unreachable, auth, etc.)\n this.logger.debug(\n `${LOG_PREFIX} Failed to list containers: ${error instanceof Error ? error.message : String(error)}`,\n );\n throw error;\n }\n }\n\n /**\n * Ensure the Docker image is available locally. Pulls if needed.\n */\n private async _ensureImage(): Promise<void> {\n try {\n await this._docker.getImage(this._image).inspect();\n this.logger.debug(`${LOG_PREFIX} Image ${this._image} available locally`);\n } catch (error) {\n // Only attempt pull if the image doesn't exist (404).\n // Re-throw infrastructure errors (daemon unreachable, auth, etc.)\n if (!isImageNotFoundError(error)) {\n throw error;\n }\n\n this.logger.debug(`${LOG_PREFIX} Pulling image ${this._image}...`);\n try {\n const stream = await this._docker.pull(this._image);\n await new Promise<void>((resolve, reject) => {\n this._docker.modem.followProgress(stream, (err: Error | null) => {\n if (err) reject(err);\n else resolve();\n });\n });\n this.logger.debug(`${LOG_PREFIX} Image ${this._image} pulled successfully`);\n } catch (error) {\n throw new SandboxError(\n `Failed to pull Docker image '${this._image}': ${error instanceof Error ? error.message : String(error)}`,\n 'NOT_READY',\n { image: this._image, reason: 'image_pull_failed' },\n );\n }\n }\n }\n}\n\n// =============================================================================\n// Error detection helpers\n// =============================================================================\n\nfunction isContainerNotRunningError(error: unknown): boolean {\n if (error instanceof Error) {\n return error.message.includes('is not running') || error.message.includes('container already stopped');\n }\n return false;\n}\n\nfunction isContainerNotFoundError(error: unknown): boolean {\n if (error instanceof Error) {\n const msg = error.message.toLowerCase();\n return msg.includes('no such container') || (msg.includes('removal') && msg.includes('is already in progress'));\n }\n return false;\n}\n\nfunction isImageNotFoundError(error: unknown): boolean {\n if (error instanceof Error) {\n return error.message.toLowerCase().includes('no such image');\n }\n return false;\n}\n","/**\n * Docker Sandbox Provider Descriptor\n *\n * Enables registration with MastraEditor for UI-driven sandbox configuration.\n */\n\nimport type { SandboxProvider } from '@mastra/core/editor';\nimport { DockerSandbox } from './sandbox';\nimport type { DockerSandboxOptions } from './sandbox';\n\n/**\n * Serializable config for the Docker sandbox provider.\n * This is the subset of DockerSandboxOptions that can be stored in a config file\n * and rendered in a UI form.\n */\nexport interface DockerProviderConfig {\n /** Docker image to use */\n image?: string;\n /** Default command timeout in milliseconds */\n timeout?: number;\n /** Environment variables */\n env?: Record<string, string>;\n /** Host-to-container bind mounts */\n volumes?: Record<string, string>;\n /** Docker network to join */\n network?: string;\n /** Working directory inside the container */\n workingDir?: string;\n /** Run in privileged mode */\n privileged?: boolean;\n}\n\nexport const dockerSandboxProvider: SandboxProvider<DockerProviderConfig> = {\n id: 'docker',\n name: 'Docker Sandbox',\n description: 'Local container sandbox powered by Docker',\n configSchema: {\n type: 'object',\n properties: {\n image: {\n type: 'string',\n description: 'Docker image to use',\n default: 'node:22-slim',\n },\n timeout: {\n type: 'number',\n description: 'Default command timeout in milliseconds',\n default: 300_000,\n },\n env: {\n type: 'object',\n description: 'Environment variables',\n additionalProperties: { type: 'string' },\n },\n volumes: {\n type: 'object',\n description: 'Host-to-container bind mounts (host path → container path)',\n additionalProperties: { type: 'string' },\n },\n network: {\n type: 'string',\n description: 'Docker network to join',\n },\n workingDir: {\n type: 'string',\n description: 'Working directory inside the container',\n default: '/workspace',\n },\n privileged: {\n type: 'boolean',\n description: 'Run in privileged mode',\n default: false,\n },\n },\n },\n createSandbox: (config: DockerProviderConfig) => new DockerSandbox(config as DockerSandboxOptions),\n};\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/sandbox/process-manager.ts","../src/sandbox/index.ts","../src/provider.ts"],"names":["ProcessHandle","SandboxProcessManager","MastraSandbox","Docker","SandboxNotReadyError","error","SandboxError","isDeepStrictEqual"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Docker Process Manager\n *\n * Implements SandboxProcessManager for Docker containers.\n * Uses `container.exec()` to run commands inside a long-lived container.\n * Each spawned process gets a dedicated exec instance with separate\n * stdout/stderr streams.\n */\n\nimport { ProcessHandle, SandboxProcessManager } from '@mastra/core/workspace';\nimport type { CommandResult, ProcessInfo, SpawnProcessOptions } from '@mastra/core/workspace';\nimport type { Container, Exec, ExecInspectInfo } from 'dockerode';\n\n// =============================================================================\n// Docker Process Handle\n// =============================================================================\n\n/**\n * Wraps a Docker exec instance to conform to Mastra's ProcessHandle.\n * Not exported — internal to this module.\n *\n * Listener dispatch is handled by the base class. The manager's spawn()\n * method wires Docker stream callbacks to handle.emitStdout/emitStderr.\n */\nclass DockerProcessHandle extends ProcessHandle {\n readonly pid: string;\n\n private readonly _exec: Exec;\n private readonly _container: Container;\n private readonly _startTime: number;\n private _exitCode: number | undefined;\n /** @internal Set by kill() and timeout to distinguish forced termination from natural exit */\n _killed = false;\n private _waitPromise: Promise<CommandResult> | null = null;\n private _stdinStream: NodeJS.WritableStream | null = null;\n private _execStream: NodeJS.ReadWriteStream | null = null;\n\n constructor(\n exec: Exec,\n container: Container,\n startTime: number,\n stdinStream: NodeJS.WritableStream | null,\n options?: SpawnProcessOptions,\n ) {\n super(options);\n this.pid = exec.id;\n this._exec = exec;\n this._container = container;\n this._startTime = startTime;\n this._stdinStream = stdinStream;\n }\n\n get exitCode(): number | undefined {\n return this._exitCode;\n }\n\n /** @internal Set exit code when stream closes */\n _setExitCode(code: number): void {\n this._exitCode = code;\n }\n\n /** @internal Set the wait promise from spawn */\n _setWaitPromise(p: Promise<CommandResult>): void {\n this._waitPromise = p;\n }\n\n /** @internal Set the exec stream so kill() can destroy it */\n _setExecStream(stream: NodeJS.ReadWriteStream): void {\n this._execStream = stream;\n }\n\n async wait(): Promise<CommandResult> {\n if (this._waitPromise) {\n return this._waitPromise;\n }\n\n // If no wait promise set yet, poll exec inspect\n const info = await this._inspectExec();\n return {\n success: (info.ExitCode ?? 1) === 0,\n exitCode: info.ExitCode ?? 1,\n stdout: this.stdout,\n stderr: this.stderr,\n executionTimeMs: Date.now() - this._startTime,\n };\n }\n\n async kill(): Promise<boolean> {\n if (this._exitCode !== undefined) return false;\n\n try {\n // Get the PID inside the container from exec inspect.\n // Single retry with 50ms delay — Docker may not have assigned a PID yet\n // if kill() is called immediately after spawn(). A polling loop with\n // backoff would be more robust under heavy load, but overkill in practice.\n let info = await this._inspectExec();\n if (!info.Running || !info.Pid) {\n await new Promise(r => setTimeout(r, 50));\n info = await this._inspectExec();\n }\n\n if (!info.Running) {\n this._killed = true;\n this._destroyStream();\n return false;\n }\n\n const pid = info.Pid;\n if (!pid) {\n this._killed = true;\n this._destroyStream();\n return false;\n }\n\n // Kill the process group (negative PID), fall back to direct PID\n const killExec = await this._container.exec({\n Cmd: ['sh', '-c', `kill -9 -${pid} 2>/dev/null || kill -9 ${pid}`],\n AttachStdout: false,\n AttachStderr: false,\n });\n await killExec.start({});\n\n // Mark as killed and destroy stream so wait() resolves.\n // Docker exec streams don't close automatically when the process is killed externally.\n this._killed = true;\n this._destroyStream();\n return true;\n } catch (error: unknown) {\n this._killed = true;\n this._destroyStream();\n // ESRCH / \"no such process\" is expected if the process exited between inspect and kill\n const msg = error instanceof Error ? error.message.toLowerCase() : '';\n if (!msg.includes('no such process') && !msg.includes('esrch')) {\n // Unexpected error — not fatal but worth noting for debugging\n console.warn(`[DockerProcessManager] kill(${this.pid}) failed unexpectedly:`, error);\n }\n return false;\n }\n }\n\n async sendStdin(data: string): Promise<void> {\n if (this._exitCode !== undefined) {\n throw new Error(`Process ${this.pid} has already exited with code ${this._exitCode}`);\n }\n if (!this._stdinStream) {\n throw new Error(`Process ${this.pid} was not started with stdin support`);\n }\n this._stdinStream.write(data);\n }\n\n /** @internal Force-close the exec stream to unblock wait(). */\n _destroyStream(): void {\n const stream = this._execStream as unknown as { destroy?: () => void } | null;\n if (stream && typeof stream.destroy === 'function') {\n stream.destroy();\n this._execStream = null;\n }\n }\n\n private async _inspectExec(): Promise<ExecInspectInfo> {\n return this._exec.inspect();\n }\n}\n\n// =============================================================================\n// Docker Process Manager\n// =============================================================================\n\n/**\n * Docker implementation of SandboxProcessManager.\n * Uses `container.exec()` with stream-based I/O.\n */\nexport class DockerProcessManager extends SandboxProcessManager {\n private _container: Container | null = null;\n private readonly _defaultTimeout: number;\n\n constructor(options: { env: Record<string, string>; defaultTimeout?: number }) {\n super(options);\n this._defaultTimeout = options.defaultTimeout ?? 0;\n }\n\n /** @internal Called by DockerSandbox after container is ready */\n setContainer(container: Container): void {\n this._container = container;\n }\n\n /** Get the container, throwing if not set */\n private get container(): Container {\n if (!this._container) {\n throw new Error('Docker container not available. Has the sandbox been started?');\n }\n return this._container;\n }\n\n async spawn(command: string, options: SpawnProcessOptions = {}): Promise<ProcessHandle> {\n const container = this.container;\n\n // Merge default env with per-spawn env\n const mergedEnv = { ...this.env, ...options.env };\n const envArray = Object.entries(mergedEnv)\n .filter((entry): entry is [string, string] => entry[1] !== undefined)\n .map(([k, v]) => `${k}=${v}`);\n\n // Create exec instance\n const exec = await container.exec({\n Cmd: ['sh', '-c', command],\n AttachStdout: true,\n AttachStderr: true,\n AttachStdin: true,\n Tty: false,\n Env: envArray.length > 0 ? envArray : undefined,\n WorkingDir: options.cwd,\n });\n\n // Start exec and get the multiplexed stream\n const stream = await exec.start({ hijack: true, stdin: true });\n\n const startTime = Date.now();\n const handle = new DockerProcessHandle(exec, container, startTime, stream, options);\n handle._setExecStream(stream);\n\n // Create the wait promise that resolves when the stream ends\n const waitPromise = new Promise<CommandResult>(resolve => {\n // Demux the multiplexed stream into stdout/stderr\n // Docker multiplexes stdout/stderr into a single stream with 8-byte headers\n // when Tty is false. We need to parse these headers.\n const buffer: Buffer[] = [];\n\n stream.on('data', (chunk: Buffer) => {\n buffer.push(chunk);\n // Process all complete frames in the buffer\n let combined = Buffer.concat(buffer);\n buffer.length = 0;\n\n while (combined.length >= 8) {\n const type = combined[0]; // 1 = stdout, 2 = stderr\n const size = combined.readUInt32BE(4);\n\n if (combined.length < 8 + size) {\n // Incomplete frame, save for next chunk\n buffer.push(combined);\n break;\n }\n\n const payload = combined.subarray(8, 8 + size).toString('utf-8');\n if (type === 1) {\n handle.emitStdout(payload);\n } else if (type === 2) {\n handle.emitStderr(payload);\n }\n\n combined = combined.subarray(8 + size);\n }\n\n // Save any remaining partial data\n if (combined.length > 0 && buffer.length === 0) {\n buffer.push(combined);\n }\n });\n\n stream.on('end', async () => {\n // Get exit code from exec inspect\n try {\n const info = await exec.inspect();\n const exitCode = info.ExitCode ?? 1;\n handle._setExitCode(exitCode);\n resolve({\n success: exitCode === 0,\n exitCode,\n stdout: handle.stdout,\n stderr: handle.stderr,\n executionTimeMs: Date.now() - startTime,\n });\n } catch {\n handle._setExitCode(1);\n resolve({\n success: false,\n exitCode: 1,\n stdout: handle.stdout,\n stderr: handle.stderr,\n executionTimeMs: Date.now() - startTime,\n });\n }\n });\n\n // 'close' fires when stream.destroy() is called (e.g., from kill or timeout).\n // Only resolve with SIGKILL exit code when the process was explicitly killed;\n // natural stream close should be handled by the 'end' event above.\n // Note: Docker multiplexed streams always emit 'end' before 'close' for\n // natural exits, so the !_killed guard won't silently drop natural closes.\n stream.on('close', () => {\n if (handle.exitCode !== undefined) return; // Already resolved via 'end'\n if (!handle._killed) return; // Natural close — 'end' handles it\n handle._setExitCode(137); // SIGKILL\n resolve({\n success: false,\n exitCode: 137,\n stdout: handle.stdout,\n stderr: handle.stderr,\n executionTimeMs: Date.now() - startTime,\n });\n });\n\n stream.on('error', () => {\n if (handle.exitCode !== undefined) return; // Already resolved\n handle._setExitCode(1);\n resolve({\n success: false,\n exitCode: 1,\n stdout: handle.stdout,\n stderr: handle.stderr || 'Stream error',\n executionTimeMs: Date.now() - startTime,\n });\n });\n });\n\n // Wire up timeout: kill the process and destroy the stream after the timeout period.\n // Per-spawn timeout takes precedence; falls back to the sandbox-level default.\n const resolvedTimeout = options.timeout ?? this._defaultTimeout;\n if (resolvedTimeout > 0) {\n const timeoutMs = resolvedTimeout;\n const timer = setTimeout(() => {\n if (handle.exitCode === undefined) {\n handle._killed = true;\n handle.kill().catch(() => {});\n // Ensure stream is destroyed even if kill() fails (e.g., PID not found)\n handle._destroyStream();\n }\n }, timeoutMs);\n // Clear timer when process exits naturally\n void waitPromise.then(() => clearTimeout(timer));\n }\n\n handle._setWaitPromise(waitPromise);\n this._tracked.set(handle.pid, handle);\n return handle;\n }\n\n /** Clear all tracked process handles and release the container reference (e.g., after container stop/destroy) */\n reset(): void {\n this._tracked.clear();\n this._container = null;\n }\n\n async list(): Promise<ProcessInfo[]> {\n const results: ProcessInfo[] = [];\n\n for (const [pid, handle] of this._tracked) {\n results.push({\n pid,\n command: handle.command,\n running: handle.exitCode === undefined,\n exitCode: handle.exitCode,\n });\n }\n\n return results;\n }\n}\n","/**\n * Docker Sandbox Provider\n *\n * A Docker-based sandbox implementation that uses long-lived containers\n * with `docker exec` for command execution. Targets local development,\n * CI/CD, air-gapped deployments, and cost-sensitive scenarios where\n * cloud sandboxes are overkill.\n *\n * @see https://docs.docker.com/engine/api/\n */\n\nimport { isDeepStrictEqual } from 'node:util';\nimport type { RequestContext } from '@mastra/core/di';\nimport type { SandboxInfo, ProviderStatus, MastraSandboxOptions } from '@mastra/core/workspace';\nimport { MastraSandbox, SandboxError, SandboxNotReadyError } from '@mastra/core/workspace';\nimport Docker from 'dockerode';\nimport type { Container, ContainerInfo } from 'dockerode';\nimport { DockerProcessManager } from './process-manager';\n\nconst LOG_PREFIX = '[DockerSandbox]';\n\n/**\n * Inlined from `@mastra/core/workspace` to avoid requiring a newer core peer dep.\n * Canonical type: packages/core/src/workspace/sandbox/mastra-sandbox.ts\n * TODO: Remove once minimum peer dep includes InstructionsOption export.\n */\ntype InstructionsOption = string | ((opts: { defaultInstructions: string; requestContext?: RequestContext }) => string);\n\ntype DockerSandboxUlimit = {\n name: string;\n soft: number;\n hard: number;\n};\n\ntype DockerSandboxTmpfs = Record<string, string>;\n\n// =============================================================================\n// Docker Sandbox Options\n// =============================================================================\n\nexport interface DockerSandboxOptions extends Omit<MastraSandboxOptions, 'processes'> {\n /** Unique identifier for this sandbox instance. Used for container naming and reconnection. */\n id?: string;\n /** Docker image to use.\n * @default 'node:22-slim'\n */\n image?: string;\n /** Container entrypoint command. Must keep the container alive.\n * @default ['sleep', 'infinity']\n */\n command?: string[];\n /** Environment variables to set in the container */\n env?: Record<string, string>;\n /** Host-to-container bind mounts (e.g., `{ '/host/path': '/container/path' }`) */\n volumes?: Record<string, string>;\n /** Docker network to join */\n network?: string;\n /** Run in privileged mode\n * @default false\n */\n privileged?: boolean;\n /** Memory limit in bytes (HostConfig.Memory). Docker treats 0 as unlimited. */\n memory?: number;\n /** Total memory plus swap in bytes (HostConfig.MemorySwap). */\n memorySwap?: number;\n /** CPU shares relative weight (HostConfig.CpuShares). */\n cpuShares?: number;\n /** CPU quota in microseconds per period (HostConfig.CpuQuota). */\n cpuQuota?: number;\n /** CPU period in microseconds (HostConfig.CpuPeriod). */\n cpuPeriod?: number;\n /** Maximum number of PIDs in the container (HostConfig.PidsLimit). */\n pidsLimit?: number;\n /** Mount the container root filesystem as read-only (HostConfig.ReadonlyRootfs). */\n readonlyRootfs?: boolean;\n /** Linux capabilities to drop (HostConfig.CapDrop), e.g. ['ALL']. */\n capDrop?: string[];\n /** Linux capabilities to add (HostConfig.CapAdd). */\n capAdd?: string[];\n /** Security options (HostConfig.SecurityOpt), e.g. ['no-new-privileges:true']. */\n securityOpt?: string[];\n /** Ulimit entries for Docker HostConfig.Ulimits. */\n ulimits?: DockerSandboxUlimit[];\n /** tmpfs mount paths with options (HostConfig.Tmpfs). */\n tmpfs?: DockerSandboxTmpfs;\n /** Default command timeout in milliseconds\n * @default 300_000 // 5 minutes\n */\n timeout?: number;\n /** Working directory inside the container\n * @default '/workspace'\n */\n workingDir?: string;\n /** Container labels for filtering and identification */\n labels?: Record<string, string>;\n /** Pass-through dockerode connection options (socket path, host, TLS certs) */\n dockerOptions?: Docker.DockerOptions;\n /**\n * Custom instructions that override the default instructions\n * returned by `getInstructions()`.\n *\n * - `string` — Fully replaces the default instructions.\n * Pass an empty string to suppress instructions entirely.\n * - `(opts) => string` — Receives the default instructions and\n * optional request context so you can extend or customise per-request.\n */\n instructions?: InstructionsOption;\n}\n\n// =============================================================================\n// Docker Sandbox Implementation\n// =============================================================================\n\n/**\n * Docker sandbox implementation using long-lived containers.\n *\n * Features:\n * - Long-lived container with `docker exec` for commands\n * - Bind mount support via Docker volumes\n * - Reconnection to existing containers by ID/name\n * - Container label tracking for discovery\n *\n * @example Basic usage\n * ```typescript\n * import { Workspace } from '@mastra/core/workspace';\n * import { DockerSandbox } from '@mastra/docker';\n *\n * const sandbox = new DockerSandbox({\n * image: 'node:22-slim',\n * timeout: 60000,\n * });\n *\n * const workspace = new Workspace({ sandbox });\n * const result = await workspace.executeCode('console.log(\"Hello!\")');\n * ```\n *\n * @example With bind mounts\n * ```typescript\n * const sandbox = new DockerSandbox({\n * image: 'node:22-slim',\n * volumes: { '/my/project': '/workspace/project' },\n * });\n * ```\n */\nexport class DockerSandbox extends MastraSandbox {\n readonly id: string;\n readonly name = 'DockerSandbox';\n readonly provider = 'docker';\n status: ProviderStatus = 'pending';\n\n declare readonly processes: DockerProcessManager;\n\n /** Underlying Docker client */\n private readonly _docker: Docker;\n\n /** Container reference (set after start) */\n private _container: Container | null = null;\n\n /** Configuration */\n private readonly _image: string;\n private readonly _command: string[];\n private readonly _env: Record<string, string>;\n private readonly _volumes: Record<string, string>;\n private readonly _network?: string;\n private readonly _privileged: boolean;\n private readonly _privilegedWasSet: boolean;\n private readonly _memory?: number;\n private readonly _memorySwap?: number;\n private readonly _cpuShares?: number;\n private readonly _cpuQuota?: number;\n private readonly _cpuPeriod?: number;\n private readonly _pidsLimit?: number;\n private readonly _readonlyRootfs?: boolean;\n private readonly _capDrop?: string[];\n private readonly _capAdd?: string[];\n private readonly _securityOpt?: string[];\n private readonly _ulimits?: DockerSandboxUlimit[];\n private readonly _tmpfs?: DockerSandboxTmpfs;\n private readonly _workingDir: string;\n private readonly _labels: Record<string, string>;\n private readonly _instructionsOverride?: InstructionsOption;\n\n constructor(options: DockerSandboxOptions = {}) {\n const processManager = new DockerProcessManager({\n env: options.env ?? {},\n defaultTimeout: options.timeout ?? 300_000,\n });\n\n super({\n ...options,\n name: 'DockerSandbox',\n processes: processManager,\n });\n\n this.id = options.id ?? this._generateId();\n this._image = options.image ?? 'node:22-slim';\n this._command = options.command ?? ['sleep', 'infinity'];\n this._env = options.env ?? {};\n this._volumes = options.volumes ?? {};\n this._network = options.network;\n this._privileged = options.privileged ?? false;\n this._privilegedWasSet = options.privileged !== undefined;\n this._memory = options.memory;\n this._memorySwap = options.memorySwap;\n this._cpuShares = options.cpuShares;\n this._cpuQuota = options.cpuQuota;\n this._cpuPeriod = options.cpuPeriod;\n this._pidsLimit = options.pidsLimit;\n this._readonlyRootfs = options.readonlyRootfs;\n this._capDrop = options.capDrop;\n this._capAdd = options.capAdd;\n this._securityOpt = options.securityOpt;\n this._ulimits = options.ulimits;\n this._tmpfs = options.tmpfs;\n this._workingDir = options.workingDir ?? '/workspace';\n this._labels = {\n ...options.labels,\n 'mastra.sandbox': 'true',\n 'mastra.sandbox.id': this.id,\n };\n this._instructionsOverride = options.instructions;\n this._docker = new Docker(options.dockerOptions);\n }\n\n /**\n * Get the underlying Docker container for direct access.\n * @throws {SandboxNotReadyError} If the sandbox has not been started.\n */\n get container(): Container {\n if (!this._container) {\n throw new SandboxNotReadyError(this.id);\n }\n return this._container;\n }\n\n // ---------------------------------------------------------------------------\n // Lifecycle\n // ---------------------------------------------------------------------------\n\n async start(): Promise<void> {\n this.logger.debug(`${LOG_PREFIX} Starting sandbox ${this.id}...`);\n\n // Try to reconnect to existing container\n const existing = await this._findExistingContainer();\n if (existing) {\n this.logger.debug(`${LOG_PREFIX} Found existing container ${existing.Id}`);\n this._container = this._docker.getContainer(existing.Id);\n\n // Use inspect() to get authoritative container state — listContainers() state\n // can be stale immediately after stop() returns but before container fully exits\n const info = await this._container.inspect();\n // On reconnect, actual HostConfig controls whether hardening is effective.\n this._warnOnPrivilegedHardeningConflict(info.HostConfig?.Privileged ?? this._privileged);\n this._warnOnReconnectedHostConfigMismatch(existing.Id, info.HostConfig);\n const actualState = info.State?.Running ? 'running' : 'stopped';\n\n if (actualState !== 'running') {\n this.logger.debug(`${LOG_PREFIX} Container exists but not running (${actualState}), starting...`);\n await this._container.start();\n }\n\n // Provide container reference to process manager\n this.processes.setContainer(this._container);\n\n this.logger.debug(`${LOG_PREFIX} Reconnected to container ${existing.Id}`);\n return;\n }\n\n this._warnOnPrivilegedHardeningConflict(this._privileged);\n\n // Pull image if not available locally\n await this._ensureImage();\n\n // Build environment array for Docker API\n const envArray = Object.entries(this._env).map(([k, v]) => `${k}=${v}`);\n\n // Build bind mount array\n const binds = Object.entries(this._volumes).map(([host, container]) => `${host}:${container}`);\n\n // Create container\n this.logger.debug(`${LOG_PREFIX} Creating container with image ${this._image}...`);\n this._container = await this._docker.createContainer({\n Image: this._image,\n Cmd: this._command,\n Env: envArray,\n WorkingDir: this._workingDir,\n Labels: this._labels,\n HostConfig: {\n Binds: binds.length > 0 ? binds : undefined,\n NetworkMode: this._network,\n Privileged: this._privileged,\n Memory: this._memory,\n MemorySwap: this._memorySwap,\n CpuShares: this._cpuShares,\n CpuQuota: this._cpuQuota,\n CpuPeriod: this._cpuPeriod,\n PidsLimit: this._pidsLimit,\n ReadonlyRootfs: this._readonlyRootfs,\n CapDrop: this._capDrop,\n CapAdd: this._capAdd,\n SecurityOpt: this._securityOpt,\n Ulimits: this._ulimits?.map(toDockerUlimit),\n Tmpfs: this._tmpfs,\n },\n // Keep stdin open for interactive use\n OpenStdin: true,\n Tty: false,\n });\n\n // Start container\n await this._container.start();\n\n // Provide container reference to process manager\n this.processes.setContainer(this._container);\n\n this.logger.debug(`${LOG_PREFIX} Container started: ${this._container.id}`);\n }\n\n private _warnOnPrivilegedHardeningConflict(effectivePrivileged: boolean | undefined): void {\n if (!effectivePrivileged) return;\n\n // Privileged mode makes capability and security-option controls ineffective.\n // ReadonlyRootfs, ulimits, tmpfs, memory, CPU, and PID limits still apply.\n const conflictedHostConfigFields = [\n this._capDrop && this._capDrop.length > 0 ? 'CapDrop' : undefined,\n this._capAdd && this._capAdd.length > 0 ? 'CapAdd' : undefined,\n this._securityOpt && this._securityOpt.length > 0 ? 'SecurityOpt' : undefined,\n ].filter((field): field is keyof Docker.HostConfig => field !== undefined);\n\n if (conflictedHostConfigFields.length === 0) return;\n\n const optionNames = conflictedHostConfigFields.map(toDockerSandboxOptionName);\n\n this.logger.warn(\n `${LOG_PREFIX} Privileged containers can bypass some requested hardening controls: ${optionNames.join(', ')}`,\n { fields: optionNames, hostConfigFields: conflictedHostConfigFields },\n );\n }\n\n private _warnOnReconnectedHostConfigMismatch(containerId: string, hostConfig?: Docker.HostConfig): void {\n if (!hostConfig) return;\n\n const mismatchedHostConfigFields = this._requestedHardeningHostConfigEntries(hostConfig)\n .filter(([field, requestedValue]) => !isHostConfigValueEqual(field, hostConfig[field], requestedValue))\n .map(([field]) => field);\n\n if (mismatchedHostConfigFields.length === 0) return;\n\n if (\n !this._privilegedWasSet &&\n hostConfig.Privileged === true &&\n mismatchedHostConfigFields.includes('Privileged')\n ) {\n this.logger.warn(\n `${LOG_PREFIX} Reconnected to existing container ${containerId}; the existing container is privileged, but this DockerSandbox did not request privileged mode. Destroy and recreate the sandbox to apply the default non-privileged mode.`,\n { containerId, fields: ['privileged'], hostConfigFields: ['Privileged'] },\n );\n }\n\n const remainingMismatchedHostConfigFields = mismatchedHostConfigFields.filter(\n field => field !== 'Privileged' || this._privilegedWasSet,\n );\n\n if (remainingMismatchedHostConfigFields.length === 0) return;\n\n const mismatchedOptions = remainingMismatchedHostConfigFields.map(toDockerSandboxOptionName);\n\n this.logger.warn(\n `${LOG_PREFIX} Reconnected to existing container ${containerId}; requested Docker option(s) ${mismatchedOptions.join(\n ', ',\n )} differ from inspected HostConfig field(s) ${remainingMismatchedHostConfigFields.join(\n ', ',\n )} and cannot be applied to the existing container. Destroy and recreate the sandbox to apply them.`,\n { containerId, fields: mismatchedOptions, hostConfigFields: remainingMismatchedHostConfigFields },\n );\n }\n\n private _requestedHardeningHostConfigEntries(\n hostConfig?: Docker.HostConfig,\n ): Array<[keyof Docker.HostConfig, unknown]> {\n const entries: Array<[keyof Docker.HostConfig, unknown]> = [\n ['Memory', this._memory],\n ['MemorySwap', this._memorySwap],\n ['CpuShares', this._cpuShares],\n ['CpuQuota', this._cpuQuota],\n ['CpuPeriod', this._cpuPeriod],\n ['PidsLimit', this._pidsLimit],\n ['ReadonlyRootfs', this._readonlyRootfs],\n ['CapDrop', this._capDrop],\n ['CapAdd', this._capAdd],\n ['SecurityOpt', this._securityOpt],\n ['Ulimits', this._ulimits],\n ['Tmpfs', this._tmpfs],\n ];\n\n if (this._privilegedWasSet || hostConfig?.Privileged === true) {\n entries.unshift(['Privileged', this._privileged]);\n }\n\n return entries.filter((entry): entry is [keyof Docker.HostConfig, unknown] => isPresentHostConfigValue(entry[1]));\n }\n\n async stop(): Promise<void> {\n const container = await this._resolveContainer();\n if (!container) return;\n\n this.logger.debug(`${LOG_PREFIX} Stopping container ${container.id}...`);\n try {\n await container.stop({ t: 10 });\n } catch (error: unknown) {\n // Container may already be stopped\n if (!isContainerNotRunningError(error)) {\n throw error;\n }\n }\n this.processes.reset();\n this.logger.debug(`${LOG_PREFIX} Container stopped`);\n }\n\n async destroy(): Promise<void> {\n const container = await this._resolveContainer();\n if (!container) return;\n\n this.logger.debug(`${LOG_PREFIX} Destroying container ${container.id}...`);\n try {\n await container.remove({ force: true, v: true });\n } catch (error: unknown) {\n // Container may already be removed\n if (!isContainerNotFoundError(error)) {\n throw error;\n }\n }\n this.processes.reset();\n this._container = null;\n this.logger.debug(`${LOG_PREFIX} Container destroyed`);\n }\n\n // ---------------------------------------------------------------------------\n // Instructions\n // ---------------------------------------------------------------------------\n\n getInstructions(opts?: { requestContext?: RequestContext }): string {\n const defaultInstructions = [\n `You are working inside a Docker container (image: ${this._image}).`,\n `The working directory is ${this._workingDir}.`,\n 'You can execute shell commands using executeCommand().',\n 'You can spawn background processes using processes.spawn().',\n ].join('\\n');\n\n if (this._instructionsOverride === undefined) return defaultInstructions;\n if (typeof this._instructionsOverride === 'string') return this._instructionsOverride;\n return this._instructionsOverride({ defaultInstructions, requestContext: opts?.requestContext });\n }\n\n // ---------------------------------------------------------------------------\n // Info\n // ---------------------------------------------------------------------------\n\n async getInfo(): Promise<SandboxInfo> {\n const info: SandboxInfo = {\n id: this.id,\n name: this.name,\n provider: this.provider,\n status: this.status,\n createdAt: new Date(),\n metadata: {\n image: this._image,\n workingDir: this._workingDir,\n labels: this._labels,\n },\n };\n\n if (this._container) {\n try {\n const inspect = await this._container.inspect();\n info.createdAt = new Date(inspect.Created);\n info.metadata = {\n ...info.metadata,\n containerId: inspect.Id,\n containerName: inspect.Name,\n state: inspect.State.Status,\n };\n } catch {\n // Container may have been removed\n }\n }\n\n return info;\n }\n\n // ---------------------------------------------------------------------------\n // Private helpers\n // ---------------------------------------------------------------------------\n\n private _generateId(): string {\n return `docker-sandbox-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;\n }\n\n /**\n * Resolve the container reference, looking up by label if `_container` is unset.\n * This ensures `stop()` and `destroy()` work even when the instance was created\n * with an existing container's ID but `start()` was never called.\n */\n private async _resolveContainer(): Promise<Container | null> {\n if (this._container) return this._container;\n const existing = await this._findExistingContainer();\n if (!existing) return null;\n this._container = this._docker.getContainer(existing.Id);\n return this._container;\n }\n\n /**\n * Find an existing container matching this sandbox's ID via labels.\n */\n private async _findExistingContainer(): Promise<ContainerInfo | null> {\n try {\n const containers = await this._docker.listContainers({\n all: true,\n filters: {\n label: [`mastra.sandbox.id=${this.id}`],\n },\n });\n return containers[0] ?? null;\n } catch (error) {\n // Log and re-throw infrastructure errors (daemon unreachable, auth, etc.)\n this.logger.debug(\n `${LOG_PREFIX} Failed to list containers: ${error instanceof Error ? error.message : String(error)}`,\n );\n throw error;\n }\n }\n\n /**\n * Ensure the Docker image is available locally. Pulls if needed.\n */\n private async _ensureImage(): Promise<void> {\n try {\n await this._docker.getImage(this._image).inspect();\n this.logger.debug(`${LOG_PREFIX} Image ${this._image} available locally`);\n } catch (error) {\n // Only attempt pull if the image doesn't exist (404).\n // Re-throw infrastructure errors (daemon unreachable, auth, etc.)\n if (!isImageNotFoundError(error)) {\n throw error;\n }\n\n this.logger.debug(`${LOG_PREFIX} Pulling image ${this._image}...`);\n try {\n const stream = await this._docker.pull(this._image);\n await new Promise<void>((resolve, reject) => {\n this._docker.modem.followProgress(stream, (err: Error | null) => {\n if (err) reject(err);\n else resolve();\n });\n });\n this.logger.debug(`${LOG_PREFIX} Image ${this._image} pulled successfully`);\n } catch (error) {\n throw new SandboxError(\n `Failed to pull Docker image '${this._image}': ${error instanceof Error ? error.message : String(error)}`,\n 'NOT_READY',\n { image: this._image, reason: 'image_pull_failed' },\n );\n }\n }\n }\n}\n\n// =============================================================================\n// Error detection helpers\n// =============================================================================\n\nfunction isContainerNotRunningError(error: unknown): boolean {\n if (error instanceof Error) {\n return error.message.includes('is not running') || error.message.includes('container already stopped');\n }\n return false;\n}\n\nfunction isContainerNotFoundError(error: unknown): boolean {\n if (error instanceof Error) {\n const msg = error.message.toLowerCase();\n return msg.includes('no such container') || (msg.includes('removal') && msg.includes('is already in progress'));\n }\n return false;\n}\n\nfunction isImageNotFoundError(error: unknown): boolean {\n if (error instanceof Error) {\n return error.message.toLowerCase().includes('no such image');\n }\n return false;\n}\n\nfunction isHostConfigValueEqual(field: keyof Docker.HostConfig, actual: unknown, expected: unknown): boolean {\n // Structural equality for the Docker HostConfig shapes exposed by DockerSandboxOptions.\n return isDeepStrictEqual(normalizeHostConfigValue(field, actual), normalizeHostConfigValue(field, expected));\n}\n\nfunction normalizeHostConfigValue(field: keyof Docker.HostConfig, value: unknown): unknown {\n if (value == null) return undefined;\n\n if ((field === 'CapAdd' || field === 'CapDrop') && Array.isArray(value)) {\n if (value.length === 0) return undefined;\n return value.map(normalizeCapability).sort();\n }\n\n if (field === 'SecurityOpt' && Array.isArray(value)) {\n if (value.length === 0) return undefined;\n return value.map(normalizeSecurityOpt).sort();\n }\n\n if (field === 'Tmpfs' && value && typeof value === 'object' && !Array.isArray(value)) {\n if (Object.keys(value).length === 0) return undefined;\n return Object.fromEntries(\n Object.entries(value)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([path, options]) => [path, typeof options === 'string' ? normalizeTmpfsOptions(options) : options]),\n );\n }\n\n if (Array.isArray(value)) {\n if (field === 'Ulimits' && value.length === 0) return undefined;\n return value\n .map(nestedValue => normalizeHostConfigValue(field, nestedValue))\n .sort((a, b) => JSON.stringify(a).localeCompare(JSON.stringify(b)));\n }\n\n if (field === 'Ulimits' && value && typeof value === 'object') {\n return normalizeUlimit(value);\n }\n\n if (value && typeof value === 'object') {\n return Object.fromEntries(\n Object.entries(value)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([key, nestedValue]) => [key, normalizeHostConfigValue(field, nestedValue)]),\n );\n }\n\n return value;\n}\n\nfunction isPresentHostConfigValue(value: unknown): boolean {\n if (value == null) return false;\n if (Array.isArray(value)) return value.length > 0;\n if (value && typeof value === 'object') return Object.keys(value).length > 0;\n return true;\n}\n\nfunction normalizeCapability(capability: unknown): unknown {\n return typeof capability === 'string' ? capability.toUpperCase().replace(/^CAP_/, '') : capability;\n}\n\nfunction normalizeTmpfsOptions(options: string): string {\n return options\n .split(',')\n .map(option => option.trim())\n .filter(Boolean)\n .sort()\n .join(',');\n}\n\nfunction normalizeSecurityOpt(option: unknown): unknown {\n if (typeof option !== 'string') return option;\n\n const noNewPrivileges = option.match(/^no-new-privileges[:=](.+)$/i);\n if (noNewPrivileges) {\n return `no-new-privileges=${noNewPrivileges[1]}`;\n }\n\n return option;\n}\n\nfunction normalizeUlimit(value: object): unknown {\n const record = value as Record<string, unknown>;\n return {\n name: record.name ?? record.Name,\n soft: record.soft ?? record.Soft,\n hard: record.hard ?? record.Hard,\n };\n}\n\nfunction toDockerUlimit(ulimit: DockerSandboxUlimit): Docker.Ulimit {\n return {\n Name: ulimit.name,\n Soft: ulimit.soft,\n Hard: ulimit.hard,\n };\n}\n\nfunction toDockerSandboxOptionName(field: keyof Docker.HostConfig): string {\n const optionNames: Partial<Record<keyof Docker.HostConfig, string>> = {\n Privileged: 'privileged',\n Memory: 'memory',\n MemorySwap: 'memorySwap',\n CpuShares: 'cpuShares',\n CpuQuota: 'cpuQuota',\n CpuPeriod: 'cpuPeriod',\n PidsLimit: 'pidsLimit',\n ReadonlyRootfs: 'readonlyRootfs',\n CapDrop: 'capDrop',\n CapAdd: 'capAdd',\n SecurityOpt: 'securityOpt',\n Ulimits: 'ulimits',\n Tmpfs: 'tmpfs',\n };\n\n return optionNames[field] ?? String(field);\n}\n","/**\n * Docker Sandbox Provider Descriptor\n *\n * Enables registration with MastraEditor for UI-driven sandbox configuration.\n */\n\nimport type { SandboxProvider } from '@mastra/core/editor';\nimport { DockerSandbox } from './sandbox';\nimport type { DockerSandboxOptions } from './sandbox';\n\n/**\n * Serializable config for the Docker sandbox provider.\n * This is the subset of DockerSandboxOptions that can be stored in a config file\n * and rendered in a UI form.\n */\nexport interface DockerProviderConfig {\n /** Docker image to use */\n image?: string;\n /** Default command timeout in milliseconds */\n timeout?: number;\n /** Environment variables */\n env?: Record<string, string>;\n /** Host-to-container bind mounts */\n volumes?: Record<string, string>;\n /** Docker network to join */\n network?: string;\n /** Working directory inside the container */\n workingDir?: string;\n /** Run in privileged mode */\n privileged?: boolean;\n /** Memory limit in bytes */\n memory?: number;\n /** Total memory plus swap in bytes */\n memorySwap?: number;\n /** CPU shares relative weight */\n cpuShares?: number;\n /** CPU quota in microseconds per period */\n cpuQuota?: number;\n /** CPU period in microseconds */\n cpuPeriod?: number;\n /** Maximum number of PIDs in the container */\n pidsLimit?: number;\n /** Mount the container root filesystem as read-only */\n readonlyRootfs?: boolean;\n /** Linux capabilities to drop */\n capDrop?: string[];\n /** Linux capabilities to add */\n capAdd?: string[];\n /** Docker security options */\n securityOpt?: string[];\n /** Ulimit entries for Docker HostConfig.Ulimits */\n ulimits?: DockerSandboxOptions['ulimits'];\n /** tmpfs mount paths with options */\n tmpfs?: DockerSandboxOptions['tmpfs'];\n}\n\nexport const dockerSandboxProvider: SandboxProvider<DockerProviderConfig> = {\n id: 'docker',\n name: 'Docker Sandbox',\n description: 'Local container sandbox powered by Docker',\n configSchema: {\n type: 'object',\n properties: {\n image: {\n type: 'string',\n description: 'Docker image to use',\n default: 'node:22-slim',\n },\n timeout: {\n type: 'number',\n description: 'Default command timeout in milliseconds',\n default: 300_000,\n },\n env: {\n type: 'object',\n description: 'Environment variables',\n additionalProperties: { type: 'string' },\n },\n volumes: {\n type: 'object',\n description: 'Host-to-container bind mounts (host path → container path)',\n additionalProperties: { type: 'string' },\n },\n network: {\n type: 'string',\n description: 'Docker network to join',\n },\n workingDir: {\n type: 'string',\n description: 'Working directory inside the container',\n default: '/workspace',\n },\n privileged: {\n type: 'boolean',\n description: 'Run in privileged mode',\n default: false,\n },\n memory: {\n type: 'number',\n description: 'Memory limit in bytes',\n },\n memorySwap: {\n type: 'number',\n description: 'Total memory plus swap in bytes',\n },\n cpuShares: {\n type: 'number',\n description: 'CPU shares relative weight',\n },\n cpuQuota: {\n type: 'number',\n description: 'CPU quota in microseconds per period',\n },\n cpuPeriod: {\n type: 'number',\n description: 'CPU period in microseconds',\n },\n pidsLimit: {\n type: 'number',\n description: 'Maximum number of PIDs in the container',\n },\n readonlyRootfs: {\n type: 'boolean',\n description: 'Mount the container root filesystem as read-only',\n },\n capDrop: {\n type: 'array',\n description: 'Linux capabilities to drop',\n items: { type: 'string' },\n },\n capAdd: {\n type: 'array',\n description: 'Linux capabilities to add',\n items: { type: 'string' },\n },\n securityOpt: {\n type: 'array',\n description: 'Docker security options',\n items: { type: 'string' },\n },\n ulimits: {\n type: 'array',\n description: 'Ulimit entries for Docker HostConfig.Ulimits',\n items: {\n type: 'object',\n required: ['name', 'soft', 'hard'],\n additionalProperties: false,\n properties: {\n name: { type: 'string' },\n soft: { type: 'number' },\n hard: { type: 'number' },\n },\n },\n },\n tmpfs: {\n type: 'object',\n description: 'tmpfs mount paths with options',\n additionalProperties: { type: 'string' },\n },\n },\n },\n createSandbox: (config: DockerProviderConfig) => new DockerSandbox(config as DockerSandboxOptions),\n};\n"]}
|