@elie-laloum/outpost 2.0.0 → 3.0.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 +24 -0
- package/dist/adapters/agents/claude-diagnostics.d.ts +1 -0
- package/dist/adapters/agents/claude-diagnostics.js +7 -0
- package/dist/adapters/agents/claude-diagnostics.js.map +1 -0
- package/dist/adapters/agents/cli-diagnostics.constants.d.ts +12 -0
- package/dist/adapters/agents/cli-diagnostics.constants.js +24 -0
- package/dist/adapters/agents/cli-diagnostics.constants.js.map +1 -0
- package/dist/adapters/agents/cli-diagnostics.d.ts +4 -0
- package/dist/adapters/agents/cli-diagnostics.js +14 -0
- package/dist/adapters/agents/cli-diagnostics.js.map +1 -0
- package/dist/adapters/agents/cli-diagnostics.types.d.ts +13 -0
- package/dist/adapters/agents/cli-diagnostics.types.js +2 -0
- package/dist/adapters/agents/cli-diagnostics.types.js.map +1 -0
- package/dist/adapters/agents/codex-diagnostics.d.ts +1 -0
- package/dist/adapters/agents/codex-diagnostics.js +7 -0
- package/dist/adapters/agents/codex-diagnostics.js.map +1 -0
- package/dist/adapters/agents/protocol-fixtures.constants.d.ts +2 -0
- package/dist/adapters/agents/protocol-fixtures.constants.js +68 -0
- package/dist/adapters/agents/protocol-fixtures.constants.js.map +1 -0
- package/dist/adapters/agents/protocol-fixtures.types.d.ts +6 -0
- package/dist/adapters/agents/protocol-fixtures.types.js +2 -0
- package/dist/adapters/agents/protocol-fixtures.types.js.map +1 -0
- package/dist/application/diagnostic-probe.d.ts +3 -0
- package/dist/application/diagnostic-probe.js +55 -0
- package/dist/application/diagnostic-probe.js.map +1 -0
- package/dist/application/doctor-agent.constants.d.ts +9 -0
- package/dist/application/doctor-agent.constants.js +8 -0
- package/dist/application/doctor-agent.constants.js.map +1 -0
- package/dist/application/doctor-agent.d.ts +3 -0
- package/dist/application/doctor-agent.js +53 -0
- package/dist/application/doctor-agent.js.map +1 -0
- package/dist/application/doctor-image.d.ts +3 -0
- package/dist/application/doctor-image.js +133 -0
- package/dist/application/doctor-image.js.map +1 -0
- package/dist/application/doctor-protocol.d.ts +3 -0
- package/dist/application/doctor-protocol.js +29 -0
- package/dist/application/doctor-protocol.js.map +1 -0
- package/dist/application/doctor-protocol.types.d.ts +10 -0
- package/dist/application/doctor-protocol.types.js +2 -0
- package/dist/application/doctor-protocol.types.js.map +1 -0
- package/dist/application/doctor-sandbox.constants.d.ts +5 -0
- package/dist/application/doctor-sandbox.constants.js +6 -0
- package/dist/application/doctor-sandbox.constants.js.map +1 -0
- package/dist/application/doctor-sandbox.d.ts +4 -0
- package/dist/application/doctor-sandbox.js +133 -0
- package/dist/application/doctor-sandbox.js.map +1 -0
- package/dist/application/doctor-sandbox.types.d.ts +23 -0
- package/dist/application/doctor-sandbox.types.js +2 -0
- package/dist/application/doctor-sandbox.types.js.map +1 -0
- package/dist/application/doctor-transfers.constants.d.ts +6 -0
- package/dist/application/doctor-transfers.constants.js +7 -0
- package/dist/application/doctor-transfers.constants.js.map +1 -0
- package/dist/application/doctor-transfers.d.ts +4 -0
- package/dist/application/doctor-transfers.js +88 -0
- package/dist/application/doctor-transfers.js.map +1 -0
- package/dist/application/doctor.constants.d.ts +9 -0
- package/dist/application/doctor.constants.js +15 -0
- package/dist/application/doctor.constants.js.map +1 -0
- package/dist/application/doctor.d.ts +3 -0
- package/dist/application/doctor.js +106 -0
- package/dist/application/doctor.js.map +1 -0
- package/dist/application/doctor.types.d.ts +39 -0
- package/dist/application/doctor.types.js +2 -0
- package/dist/application/doctor.types.js.map +1 -0
- package/dist/application/execution.js +1 -0
- package/dist/application/execution.js.map +1 -1
- package/dist/application/outpost.types.d.ts +2 -0
- package/dist/application/outpost.types.js.map +1 -1
- package/dist/application/recovery-checksum-capture.d.ts +2 -0
- package/dist/application/recovery-checksum-capture.js +32 -0
- package/dist/application/recovery-checksum-capture.js.map +1 -0
- package/dist/application/recovery-checksum-paths.d.ts +2 -0
- package/dist/application/recovery-checksum-paths.js +11 -0
- package/dist/application/recovery-checksum-paths.js.map +1 -0
- package/dist/application/recovery-checksums.constants.d.ts +5 -0
- package/dist/application/recovery-checksums.constants.js +6 -0
- package/dist/application/recovery-checksums.constants.js.map +1 -0
- package/dist/application/recovery-checksums.d.ts +3 -0
- package/dist/application/recovery-checksums.js +94 -0
- package/dist/application/recovery-checksums.js.map +1 -0
- package/dist/application/recovery-checksums.types.d.ts +17 -0
- package/dist/application/recovery-checksums.types.js +2 -0
- package/dist/application/recovery-checksums.types.js.map +1 -0
- package/dist/application/recovery-inspection.d.ts +2 -0
- package/dist/application/recovery-inspection.js +27 -0
- package/dist/application/recovery-inspection.js.map +1 -0
- package/dist/application/recovery-inspection.types.d.ts +15 -0
- package/dist/application/recovery-inspection.types.js +2 -0
- package/dist/application/recovery-inspection.types.js.map +1 -0
- package/dist/application/recovery-restorability.d.ts +2 -0
- package/dist/application/recovery-restorability.js +137 -0
- package/dist/application/recovery-restorability.js.map +1 -0
- package/dist/application/recovery-retention-policy.d.ts +2 -0
- package/dist/application/recovery-retention-policy.js +21 -0
- package/dist/application/recovery-retention-policy.js.map +1 -0
- package/dist/application/recovery-retention.constants.d.ts +3 -0
- package/dist/application/recovery-retention.constants.js +2 -0
- package/dist/application/recovery-retention.constants.js.map +1 -0
- package/dist/application/recovery-retention.d.ts +4 -0
- package/dist/application/recovery-retention.js +202 -0
- package/dist/application/recovery-retention.js.map +1 -0
- package/dist/application/recovery-retention.types.d.ts +52 -0
- package/dist/application/recovery-retention.types.js +2 -0
- package/dist/application/recovery-retention.types.js.map +1 -0
- package/dist/application/recovery-verification.constants.d.ts +5 -0
- package/dist/application/recovery-verification.constants.js +10 -0
- package/dist/application/recovery-verification.constants.js.map +1 -0
- package/dist/application/recovery-verification.d.ts +2 -0
- package/dist/application/recovery-verification.js +107 -0
- package/dist/application/recovery-verification.js.map +1 -0
- package/dist/application/recovery-verification.types.d.ts +26 -0
- package/dist/application/recovery-verification.types.js +2 -0
- package/dist/application/recovery-verification.types.js.map +1 -0
- package/dist/application/remote-apply.js +24 -6
- package/dist/application/remote-apply.js.map +1 -1
- package/dist/application/remote-backup.js +6 -2
- package/dist/application/remote-backup.js.map +1 -1
- package/dist/application/remote-download.js +36 -4
- package/dist/application/remote-download.js.map +1 -1
- package/dist/application/remote-validation.js +19 -0
- package/dist/application/remote-validation.js.map +1 -1
- package/dist/application/remote-workspace.constants.d.ts +3 -0
- package/dist/application/remote-workspace.constants.js +2 -0
- package/dist/application/remote-workspace.constants.js.map +1 -0
- package/dist/application/remote-workspace.js +6 -0
- package/dist/application/remote-workspace.js.map +1 -1
- package/dist/application/remote-workspace.types.d.ts +3 -1
- package/dist/application/remote-workspace.types.js.map +1 -1
- package/dist/application/sandbox.js +11 -0
- package/dist/application/sandbox.js.map +1 -1
- package/dist/application/task-usage.d.ts +4 -0
- package/dist/application/task-usage.js +41 -0
- package/dist/application/task-usage.js.map +1 -0
- package/dist/application/task-usage.types.d.ts +5 -0
- package/dist/application/task-usage.types.js +2 -0
- package/dist/application/task-usage.types.js.map +1 -0
- package/dist/application/tasks.js +23 -2
- package/dist/application/tasks.js.map +1 -1
- package/dist/cli/commands.js +4 -0
- package/dist/cli/commands.js.map +1 -1
- package/dist/cli/doctor-command.d.ts +3 -0
- package/dist/cli/doctor-command.js +38 -0
- package/dist/cli/doctor-command.js.map +1 -0
- package/dist/cli/main.constants.d.ts +28 -1
- package/dist/cli/main.constants.js +15 -0
- package/dist/cli/main.constants.js.map +1 -1
- package/dist/cli/recovery-command.d.ts +2 -0
- package/dist/cli/recovery-command.js +69 -0
- package/dist/cli/recovery-command.js.map +1 -0
- package/dist/cli/recovery-prune-command.d.ts +2 -0
- package/dist/cli/recovery-prune-command.js +34 -0
- package/dist/cli/recovery-prune-command.js.map +1 -0
- package/dist/cli/recovery-verify-command.d.ts +2 -0
- package/dist/cli/recovery-verify-command.js +43 -0
- package/dist/cli/recovery-verify-command.js.map +1 -0
- package/dist/domain/ports.d.ts +1 -1
- package/dist/domain/ports.js.map +1 -1
- package/dist/domain/sandbox.types.d.ts +12 -0
- package/dist/domain/sandbox.types.js.map +1 -1
- package/dist/domain/workflow/budget.constants.d.ts +1 -0
- package/dist/domain/workflow/budget.constants.js +7 -0
- package/dist/domain/workflow/budget.constants.js.map +1 -0
- package/dist/domain/workflow/budget.d.ts +9 -0
- package/dist/domain/workflow/budget.js +67 -0
- package/dist/domain/workflow/budget.js.map +1 -0
- package/dist/domain/workflow/budget.types.d.ts +15 -0
- package/dist/domain/workflow/budget.types.js +2 -0
- package/dist/domain/workflow/budget.types.js.map +1 -0
- package/dist/domain/workflow/task-runner.js +8 -1
- package/dist/domain/workflow/task-runner.js.map +1 -1
- package/dist/domain/workflow/workflow-scheduler.js +4 -2
- package/dist/domain/workflow/workflow-scheduler.js.map +1 -1
- package/dist/domain/workflow/workflow-state.js +29 -0
- package/dist/domain/workflow/workflow-state.js.map +1 -1
- package/dist/domain/workflow.d.ts +2 -0
- package/dist/domain/workflow.js +1 -0
- package/dist/domain/workflow.js.map +1 -1
- package/dist/domain/workflow.types.d.ts +10 -1
- package/dist/domain/workflow.types.js.map +1 -1
- package/dist/index.d.ts +12 -3
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/file-manifest.d.ts +6 -0
- package/dist/infrastructure/file-manifest.js +91 -0
- package/dist/infrastructure/file-manifest.js.map +1 -0
- package/dist/infrastructure/git/lock-inspection.constants.d.ts +4 -0
- package/dist/infrastructure/git/lock-inspection.constants.js +5 -0
- package/dist/infrastructure/git/lock-inspection.constants.js.map +1 -0
- package/dist/infrastructure/git/lock-inspection.d.ts +3 -0
- package/dist/infrastructure/git/lock-inspection.js +64 -0
- package/dist/infrastructure/git/lock-inspection.js.map +1 -0
- package/dist/infrastructure/git/lock-inspection.types.d.ts +27 -0
- package/dist/infrastructure/git/lock-inspection.types.js +2 -0
- package/dist/infrastructure/git/lock-inspection.types.js.map +1 -0
- package/dist/infrastructure/git/lock.d.ts +1 -0
- package/dist/infrastructure/git/lock.js +70 -29
- package/dist/infrastructure/git/lock.js.map +1 -1
- package/dist/infrastructure/git/process-identity.d.ts +3 -0
- package/dist/infrastructure/git/process-identity.js +73 -0
- package/dist/infrastructure/git/process-identity.js.map +1 -0
- package/dist/infrastructure/git/process-identity.types.d.ts +10 -0
- package/dist/infrastructure/git/process-identity.types.js +2 -0
- package/dist/infrastructure/git/process-identity.types.js.map +1 -0
- package/dist/infrastructure/git/verification-command.d.ts +1 -0
- package/dist/infrastructure/git/verification-command.js +36 -0
- package/dist/infrastructure/git/verification-command.js.map +1 -0
- package/dist/infrastructure/git/workspace-lease.js +1 -0
- package/dist/infrastructure/git/workspace-lease.js.map +1 -1
- package/dist/infrastructure/git/workspace.js +5 -1
- package/dist/infrastructure/git/workspace.js.map +1 -1
- package/dist/infrastructure/git/worktree-inspection.constants.d.ts +5 -0
- package/dist/infrastructure/git/worktree-inspection.constants.js +16 -0
- package/dist/infrastructure/git/worktree-inspection.constants.js.map +1 -0
- package/dist/infrastructure/git/worktree-inspection.d.ts +3 -0
- package/dist/infrastructure/git/worktree-inspection.js +120 -0
- package/dist/infrastructure/git/worktree-inspection.js.map +1 -0
- package/dist/infrastructure/git/worktree-inspection.types.d.ts +19 -0
- package/dist/infrastructure/git/worktree-inspection.types.js +2 -0
- package/dist/infrastructure/git/worktree-inspection.types.js.map +1 -0
- package/dist/infrastructure/inspection-file.constants.d.ts +1 -0
- package/dist/infrastructure/inspection-file.constants.js +5 -0
- package/dist/infrastructure/inspection-file.constants.js.map +1 -0
- package/dist/infrastructure/inspection-file.d.ts +1 -0
- package/dist/infrastructure/inspection-file.js +43 -0
- package/dist/infrastructure/inspection-file.js.map +1 -0
- package/dist/infrastructure/inspection-hash.constants.d.ts +1 -0
- package/dist/infrastructure/inspection-hash.constants.js +2 -0
- package/dist/infrastructure/inspection-hash.constants.js.map +1 -0
- package/dist/infrastructure/inspection-hash.d.ts +2 -0
- package/dist/infrastructure/inspection-hash.js +62 -0
- package/dist/infrastructure/inspection-hash.js.map +1 -0
- package/dist/infrastructure/inspection-hash.types.d.ts +5 -0
- package/dist/infrastructure/inspection-hash.types.js +2 -0
- package/dist/infrastructure/inspection-hash.types.js.map +1 -0
- package/dist/infrastructure/journal-retention.constants.d.ts +4 -0
- package/dist/infrastructure/journal-retention.constants.js +5 -0
- package/dist/infrastructure/journal-retention.constants.js.map +1 -0
- package/dist/infrastructure/journal-retention.d.ts +2 -0
- package/dist/infrastructure/journal-retention.js +51 -0
- package/dist/infrastructure/journal-retention.js.map +1 -0
- package/dist/infrastructure/journal.js +37 -13
- package/dist/infrastructure/journal.js.map +1 -1
- package/dist/infrastructure/opentelemetry.constants.d.ts +10 -0
- package/dist/infrastructure/opentelemetry.constants.js +11 -0
- package/dist/infrastructure/opentelemetry.constants.js.map +1 -0
- package/dist/infrastructure/opentelemetry.d.ts +3 -0
- package/dist/infrastructure/opentelemetry.js +131 -0
- package/dist/infrastructure/opentelemetry.js.map +1 -0
- package/dist/infrastructure/opentelemetry.types.d.ts +21 -0
- package/dist/infrastructure/opentelemetry.types.js +2 -0
- package/dist/infrastructure/opentelemetry.types.js.map +1 -0
- package/dist/infrastructure/storage-inventory.constants.d.ts +6 -0
- package/dist/infrastructure/storage-inventory.constants.js +11 -0
- package/dist/infrastructure/storage-inventory.constants.js.map +1 -0
- package/dist/infrastructure/storage-inventory.d.ts +2 -0
- package/dist/infrastructure/storage-inventory.js +123 -0
- package/dist/infrastructure/storage-inventory.js.map +1 -0
- package/dist/infrastructure/storage-inventory.types.d.ts +38 -0
- package/dist/infrastructure/storage-inventory.types.js +2 -0
- package/dist/infrastructure/storage-inventory.types.js.map +1 -0
- package/dist/infrastructure/transfer.js +12 -0
- package/dist/infrastructure/transfer.js.map +1 -1
- package/dist/providers/cloud.constants.d.ts +1 -0
- package/dist/providers/cloud.constants.js +1 -0
- package/dist/providers/cloud.constants.js.map +1 -1
- package/dist/providers/container-cache.constants.d.ts +11 -0
- package/dist/providers/container-cache.constants.js +9 -0
- package/dist/providers/container-cache.constants.js.map +1 -0
- package/dist/providers/container-cache.d.ts +4 -0
- package/dist/providers/container-cache.js +48 -0
- package/dist/providers/container-cache.js.map +1 -0
- package/dist/providers/container-cache.types.d.ts +8 -0
- package/dist/providers/container-cache.types.js +2 -0
- package/dist/providers/container-cache.types.js.map +1 -0
- package/dist/providers/container-plan.js +3 -1
- package/dist/providers/container-plan.js.map +1 -1
- package/dist/providers/container.js +31 -1
- package/dist/providers/container.js.map +1 -1
- package/dist/providers/container.types.d.ts +2 -0
- package/dist/providers/container.types.js.map +1 -1
- package/dist/providers/daytona-command.js +7 -4
- package/dist/providers/daytona-command.js.map +1 -1
- package/dist/providers/daytona.js +13 -4
- package/dist/providers/daytona.js.map +1 -1
- package/dist/providers/diagnostic-container.d.ts +4 -0
- package/dist/providers/diagnostic-container.js +15 -0
- package/dist/providers/diagnostic-container.js.map +1 -0
- package/dist/providers/docker.d.ts +1 -0
- package/dist/providers/docker.js.map +1 -1
- package/dist/providers/file-batches.constants.d.ts +10 -0
- package/dist/providers/file-batches.constants.js +57 -0
- package/dist/providers/file-batches.constants.js.map +1 -0
- package/dist/providers/file-batches.d.ts +2 -0
- package/dist/providers/file-batches.js +151 -0
- package/dist/providers/file-batches.js.map +1 -0
- package/dist/providers/podman.d.ts +1 -0
- package/dist/providers/podman.js.map +1 -1
- package/dist/providers/vercel.js +3 -1
- package/dist/providers/vercel.js.map +1 -1
- package/package.json +12 -1
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { lstat, opendir } from "node:fs/promises";
|
|
2
|
+
import { basename, join } from "node:path";
|
|
3
|
+
import { positive } from "../domain/errors.js";
|
|
4
|
+
import { storageCategories, storageInventoryDefaults, } from "./storage-inventory.constants.js";
|
|
5
|
+
function usage() {
|
|
6
|
+
return { bytes: 0, files: 0, directories: 0, symlinks: 0, other: 0 };
|
|
7
|
+
}
|
|
8
|
+
function addUsage(target, incoming) {
|
|
9
|
+
target.bytes += incoming.bytes;
|
|
10
|
+
target.files += incoming.files;
|
|
11
|
+
target.directories += incoming.directories;
|
|
12
|
+
target.symlinks += incoming.symlinks;
|
|
13
|
+
target.other += incoming.other;
|
|
14
|
+
}
|
|
15
|
+
function errorCode(error) {
|
|
16
|
+
if (error &&
|
|
17
|
+
typeof error === "object" &&
|
|
18
|
+
"code" in error &&
|
|
19
|
+
typeof error.code === "string")
|
|
20
|
+
return error.code;
|
|
21
|
+
return "UNAVAILABLE";
|
|
22
|
+
}
|
|
23
|
+
async function availableDirectory(path, scan) {
|
|
24
|
+
try {
|
|
25
|
+
const info = await lstat(path);
|
|
26
|
+
if (info.isDirectory() && !info.isSymbolicLink())
|
|
27
|
+
return true;
|
|
28
|
+
scan.issues.push({
|
|
29
|
+
path,
|
|
30
|
+
code: info.isSymbolicLink() ? "SYMLINK_ROOT" : "NOT_DIRECTORY",
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
if (errorCode(error) !== "ENOENT")
|
|
35
|
+
scan.issues.push({ path, code: errorCode(error) });
|
|
36
|
+
}
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
async function measure(path, scan, depth) {
|
|
40
|
+
const startIssues = scan.issues.length;
|
|
41
|
+
const entry = {
|
|
42
|
+
...usage(),
|
|
43
|
+
name: basename(path),
|
|
44
|
+
path,
|
|
45
|
+
kind: "unknown",
|
|
46
|
+
complete: true,
|
|
47
|
+
};
|
|
48
|
+
if (scan.remaining === 0) {
|
|
49
|
+
scan.issues.push({ path, code: "ENTRY_LIMIT" });
|
|
50
|
+
return { ...entry, complete: false };
|
|
51
|
+
}
|
|
52
|
+
scan.remaining--;
|
|
53
|
+
try {
|
|
54
|
+
const info = await lstat(path);
|
|
55
|
+
entry.modifiedAt = info.mtime.toISOString();
|
|
56
|
+
if (info.isSymbolicLink())
|
|
57
|
+
return { ...entry, kind: "symlink", symlinks: 1 };
|
|
58
|
+
if (info.isFile())
|
|
59
|
+
return { ...entry, kind: "file", files: 1, bytes: info.size };
|
|
60
|
+
if (!info.isDirectory()) {
|
|
61
|
+
scan.issues.push({ path, code: "UNSUPPORTED_TYPE" });
|
|
62
|
+
return { ...entry, kind: "other", other: 1, complete: false };
|
|
63
|
+
}
|
|
64
|
+
entry.kind = "directory";
|
|
65
|
+
entry.directories = 1;
|
|
66
|
+
if (depth >= storageInventoryDefaults.maxDepth) {
|
|
67
|
+
scan.issues.push({ path, code: "DEPTH_LIMIT" });
|
|
68
|
+
return { ...entry, complete: false };
|
|
69
|
+
}
|
|
70
|
+
for await (const child of await opendir(path)) {
|
|
71
|
+
const nested = await measure(join(path, child.name), scan, depth + 1);
|
|
72
|
+
addUsage(entry, nested);
|
|
73
|
+
if (nested.modifiedAt && nested.modifiedAt > entry.modifiedAt)
|
|
74
|
+
entry.modifiedAt = nested.modifiedAt;
|
|
75
|
+
if (!nested.complete)
|
|
76
|
+
entry.complete = false;
|
|
77
|
+
if (scan.remaining === 0 && !nested.complete)
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
scan.issues.push({ path, code: errorCode(error) });
|
|
83
|
+
}
|
|
84
|
+
entry.complete = entry.complete && scan.issues.length === startIssues;
|
|
85
|
+
return entry;
|
|
86
|
+
}
|
|
87
|
+
export async function storageInventory(root, maxEntries = storageInventoryDefaults.maxEntries) {
|
|
88
|
+
positive(maxEntries, "maxEntries");
|
|
89
|
+
const scan = { remaining: maxEntries, issues: [] };
|
|
90
|
+
const categories = [];
|
|
91
|
+
const total = usage();
|
|
92
|
+
const available = await availableDirectory(root, scan);
|
|
93
|
+
for (const name of storageCategories) {
|
|
94
|
+
const path = join(root, name);
|
|
95
|
+
const entries = [];
|
|
96
|
+
if (available && (await availableDirectory(path, scan))) {
|
|
97
|
+
try {
|
|
98
|
+
for await (const child of await opendir(path)) {
|
|
99
|
+
const entry = await measure(join(path, child.name), scan, 0);
|
|
100
|
+
entries.push(entry);
|
|
101
|
+
addUsage(total, entry);
|
|
102
|
+
if (scan.remaining === 0 && !entry.complete)
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
scan.issues.push({ path, code: errorCode(error) });
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
entries.sort((left, right) => left.name < right.name ? -1 : Number(left.name > right.name));
|
|
111
|
+
categories.push({ name, path, entries });
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
root,
|
|
115
|
+
categories,
|
|
116
|
+
usage: total,
|
|
117
|
+
issues: scan.issues,
|
|
118
|
+
complete: scan.issues.length === 0,
|
|
119
|
+
scannedEntries: maxEntries - scan.remaining,
|
|
120
|
+
maxEntries,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=storage-inventory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage-inventory.js","sourceRoot":"","sources":["../../src/infrastructure/storage-inventory.ts"],"names":[],"mappings":"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","sourcesContent":["import { lstat, opendir } from \"node:fs/promises\";\nimport { basename, join } from \"node:path\";\nimport { positive } from \"../domain/errors.ts\";\nimport {\n storageCategories,\n storageInventoryDefaults,\n} from \"./storage-inventory.constants.ts\";\nimport type {\n StorageCategory,\n StorageEntry,\n StorageInventory,\n StorageScan,\n StorageUsage,\n} from \"./storage-inventory.types.ts\";\n\nfunction usage(): StorageUsage {\n return { bytes: 0, files: 0, directories: 0, symlinks: 0, other: 0 };\n}\nfunction addUsage(\n target: StorageUsage,\n incoming: Readonly<StorageUsage>,\n): void {\n target.bytes += incoming.bytes;\n target.files += incoming.files;\n target.directories += incoming.directories;\n target.symlinks += incoming.symlinks;\n target.other += incoming.other;\n}\nfunction errorCode(error: unknown): string {\n if (\n error &&\n typeof error === \"object\" &&\n \"code\" in error &&\n typeof error.code === \"string\"\n )\n return error.code;\n return \"UNAVAILABLE\";\n}\nasync function availableDirectory(\n path: string,\n scan: StorageScan,\n): Promise<boolean> {\n try {\n const info = await lstat(path);\n if (info.isDirectory() && !info.isSymbolicLink()) return true;\n scan.issues.push({\n path,\n code: info.isSymbolicLink() ? \"SYMLINK_ROOT\" : \"NOT_DIRECTORY\",\n });\n } catch (error) {\n if (errorCode(error) !== \"ENOENT\")\n scan.issues.push({ path, code: errorCode(error) });\n }\n return false;\n}\nasync function measure(\n path: string,\n scan: StorageScan,\n depth: number,\n): Promise<StorageEntry> {\n const startIssues = scan.issues.length;\n const entry: StorageEntry = {\n ...usage(),\n name: basename(path),\n path,\n kind: \"unknown\",\n complete: true,\n };\n if (scan.remaining === 0) {\n scan.issues.push({ path, code: \"ENTRY_LIMIT\" });\n return { ...entry, complete: false };\n }\n scan.remaining--;\n try {\n const info = await lstat(path);\n entry.modifiedAt = info.mtime.toISOString();\n if (info.isSymbolicLink())\n return { ...entry, kind: \"symlink\", symlinks: 1 };\n if (info.isFile())\n return { ...entry, kind: \"file\", files: 1, bytes: info.size };\n if (!info.isDirectory()) {\n scan.issues.push({ path, code: \"UNSUPPORTED_TYPE\" });\n return { ...entry, kind: \"other\", other: 1, complete: false };\n }\n entry.kind = \"directory\";\n entry.directories = 1;\n if (depth >= storageInventoryDefaults.maxDepth) {\n scan.issues.push({ path, code: \"DEPTH_LIMIT\" });\n return { ...entry, complete: false };\n }\n for await (const child of await opendir(path)) {\n const nested = await measure(join(path, child.name), scan, depth + 1);\n addUsage(entry, nested);\n if (nested.modifiedAt && nested.modifiedAt > entry.modifiedAt)\n entry.modifiedAt = nested.modifiedAt;\n if (!nested.complete) entry.complete = false;\n if (scan.remaining === 0 && !nested.complete) break;\n }\n } catch (error) {\n scan.issues.push({ path, code: errorCode(error) });\n }\n entry.complete = entry.complete && scan.issues.length === startIssues;\n return entry;\n}\n\nexport async function storageInventory(\n root: string,\n maxEntries: number = storageInventoryDefaults.maxEntries,\n): Promise<StorageInventory> {\n positive(maxEntries, \"maxEntries\");\n const scan: StorageScan = { remaining: maxEntries, issues: [] };\n const categories: StorageCategory[] = [];\n const total = usage();\n const available = await availableDirectory(root, scan);\n for (const name of storageCategories) {\n const path = join(root, name);\n const entries: StorageEntry[] = [];\n if (available && (await availableDirectory(path, scan))) {\n try {\n for await (const child of await opendir(path)) {\n const entry = await measure(join(path, child.name), scan, 0);\n entries.push(entry);\n addUsage(total, entry);\n if (scan.remaining === 0 && !entry.complete) break;\n }\n } catch (error) {\n scan.issues.push({ path, code: errorCode(error) });\n }\n }\n entries.sort((left, right) =>\n left.name < right.name ? -1 : Number(left.name > right.name),\n );\n categories.push({ name, path, entries });\n }\n return {\n root,\n categories,\n usage: total,\n issues: scan.issues,\n complete: scan.issues.length === 0,\n scannedEntries: maxEntries - scan.remaining,\n maxEntries,\n };\n}\n"]}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export type StorageCategoryName = "recovery" | "logs" | "locks" | "workspaces";
|
|
2
|
+
export type StorageEntryKind = "file" | "directory" | "symlink" | "other" | "unknown";
|
|
3
|
+
export interface StorageIssue {
|
|
4
|
+
readonly path: string;
|
|
5
|
+
readonly code: string;
|
|
6
|
+
}
|
|
7
|
+
export interface StorageUsage {
|
|
8
|
+
bytes: number;
|
|
9
|
+
files: number;
|
|
10
|
+
directories: number;
|
|
11
|
+
symlinks: number;
|
|
12
|
+
other: number;
|
|
13
|
+
}
|
|
14
|
+
export interface StorageEntry extends StorageUsage {
|
|
15
|
+
readonly name: string;
|
|
16
|
+
readonly path: string;
|
|
17
|
+
kind: StorageEntryKind;
|
|
18
|
+
modifiedAt?: string;
|
|
19
|
+
complete: boolean;
|
|
20
|
+
}
|
|
21
|
+
export interface StorageCategory {
|
|
22
|
+
readonly name: StorageCategoryName;
|
|
23
|
+
readonly path: string;
|
|
24
|
+
readonly entries: readonly StorageEntry[];
|
|
25
|
+
}
|
|
26
|
+
export interface StorageInventory {
|
|
27
|
+
readonly root: string;
|
|
28
|
+
readonly categories: readonly StorageCategory[];
|
|
29
|
+
readonly usage: Readonly<StorageUsage>;
|
|
30
|
+
readonly issues: readonly StorageIssue[];
|
|
31
|
+
readonly complete: boolean;
|
|
32
|
+
readonly scannedEntries: number;
|
|
33
|
+
readonly maxEntries: number;
|
|
34
|
+
}
|
|
35
|
+
export interface StorageScan {
|
|
36
|
+
remaining: number;
|
|
37
|
+
readonly issues: StorageIssue[];
|
|
38
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage-inventory.types.js","sourceRoot":"","sources":["../../src/infrastructure/storage-inventory.types.ts"],"names":[],"mappings":"","sourcesContent":["export type StorageCategoryName = \"recovery\" | \"logs\" | \"locks\" | \"workspaces\";\nexport type StorageEntryKind =\n \"file\" | \"directory\" | \"symlink\" | \"other\" | \"unknown\";\n\nexport interface StorageIssue {\n readonly path: string;\n readonly code: string;\n}\nexport interface StorageUsage {\n bytes: number;\n files: number;\n directories: number;\n symlinks: number;\n other: number;\n}\nexport interface StorageEntry extends StorageUsage {\n readonly name: string;\n readonly path: string;\n kind: StorageEntryKind;\n modifiedAt?: string;\n complete: boolean;\n}\nexport interface StorageCategory {\n readonly name: StorageCategoryName;\n readonly path: string;\n readonly entries: readonly StorageEntry[];\n}\nexport interface StorageInventory {\n readonly root: string;\n readonly categories: readonly StorageCategory[];\n readonly usage: Readonly<StorageUsage>;\n readonly issues: readonly StorageIssue[];\n readonly complete: boolean;\n readonly scannedEntries: number;\n readonly maxEntries: number;\n}\nexport interface StorageScan {\n remaining: number;\n readonly issues: StorageIssue[];\n}\n"]}
|
|
@@ -25,6 +25,18 @@ export function boundedTransfers(lease, defaults) {
|
|
|
25
25
|
release: lease.release.bind(lease),
|
|
26
26
|
upload: copy("upload"),
|
|
27
27
|
download: copy("download"),
|
|
28
|
+
...(lease.fileTransfers
|
|
29
|
+
? {
|
|
30
|
+
fileTransfers: {
|
|
31
|
+
manifest: (source, paths, options = {}) => transfer({ ...defaults, ...options }, (signal) => lease.fileTransfers.manifest(source, paths, {
|
|
32
|
+
...defaults,
|
|
33
|
+
...options,
|
|
34
|
+
signal,
|
|
35
|
+
})),
|
|
36
|
+
downloadBatch: (source, entries, destination, options = {}) => transfer({ ...defaults, ...options }, (signal) => lease.fileTransfers.downloadBatch(source, entries, destination, { ...defaults, ...options, signal })),
|
|
37
|
+
},
|
|
38
|
+
}
|
|
39
|
+
: {}),
|
|
28
40
|
};
|
|
29
41
|
}
|
|
30
42
|
//# sourceMappingURL=transfer.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transfer.js","sourceRoot":"","sources":["../../src/infrastructure/transfer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAE9D,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAE3D,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,OAAwB,EACxB,OAA4C;IAE5C,OAAO,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC;IACjC,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,gBAAgB,CAAC,UAAU,CAAC;IACrE,SAAS,CACP,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,UAAU,GAAG,CAAC,EAC7C,oCAAoC,CACrC,CAAC;IACF,MAAM,IAAI,GAAG,IAAI,eAAe,EAAE,CAAC;IACnC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM;QAC3B,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAChD,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;IAChB,MAAM,KAAK,GAAG,UAAU,CACtB,GAAG,EAAE,CACH,IAAI,CAAC,KAAK,CACR,IAAI,YAAY,CAAC,SAAS,EAAE,yBAAyB,EAAE,EAAE,UAAU,EAAE,CAAC,CACvE,EACH,UAAU,CACX,CAAC;IACF,IAAI,CAAC;QACH,OAAO,MAAM,aAAa,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC;IACtD,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,KAAmB,EACnB,QAAyB;IAEzB,MAAM,IAAI,GACR,CAAC,MAA6B,EAAE,EAAE,CAClC,CAAC,MAAc,EAAE,WAAmB,EAAE,UAA2B,EAAE,EAAE,EAAE,CACrE,QAAQ,CAAC,EAAE,GAAG,QAAQ,EAAE,GAAG,OAAO,EAAE,EAAE,CAAC,MAAM,EAAE,EAAE,CAC/C,KAAK,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE,GAAG,QAAQ,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,CAAC,CACxE,CAAC;IACN,OAAO;QACL,GAAG,KAAK;QACR,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;QAChC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC;QAClC,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC;QACtB,QAAQ,EAAE,IAAI,CAAC,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"transfer.js","sourceRoot":"","sources":["../../src/infrastructure/transfer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAE9D,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAE3D,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,OAAwB,EACxB,OAA4C;IAE5C,OAAO,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC;IACjC,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,gBAAgB,CAAC,UAAU,CAAC;IACrE,SAAS,CACP,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,UAAU,GAAG,CAAC,EAC7C,oCAAoC,CACrC,CAAC;IACF,MAAM,IAAI,GAAG,IAAI,eAAe,EAAE,CAAC;IACnC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM;QAC3B,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAChD,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;IAChB,MAAM,KAAK,GAAG,UAAU,CACtB,GAAG,EAAE,CACH,IAAI,CAAC,KAAK,CACR,IAAI,YAAY,CAAC,SAAS,EAAE,yBAAyB,EAAE,EAAE,UAAU,EAAE,CAAC,CACvE,EACH,UAAU,CACX,CAAC;IACF,IAAI,CAAC;QACH,OAAO,MAAM,aAAa,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC;IACtD,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,KAAmB,EACnB,QAAyB;IAEzB,MAAM,IAAI,GACR,CAAC,MAA6B,EAAE,EAAE,CAClC,CAAC,MAAc,EAAE,WAAmB,EAAE,UAA2B,EAAE,EAAE,EAAE,CACrE,QAAQ,CAAC,EAAE,GAAG,QAAQ,EAAE,GAAG,OAAO,EAAE,EAAE,CAAC,MAAM,EAAE,EAAE,CAC/C,KAAK,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE,GAAG,QAAQ,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,CAAC,CACxE,CAAC;IACN,OAAO;QACL,GAAG,KAAK;QACR,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;QAChC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC;QAClC,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC;QACtB,QAAQ,EAAE,IAAI,CAAC,UAAU,CAAC;QAC1B,GAAG,CAAC,KAAK,CAAC,aAAa;YACrB,CAAC,CAAC;gBACE,aAAa,EAAE;oBACb,QAAQ,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,EAAE,EAAE,EAAE,CACxC,QAAQ,CAAC,EAAE,GAAG,QAAQ,EAAE,GAAG,OAAO,EAAE,EAAE,CAAC,MAAM,EAAE,EAAE,CAC/C,KAAK,CAAC,aAAc,CAAC,QAAQ,CAAC,MAAM,EAAE,KAAK,EAAE;wBAC3C,GAAG,QAAQ;wBACX,GAAG,OAAO;wBACV,MAAM;qBACP,CAAC,CACH;oBACH,aAAa,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,GAAG,EAAE,EAAE,EAAE,CAC5D,QAAQ,CAAC,EAAE,GAAG,QAAQ,EAAE,GAAG,OAAO,EAAE,EAAE,CAAC,MAAM,EAAE,EAAE,CAC/C,KAAK,CAAC,aAAc,CAAC,aAAa,CAChC,MAAM,EACN,OAAO,EACP,WAAW,EACX,EAAE,GAAG,QAAQ,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,CACpC,CACF;iBACJ;aACF;YACH,CAAC,CAAC,EAAE,CAAC;KACR,CAAC;AACJ,CAAC","sourcesContent":["import { invariant, OutpostError } from \"../domain/errors.ts\";\nimport type { SandboxLease, TransferOptions } from \"../domain/sandbox.types.ts\";\nimport { interruptible } from \"./abort.ts\";\nimport { transferDefaults } from \"./transfer.constants.ts\";\n\nexport async function transfer<T>(\n options: TransferOptions,\n perform: (signal: AbortSignal) => Promise<T>,\n): Promise<T> {\n options.signal?.throwIfAborted();\n const deadlineMs = options.deadlineMs ?? transferDefaults.deadlineMs;\n invariant(\n Number.isFinite(deadlineMs) && deadlineMs > 0,\n \"Transfer deadline must be positive\",\n );\n const stop = new AbortController();\n const signal = options.signal\n ? AbortSignal.any([options.signal, stop.signal])\n : stop.signal;\n const timer = setTimeout(\n () =>\n stop.abort(\n new OutpostError(\"timeout\", \"File transfer timed out\", { deadlineMs }),\n ),\n deadlineMs,\n );\n try {\n return await interruptible(perform(signal), signal);\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport function boundedTransfers(\n lease: SandboxLease,\n defaults: TransferOptions,\n): SandboxLease {\n const copy =\n (method: \"upload\" | \"download\") =>\n (source: string, destination: string, options: TransferOptions = {}) =>\n transfer({ ...defaults, ...options }, (signal) =>\n lease[method](source, destination, { ...defaults, ...options, signal }),\n );\n return {\n ...lease,\n invoke: lease.invoke.bind(lease),\n release: lease.release.bind(lease),\n upload: copy(\"upload\"),\n download: copy(\"download\"),\n ...(lease.fileTransfers\n ? {\n fileTransfers: {\n manifest: (source, paths, options = {}) =>\n transfer({ ...defaults, ...options }, (signal) =>\n lease.fileTransfers!.manifest(source, paths, {\n ...defaults,\n ...options,\n signal,\n }),\n ),\n downloadBatch: (source, entries, destination, options = {}) =>\n transfer({ ...defaults, ...options }, (signal) =>\n lease.fileTransfers!.downloadBatch(\n source,\n entries,\n destination,\n { ...defaults, ...options, signal },\n ),\n ),\n },\n }\n : {}),\n };\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cloud.constants.js","sourceRoot":"","sources":["../../src/providers/cloud.constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC;IACzC,UAAU,EAAE,OAAO;IACnB,WAAW,EAAE,MAAM;IACnB,cAAc,EAAE,MAAM;CACvB,CAAC,CAAC;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC;IACtC,MAAM,EAAE,yBAAyB;IACjC,WAAW,EAAE,eAAe;CAC7B,CAAC,CAAC","sourcesContent":["export const cloudDefaults = Object.freeze({\n deadlineMs: 600_000,\n retainBytes: 65_536,\n cancellationMs: 15_000,\n});\nexport const cloudRoots = Object.freeze({\n vercel: \"/vercel/sandbox/outpost\",\n daytonaHome: \"/home/daytona\",\n});\n"]}
|
|
1
|
+
{"version":3,"file":"cloud.constants.js","sourceRoot":"","sources":["../../src/providers/cloud.constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC;IACzC,UAAU,EAAE,OAAO;IACnB,WAAW,EAAE,MAAM;IACnB,MAAM,EAAE,GAAG;IACX,cAAc,EAAE,MAAM;CACvB,CAAC,CAAC;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC;IACtC,MAAM,EAAE,yBAAyB;IACjC,WAAW,EAAE,eAAe;CAC7B,CAAC,CAAC","sourcesContent":["export const cloudDefaults = Object.freeze({\n deadlineMs: 600_000,\n retainBytes: 65_536,\n pollMs: 100,\n cancellationMs: 15_000,\n});\nexport const cloudRoots = Object.freeze({\n vercel: \"/vercel/sandbox/outpost\",\n daytonaHome: \"/home/daytona\",\n});\n"]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare const cacheDefaults: Readonly<{
|
|
2
|
+
root: "/outpost/cache";
|
|
3
|
+
label: "io.outpost.cache";
|
|
4
|
+
version: 1;
|
|
5
|
+
namePattern: RegExp;
|
|
6
|
+
maximumKeyLength: 1024;
|
|
7
|
+
}>;
|
|
8
|
+
export declare const cacheCreateOptions: {
|
|
9
|
+
readonly docker: readonly [];
|
|
10
|
+
readonly podman: readonly ["--ignore"];
|
|
11
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const cacheDefaults = Object.freeze({
|
|
2
|
+
root: "/outpost/cache",
|
|
3
|
+
label: "io.outpost.cache",
|
|
4
|
+
version: 1,
|
|
5
|
+
namePattern: /^[a-z][a-z0-9-]{0,47}$/,
|
|
6
|
+
maximumKeyLength: 1024,
|
|
7
|
+
});
|
|
8
|
+
export const cacheCreateOptions = { docker: [], podman: ["--ignore"] };
|
|
9
|
+
//# sourceMappingURL=container-cache.constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"container-cache.constants.js","sourceRoot":"","sources":["../../src/providers/container-cache.constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC;IACzC,IAAI,EAAE,gBAAgB;IACtB,KAAK,EAAE,kBAAkB;IACzB,OAAO,EAAE,CAAC;IACV,WAAW,EAAE,wBAAwB;IACrC,gBAAgB,EAAE,IAAI;CACvB,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,kBAAkB,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,UAAU,CAAC,EAAW,CAAC","sourcesContent":["export const cacheDefaults = Object.freeze({\n root: \"/outpost/cache\",\n label: \"io.outpost.cache\",\n version: 1,\n namePattern: /^[a-z][a-z0-9-]{0,47}$/,\n maximumKeyLength: 1024,\n});\n\nexport const cacheCreateOptions = { docker: [], podman: [\"--ignore\"] } as const;\n"]}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { DependencyCache, ContainerCacheMount } from "./container-cache.types.ts";
|
|
2
|
+
import type { ContainerOptions, ContainerUser } from "./container.types.ts";
|
|
3
|
+
export declare function validateCaches(config: ContainerOptions): void;
|
|
4
|
+
export declare function cacheMounts(caches: readonly DependencyCache[], repository: string, image: string, user: ContainerUser): Promise<ContainerCacheMount[]>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { realpath } from "node:fs/promises";
|
|
3
|
+
import { posix } from "node:path";
|
|
4
|
+
import { invariant } from "../domain/errors.js";
|
|
5
|
+
import { cacheDefaults } from "./container-cache.constants.js";
|
|
6
|
+
export function validateCaches(config) {
|
|
7
|
+
const names = new Set();
|
|
8
|
+
for (const cache of config.caches ?? []) {
|
|
9
|
+
invariant(typeof cache.name === "string" &&
|
|
10
|
+
cacheDefaults.namePattern.test(cache.name), "Cache names must start with a lowercase letter and contain at most 48 lowercase letters, digits or hyphens");
|
|
11
|
+
invariant(!names.has(cache.name), `Duplicate cache name: ${cache.name}`);
|
|
12
|
+
invariant(typeof cache.key === "string" &&
|
|
13
|
+
cache.key.trim().length > 0 &&
|
|
14
|
+
cache.key.length <= cacheDefaults.maximumKeyLength, "Cache keys must be nonempty strings of at most 1024 characters");
|
|
15
|
+
names.add(cache.name);
|
|
16
|
+
}
|
|
17
|
+
if (!names.size)
|
|
18
|
+
return;
|
|
19
|
+
for (const volume of config.volumes ?? []) {
|
|
20
|
+
const target = posix.resolve("/workspace", volume.target.replaceAll("\\", "/"));
|
|
21
|
+
invariant(!(target === cacheDefaults.root ||
|
|
22
|
+
target.startsWith(cacheDefaults.root + "/") ||
|
|
23
|
+
cacheDefaults.root.startsWith(target.replace(/\/$/, "") + "/")), "Explicit volumes must not overlap dependency caches");
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export async function cacheMounts(caches, repository, image, user) {
|
|
27
|
+
if (!caches.length)
|
|
28
|
+
return [];
|
|
29
|
+
const canonical = await realpath(repository);
|
|
30
|
+
return caches.map(({ name, key }) => {
|
|
31
|
+
const digest = createHash("sha256")
|
|
32
|
+
.update(JSON.stringify([
|
|
33
|
+
cacheDefaults.version,
|
|
34
|
+
canonical,
|
|
35
|
+
image,
|
|
36
|
+
user.uid,
|
|
37
|
+
user.gid,
|
|
38
|
+
name,
|
|
39
|
+
key,
|
|
40
|
+
]))
|
|
41
|
+
.digest("hex");
|
|
42
|
+
return {
|
|
43
|
+
volume: `outpost-cache-${name}-${digest}`,
|
|
44
|
+
target: `${cacheDefaults.root}/${name}`,
|
|
45
|
+
};
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=container-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"container-cache.js","sourceRoot":"","sources":["../../src/providers/container-cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAO/D,MAAM,UAAU,cAAc,CAAC,MAAwB;IACrD,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC;QACxC,SAAS,CACP,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ;YAC5B,aAAa,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAC5C,4GAA4G,CAC7G,CAAC;QACF,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,yBAAyB,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;QACzE,SAAS,CACP,OAAO,KAAK,CAAC,GAAG,KAAK,QAAQ;YAC3B,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;YAC3B,KAAK,CAAC,GAAG,CAAC,MAAM,IAAI,aAAa,CAAC,gBAAgB,EACpD,gEAAgE,CACjE,CAAC;QACF,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACxB,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,IAAI;QAAE,OAAO;IACxB,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC;QAC1C,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAC1B,YAAY,EACZ,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CACpC,CAAC;QACF,SAAS,CACP,CAAC,CACC,MAAM,KAAK,aAAa,CAAC,IAAI;YAC7B,MAAM,CAAC,UAAU,CAAC,aAAa,CAAC,IAAI,GAAG,GAAG,CAAC;YAC3C,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAC/D,EACD,qDAAqD,CACtD,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,MAAkC,EAClC,UAAkB,EAClB,KAAa,EACb,IAAmB;IAEnB,IAAI,CAAC,MAAM,CAAC,MAAM;QAAE,OAAO,EAAE,CAAC;IAC9B,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,UAAU,CAAC,CAAC;IAC7C,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,EAAE;QAClC,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC;aAChC,MAAM,CACL,IAAI,CAAC,SAAS,CAAC;YACb,aAAa,CAAC,OAAO;YACrB,SAAS;YACT,KAAK;YACL,IAAI,CAAC,GAAG;YACR,IAAI,CAAC,GAAG;YACR,IAAI;YACJ,GAAG;SACJ,CAAC,CACH;aACA,MAAM,CAAC,KAAK,CAAC,CAAC;QACjB,OAAO;YACL,MAAM,EAAE,iBAAiB,IAAI,IAAI,MAAM,EAAE;YACzC,MAAM,EAAE,GAAG,aAAa,CAAC,IAAI,IAAI,IAAI,EAAE;SACxC,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { realpath } from \"node:fs/promises\";\nimport { posix } from \"node:path\";\nimport { invariant } from \"../domain/errors.ts\";\nimport { cacheDefaults } from \"./container-cache.constants.ts\";\nimport type {\n DependencyCache,\n ContainerCacheMount,\n} from \"./container-cache.types.ts\";\nimport type { ContainerOptions, ContainerUser } from \"./container.types.ts\";\n\nexport function validateCaches(config: ContainerOptions): void {\n const names = new Set<string>();\n for (const cache of config.caches ?? []) {\n invariant(\n typeof cache.name === \"string\" &&\n cacheDefaults.namePattern.test(cache.name),\n \"Cache names must start with a lowercase letter and contain at most 48 lowercase letters, digits or hyphens\",\n );\n invariant(!names.has(cache.name), `Duplicate cache name: ${cache.name}`);\n invariant(\n typeof cache.key === \"string\" &&\n cache.key.trim().length > 0 &&\n cache.key.length <= cacheDefaults.maximumKeyLength,\n \"Cache keys must be nonempty strings of at most 1024 characters\",\n );\n names.add(cache.name);\n }\n if (!names.size) return;\n for (const volume of config.volumes ?? []) {\n const target = posix.resolve(\n \"/workspace\",\n volume.target.replaceAll(\"\\\\\", \"/\"),\n );\n invariant(\n !(\n target === cacheDefaults.root ||\n target.startsWith(cacheDefaults.root + \"/\") ||\n cacheDefaults.root.startsWith(target.replace(/\\/$/, \"\") + \"/\")\n ),\n \"Explicit volumes must not overlap dependency caches\",\n );\n }\n}\n\nexport async function cacheMounts(\n caches: readonly DependencyCache[],\n repository: string,\n image: string,\n user: ContainerUser,\n): Promise<ContainerCacheMount[]> {\n if (!caches.length) return [];\n const canonical = await realpath(repository);\n return caches.map(({ name, key }) => {\n const digest = createHash(\"sha256\")\n .update(\n JSON.stringify([\n cacheDefaults.version,\n canonical,\n image,\n user.uid,\n user.gid,\n name,\n key,\n ]),\n )\n .digest(\"hex\");\n return {\n volume: `outpost-cache-${name}-${digest}`,\n target: `${cacheDefaults.root}/${name}`,\n };\n });\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"container-cache.types.js","sourceRoot":"","sources":["../../src/providers/container-cache.types.ts"],"names":[],"mappings":"","sourcesContent":["export interface DependencyCache {\n readonly name: string;\n readonly key: string;\n}\n\nexport interface ContainerCacheMount {\n readonly volume: string;\n readonly target: string;\n}\n"]}
|
|
@@ -21,7 +21,9 @@ export function containerPlan({ config, engine, user, root, name, image, volumes
|
|
|
21
21
|
root,
|
|
22
22
|
"--cap-drop",
|
|
23
23
|
"ALL",
|
|
24
|
-
...(fileParents.size
|
|
24
|
+
...(fileParents.size || config.caches?.length
|
|
25
|
+
? ["--cap-add", "CHOWN"]
|
|
26
|
+
: []),
|
|
25
27
|
"--security-opt",
|
|
26
28
|
"no-new-privileges",
|
|
27
29
|
"--tmpfs",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"container-plan.js","sourceRoot":"","sources":["../../src/providers/container-plan.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,aAAa,CAAC,EAC5B,MAAM,EACN,MAAM,EACN,IAAI,EACJ,IAAI,EACJ,IAAI,EACJ,KAAK,EACL,OAAO,EACP,WAAW,GACU;IACrB,MAAM,QAAQ,GACZ,OAAO,MAAM,CAAC,QAAQ,KAAK,QAAQ;QACjC,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC;QACnB,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;IAC9B,MAAM,IAAI,GAAG;QACX,QAAQ;QACR,QAAQ;QACR,IAAI;QACJ,QAAQ;QACR,QAAQ;QACR,GAAG,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE;QACzB,GAAG,CAAC,MAAM,KAAK,QAAQ;YACvB,MAAM,CAAC,MAAM,KAAK,KAAK;YACvB,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,CAAC;YACvD,CAAC,CAAC;gBACE,UAAU;gBACV,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,eAAe,IAAI,CAAC,GAAG,QAAQ,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,SAAS;aACpE;YACH,CAAC,CAAC,EAAE,CAAC;QACP,WAAW;QACX,IAAI;QACJ,YAAY;QACZ,KAAK;QACL,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"container-plan.js","sourceRoot":"","sources":["../../src/providers/container-plan.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,aAAa,CAAC,EAC5B,MAAM,EACN,MAAM,EACN,IAAI,EACJ,IAAI,EACJ,IAAI,EACJ,KAAK,EACL,OAAO,EACP,WAAW,GACU;IACrB,MAAM,QAAQ,GACZ,OAAO,MAAM,CAAC,QAAQ,KAAK,QAAQ;QACjC,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC;QACnB,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;IAC9B,MAAM,IAAI,GAAG;QACX,QAAQ;QACR,QAAQ;QACR,IAAI;QACJ,QAAQ;QACR,QAAQ;QACR,GAAG,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE;QACzB,GAAG,CAAC,MAAM,KAAK,QAAQ;YACvB,MAAM,CAAC,MAAM,KAAK,KAAK;YACvB,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,CAAC;YACvD,CAAC,CAAC;gBACE,UAAU;gBACV,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,eAAe,IAAI,CAAC,GAAG,QAAQ,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,SAAS;aACpE;YACH,CAAC,CAAC,EAAE,CAAC;QACP,WAAW;QACX,IAAI;QACJ,YAAY;QACZ,KAAK;QACL,GAAG,CAAC,WAAW,CAAC,IAAI,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM;YAC3C,CAAC,CAAC,CAAC,WAAW,EAAE,OAAO,CAAC;YACxB,CAAC,CAAC,EAAE,CAAC;QACP,gBAAgB;QAChB,mBAAmB;QACnB,SAAS;QACT,MAAM,KAAK,QAAQ;YACjB,CAAC,CAAC,0BAA0B;YAC5B,CAAC,CAAC,sBAAsB,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,QAAQ,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,YAAY;QAC5G,GAAG,OAAO;QACV,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QACxD,GAAG,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,aAAa,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAC3E,GAAG,CAAC,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QACnE,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACvD,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,GAAG,MAAM,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/D,cAAc;QACd,OAAO;QACP,KAAK;QACL,UAAU;KACX,CAAC;IAEF,OAAO,IAAI,CAAC;AACd,CAAC","sourcesContent":["import type { ContainerPlanOptions } from \"./container.types.ts\";\n\nexport function containerPlan({\n config,\n engine,\n user,\n root,\n name,\n image,\n volumes,\n fileParents,\n}: ContainerPlanOptions): string[] {\n const networks =\n typeof config.networks === \"string\"\n ? [config.networks]\n : (config.networks ?? []);\n const args = [\n \"create\",\n \"--name\",\n name,\n \"--init\",\n \"--user\",\n `${user.uid}:${user.gid}`,\n ...(engine === \"podman\" &&\n config.userns !== false &&\n (process.getuid?.() !== 0 || config.userns === \"keep-id\")\n ? [\n \"--userns\",\n config.user ? `keep-id:uid=${user.uid},gid=${user.gid}` : \"keep-id\",\n ]\n : []),\n \"--workdir\",\n root,\n \"--cap-drop\",\n \"ALL\",\n ...(fileParents.size || config.caches?.length\n ? [\"--cap-add\", \"CHOWN\"]\n : []),\n \"--security-opt\",\n \"no-new-privileges\",\n \"--tmpfs\",\n engine === \"podman\"\n ? \"/home/agent:rw,mode=1777\"\n : `/home/agent:rw,uid=${fileParents.size ? 0 : user.uid},gid=${fileParents.size ? 0 : user.gid},mode=0700`,\n ...volumes,\n ...networks.flatMap((network) => [\"--network\", network]),\n ...(config.groups ?? []).flatMap((group) => [\"--group-add\", String(group)]),\n ...(config.devices ?? []).flatMap((device) => [\"--device\", device]),\n ...(config.cpus ? [\"--cpus\", String(config.cpus)] : []),\n ...(config.memoryMb ? [\"--memory\", `${config.memoryMb}m`] : []),\n \"--entrypoint\",\n \"sleep\",\n image,\n \"infinity\",\n ];\n\n return args;\n}\n"]}
|
|
@@ -4,6 +4,8 @@ import { basename } from "node:path";
|
|
|
4
4
|
import { invariant } from "../domain/errors.js";
|
|
5
5
|
import { executeProcess, quote, requireSuccess, } from "../infrastructure/process.js";
|
|
6
6
|
import { registerCleanup } from "../infrastructure/shutdown.js";
|
|
7
|
+
import { cacheMounts, validateCaches } from "./container-cache.js";
|
|
8
|
+
import { cacheCreateOptions, cacheDefaults, } from "./container-cache.constants.js";
|
|
7
9
|
import { containerCommand } from "./container-command.js";
|
|
8
10
|
import { containerFiles } from "./container-files.js";
|
|
9
11
|
import { containerMounts } from "./container-mounts.js";
|
|
@@ -16,7 +18,11 @@ export function imageName(repository) {
|
|
|
16
18
|
.replace(/[^a-z0-9_.-]/g, "-") || "workspace"}`;
|
|
17
19
|
}
|
|
18
20
|
export function containerProvider(engine, options = {}, executor = executeProcess, platform = process.platform) {
|
|
19
|
-
const config = {
|
|
21
|
+
const config = {
|
|
22
|
+
...options,
|
|
23
|
+
caches: (options.caches ?? []).map((cache) => ({ ...cache })),
|
|
24
|
+
};
|
|
25
|
+
validateCaches(config);
|
|
20
26
|
if (config.cpus !== undefined)
|
|
21
27
|
invariant(Number.isFinite(config.cpus) && config.cpus > 0, "cpus must be positive");
|
|
22
28
|
if (config.memoryMb !== undefined)
|
|
@@ -47,6 +53,9 @@ export function containerProvider(engine, options = {}, executor = executeProces
|
|
|
47
53
|
await containerPreflight(engine, platform, call, config, image, user);
|
|
48
54
|
const root = containerDefaults.root, home = containerDefaults.home;
|
|
49
55
|
const { env, volumes, fileParents } = await containerMounts(context, config, platform, root, home);
|
|
56
|
+
const caches = await cacheMounts(config.caches ?? [], context.repository, image, user);
|
|
57
|
+
for (const cache of caches)
|
|
58
|
+
volumes.push("--volume", `${cache.volume}:${cache.target}:nocopy`);
|
|
50
59
|
const args = containerPlan({
|
|
51
60
|
config,
|
|
52
61
|
engine,
|
|
@@ -72,10 +81,31 @@ export function containerProvider(engine, options = {}, executor = executeProces
|
|
|
72
81
|
return releasing;
|
|
73
82
|
};
|
|
74
83
|
try {
|
|
84
|
+
for (const cache of caches)
|
|
85
|
+
await call([
|
|
86
|
+
"volume",
|
|
87
|
+
"create",
|
|
88
|
+
...cacheCreateOptions[engine],
|
|
89
|
+
"--label",
|
|
90
|
+
`${cacheDefaults.label}=true`,
|
|
91
|
+
cache.volume,
|
|
92
|
+
], context.signal ? { signal: context.signal } : {});
|
|
75
93
|
await call(args, {
|
|
76
94
|
...(context.signal ? { signal: context.signal } : {}),
|
|
77
95
|
});
|
|
78
96
|
await call(["start", name], context.signal ? { signal: context.signal } : {});
|
|
97
|
+
for (const cache of caches) {
|
|
98
|
+
await call([
|
|
99
|
+
"exec",
|
|
100
|
+
"--user",
|
|
101
|
+
"0:0",
|
|
102
|
+
name,
|
|
103
|
+
"chown",
|
|
104
|
+
`${user.uid}:${user.gid}`,
|
|
105
|
+
cache.target,
|
|
106
|
+
], context.signal ? { signal: context.signal } : {});
|
|
107
|
+
await call(["exec", name, "chmod", "700", cache.target], context.signal ? { signal: context.signal } : {});
|
|
108
|
+
}
|
|
79
109
|
for (const parent of fileParents)
|
|
80
110
|
await call([
|
|
81
111
|
"exec",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"container.js","sourceRoot":"","sources":["../../src/providers/container.ts"],"names":[],"mappings":"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","sourcesContent":["import { execFileSync } from \"node:child_process\";\nimport { randomUUID } from \"node:crypto\";\nimport { basename } from \"node:path\";\nimport type { Command } from \"../domain/command.types.ts\";\nimport { invariant } from \"../domain/errors.ts\";\nimport type { SandboxProvider } from \"../domain/sandbox.types.ts\";\nimport {\n executeProcess,\n quote,\n requireSuccess,\n} from \"../infrastructure/process.ts\";\nimport type { Executor } from \"../infrastructure/process.types.ts\";\nimport { registerCleanup } from \"../infrastructure/shutdown.ts\";\nimport { containerCommand } from \"./container-command.ts\";\nimport { containerFiles } from \"./container-files.ts\";\nimport { containerMounts } from \"./container-mounts.ts\";\nimport { containerPlan } from \"./container-plan.ts\";\nimport { containerPreflight } from \"./container-preflight.ts\";\nimport { containerDefaults } from \"./container.constants.ts\";\nimport type { ContainerEngine, ContainerOptions } from \"./container.types.ts\";\n\nexport type { ContainerOptions } from \"./container.types.ts\";\n\nexport function imageName(repository: string): string {\n return `outpost:${\n basename(repository)\n .toLowerCase()\n .replace(/[^a-z0-9_.-]/g, \"-\") || \"workspace\"\n }`;\n}\n\nexport function containerProvider(\n engine: ContainerEngine,\n options: ContainerOptions = {},\n executor: Executor = executeProcess,\n platform: NodeJS.Platform = process.platform,\n): SandboxProvider {\n const config = { ...options };\n if (config.cpus !== undefined)\n invariant(\n Number.isFinite(config.cpus) && config.cpus > 0,\n \"cpus must be positive\",\n );\n if (config.memoryMb !== undefined)\n invariant(\n Number.isSafeInteger(config.memoryMb) &&\n config.memoryMb >= containerDefaults.minimumMemoryMb,\n \"memoryMb must be at least 64\",\n );\n return {\n name: engine,\n placement: \"mounted\",\n variables: { ...config.variables },\n async acquire(context) {\n context.signal?.throwIfAborted();\n const name = `outpost-${randomUUID()}`;\n const image = config.image ?? imageName(context.repository);\n const user = config.user ?? {\n uid: process.getuid?.() ?? containerDefaults.uid,\n gid: process.getgid?.() ?? containerDefaults.gid,\n };\n invariant(\n Number.isInteger(user.uid) &&\n user.uid >= 0 &&\n Number.isInteger(user.gid) &&\n user.gid >= 0,\n \"Invalid container user\",\n );\n const call = (args: readonly string[], extra: Partial<Command> = {}) =>\n requireSuccess(\n {\n executable: engine,\n arguments: args,\n deadlineMs: containerDefaults.deadlineMs,\n ...extra,\n },\n executor,\n );\n await containerPreflight(engine, platform, call, config, image, user);\n const root = containerDefaults.root,\n home = containerDefaults.home;\n const { env, volumes, fileParents } = await containerMounts(\n context,\n config,\n platform,\n root,\n home,\n );\n const args = containerPlan({\n config,\n engine,\n user,\n root,\n name,\n image,\n volumes,\n fileParents,\n });\n let closed = false,\n releasing: Promise<void> | undefined;\n let unregister = () => {};\n const release = (): Promise<void> => {\n closed = true;\n releasing ??= call([\"rm\", \"--force\", name])\n .then(() => {\n unregister();\n })\n .catch((error) => {\n releasing = undefined;\n throw error;\n });\n return releasing;\n };\n try {\n await call(args, {\n ...(context.signal ? { signal: context.signal } : {}),\n });\n await call(\n [\"start\", name],\n context.signal ? { signal: context.signal } : {},\n );\n for (const parent of fileParents)\n await call([\n \"exec\",\n \"--user\",\n \"0:0\",\n name,\n \"sh\",\n \"-c\",\n `mkdir -p ${quote(parent)} && chown ${user.uid}:${user.gid} ${quote(parent)}`,\n ]);\n if (fileParents.size)\n await call([\n \"exec\",\n \"--user\",\n \"0:0\",\n name,\n \"chown\",\n `${user.uid}:${user.gid}`,\n home,\n ]);\n await call([\n \"exec\",\n name,\n \"sh\",\n \"-c\",\n \"command -v setsid >/dev/null && command -v kill >/dev/null && command -v tar >/dev/null && command -v cp >/dev/null\",\n ]);\n } catch (cause) {\n try {\n await release();\n } catch (cleanup) {\n throw new AggregateError(\n [cause, cleanup],\n \"Sandbox provisioning and cleanup failed\",\n );\n }\n throw cause;\n }\n unregister = registerCleanup(release, () => {\n if (!closed)\n execFileSync(engine, [\"rm\", \"--force\", name], {\n timeout: containerDefaults.cleanupMs,\n stdio: \"ignore\",\n windowsHide: true,\n });\n });\n return {\n root,\n home,\n invoke: containerCommand({\n engine,\n config,\n executor,\n root,\n name,\n env,\n call,\n isClosed: () => closed,\n }),\n ...containerFiles({\n engine,\n config,\n executor,\n root,\n name,\n env,\n call,\n isClosed: () => closed,\n }),\n release,\n };\n },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"container.js","sourceRoot":"","sources":["../../src/providers/container.ts"],"names":[],"mappings":"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","sourcesContent":["import { execFileSync } from \"node:child_process\";\nimport { randomUUID } from \"node:crypto\";\nimport { basename } from \"node:path\";\nimport type { Command } from \"../domain/command.types.ts\";\nimport { invariant } from \"../domain/errors.ts\";\nimport type { SandboxProvider } from \"../domain/sandbox.types.ts\";\nimport {\n executeProcess,\n quote,\n requireSuccess,\n} from \"../infrastructure/process.ts\";\nimport type { Executor } from \"../infrastructure/process.types.ts\";\nimport { registerCleanup } from \"../infrastructure/shutdown.ts\";\nimport { cacheMounts, validateCaches } from \"./container-cache.ts\";\nimport {\n cacheCreateOptions,\n cacheDefaults,\n} from \"./container-cache.constants.ts\";\nimport { containerCommand } from \"./container-command.ts\";\nimport { containerFiles } from \"./container-files.ts\";\nimport { containerMounts } from \"./container-mounts.ts\";\nimport { containerPlan } from \"./container-plan.ts\";\nimport { containerPreflight } from \"./container-preflight.ts\";\nimport { containerDefaults } from \"./container.constants.ts\";\nimport type { ContainerEngine, ContainerOptions } from \"./container.types.ts\";\n\nexport type { ContainerOptions } from \"./container.types.ts\";\n\nexport function imageName(repository: string): string {\n return `outpost:${\n basename(repository)\n .toLowerCase()\n .replace(/[^a-z0-9_.-]/g, \"-\") || \"workspace\"\n }`;\n}\n\nexport function containerProvider(\n engine: ContainerEngine,\n options: ContainerOptions = {},\n executor: Executor = executeProcess,\n platform: NodeJS.Platform = process.platform,\n): SandboxProvider {\n const config = {\n ...options,\n caches: (options.caches ?? []).map((cache) => ({ ...cache })),\n };\n validateCaches(config);\n if (config.cpus !== undefined)\n invariant(\n Number.isFinite(config.cpus) && config.cpus > 0,\n \"cpus must be positive\",\n );\n if (config.memoryMb !== undefined)\n invariant(\n Number.isSafeInteger(config.memoryMb) &&\n config.memoryMb >= containerDefaults.minimumMemoryMb,\n \"memoryMb must be at least 64\",\n );\n return {\n name: engine,\n placement: \"mounted\",\n variables: { ...config.variables },\n async acquire(context) {\n context.signal?.throwIfAborted();\n const name = `outpost-${randomUUID()}`;\n const image = config.image ?? imageName(context.repository);\n const user = config.user ?? {\n uid: process.getuid?.() ?? containerDefaults.uid,\n gid: process.getgid?.() ?? containerDefaults.gid,\n };\n invariant(\n Number.isInteger(user.uid) &&\n user.uid >= 0 &&\n Number.isInteger(user.gid) &&\n user.gid >= 0,\n \"Invalid container user\",\n );\n const call = (args: readonly string[], extra: Partial<Command> = {}) =>\n requireSuccess(\n {\n executable: engine,\n arguments: args,\n deadlineMs: containerDefaults.deadlineMs,\n ...extra,\n },\n executor,\n );\n await containerPreflight(engine, platform, call, config, image, user);\n const root = containerDefaults.root,\n home = containerDefaults.home;\n const { env, volumes, fileParents } = await containerMounts(\n context,\n config,\n platform,\n root,\n home,\n );\n const caches = await cacheMounts(\n config.caches ?? [],\n context.repository,\n image,\n user,\n );\n for (const cache of caches)\n volumes.push(\"--volume\", `${cache.volume}:${cache.target}:nocopy`);\n const args = containerPlan({\n config,\n engine,\n user,\n root,\n name,\n image,\n volumes,\n fileParents,\n });\n let closed = false,\n releasing: Promise<void> | undefined;\n let unregister = () => {};\n const release = (): Promise<void> => {\n closed = true;\n releasing ??= call([\"rm\", \"--force\", name])\n .then(() => {\n unregister();\n })\n .catch((error) => {\n releasing = undefined;\n throw error;\n });\n return releasing;\n };\n try {\n for (const cache of caches)\n await call(\n [\n \"volume\",\n \"create\",\n ...cacheCreateOptions[engine],\n \"--label\",\n `${cacheDefaults.label}=true`,\n cache.volume,\n ],\n context.signal ? { signal: context.signal } : {},\n );\n await call(args, {\n ...(context.signal ? { signal: context.signal } : {}),\n });\n await call(\n [\"start\", name],\n context.signal ? { signal: context.signal } : {},\n );\n for (const cache of caches) {\n await call(\n [\n \"exec\",\n \"--user\",\n \"0:0\",\n name,\n \"chown\",\n `${user.uid}:${user.gid}`,\n cache.target,\n ],\n context.signal ? { signal: context.signal } : {},\n );\n await call(\n [\"exec\", name, \"chmod\", \"700\", cache.target],\n context.signal ? { signal: context.signal } : {},\n );\n }\n for (const parent of fileParents)\n await call([\n \"exec\",\n \"--user\",\n \"0:0\",\n name,\n \"sh\",\n \"-c\",\n `mkdir -p ${quote(parent)} && chown ${user.uid}:${user.gid} ${quote(parent)}`,\n ]);\n if (fileParents.size)\n await call([\n \"exec\",\n \"--user\",\n \"0:0\",\n name,\n \"chown\",\n `${user.uid}:${user.gid}`,\n home,\n ]);\n await call([\n \"exec\",\n name,\n \"sh\",\n \"-c\",\n \"command -v setsid >/dev/null && command -v kill >/dev/null && command -v tar >/dev/null && command -v cp >/dev/null\",\n ]);\n } catch (cause) {\n try {\n await release();\n } catch (cleanup) {\n throw new AggregateError(\n [cause, cleanup],\n \"Sandbox provisioning and cleanup failed\",\n );\n }\n throw cause;\n }\n unregister = registerCleanup(release, () => {\n if (!closed)\n execFileSync(engine, [\"rm\", \"--force\", name], {\n timeout: containerDefaults.cleanupMs,\n stdio: \"ignore\",\n windowsHide: true,\n });\n });\n return {\n root,\n home,\n invoke: containerCommand({\n engine,\n config,\n executor,\n root,\n name,\n env,\n call,\n isClosed: () => closed,\n }),\n ...containerFiles({\n engine,\n config,\n executor,\n root,\n name,\n env,\n call,\n isClosed: () => closed,\n }),\n release,\n };\n },\n };\n}\n"]}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { Command, CommandResult, Variables } from "../domain/command.types.ts";
|
|
2
2
|
import type { Volume } from "../domain/sandbox.types.ts";
|
|
3
3
|
import type { Executor } from "../infrastructure/process.types.ts";
|
|
4
|
+
import type { DependencyCache } from "./container-cache.types.ts";
|
|
4
5
|
export interface ContainerOptions {
|
|
6
|
+
readonly caches?: readonly DependencyCache[];
|
|
5
7
|
readonly image?: string;
|
|
6
8
|
readonly user?: {
|
|
7
9
|
readonly uid: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"container.types.js","sourceRoot":"","sources":["../../src/providers/container.types.ts"],"names":[],"mappings":"","sourcesContent":["import type {\n Command,\n CommandResult,\n Variables,\n} from \"../domain/command.types.ts\";\nimport type { Volume } from \"../domain/sandbox.types.ts\";\nimport type { Executor } from \"../infrastructure/process.types.ts\";\n\nexport interface ContainerOptions {\n readonly image?: string;\n readonly user?: { readonly uid: number; readonly gid: number };\n readonly volumes?: readonly Volume[];\n readonly variables?: Variables;\n readonly networks?: string | readonly string[];\n readonly groups?: readonly (string | number)[];\n readonly devices?: readonly string[];\n readonly cpus?: number;\n readonly memoryMb?: number;\n readonly label?: \"z\" | \"Z\" | false;\n readonly retain?: number;\n readonly userns?: \"keep-id\" | false;\n}\n\nexport type ContainerEngine = \"docker\" | \"podman\";\nexport type ContainerCall = (\n args: readonly string[],\n extra?: Partial<Command>,\n) => Promise<CommandResult>;\nexport interface ContainerRuntime {\n readonly engine: ContainerEngine;\n readonly config: ContainerOptions;\n readonly executor: Executor;\n readonly root: string;\n readonly name: string;\n readonly env: Record<string, string>;\n readonly call: ContainerCall;\n readonly isClosed: () => boolean;\n}\nexport interface ContainerMounts {\n readonly env: Record<string, string>;\n readonly volumes: string[];\n readonly fileParents: Set<string>;\n}\n\nexport interface ContainerUser {\n readonly uid: number;\n readonly gid: number;\n}\nexport interface ContainerPlanOptions {\n readonly config: ContainerOptions;\n readonly engine: ContainerEngine;\n readonly user: ContainerUser;\n readonly root: string;\n readonly name: string;\n readonly image: string;\n readonly volumes: readonly string[];\n readonly fileParents: ReadonlySet<string>;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"container.types.js","sourceRoot":"","sources":["../../src/providers/container.types.ts"],"names":[],"mappings":"","sourcesContent":["import type {\n Command,\n CommandResult,\n Variables,\n} from \"../domain/command.types.ts\";\nimport type { Volume } from \"../domain/sandbox.types.ts\";\nimport type { Executor } from \"../infrastructure/process.types.ts\";\nimport type { DependencyCache } from \"./container-cache.types.ts\";\n\nexport interface ContainerOptions {\n readonly caches?: readonly DependencyCache[];\n readonly image?: string;\n readonly user?: { readonly uid: number; readonly gid: number };\n readonly volumes?: readonly Volume[];\n readonly variables?: Variables;\n readonly networks?: string | readonly string[];\n readonly groups?: readonly (string | number)[];\n readonly devices?: readonly string[];\n readonly cpus?: number;\n readonly memoryMb?: number;\n readonly label?: \"z\" | \"Z\" | false;\n readonly retain?: number;\n readonly userns?: \"keep-id\" | false;\n}\n\nexport type ContainerEngine = \"docker\" | \"podman\";\nexport type ContainerCall = (\n args: readonly string[],\n extra?: Partial<Command>,\n) => Promise<CommandResult>;\nexport interface ContainerRuntime {\n readonly engine: ContainerEngine;\n readonly config: ContainerOptions;\n readonly executor: Executor;\n readonly root: string;\n readonly name: string;\n readonly env: Record<string, string>;\n readonly call: ContainerCall;\n readonly isClosed: () => boolean;\n}\nexport interface ContainerMounts {\n readonly env: Record<string, string>;\n readonly volumes: string[];\n readonly fileParents: Set<string>;\n}\n\nexport interface ContainerUser {\n readonly uid: number;\n readonly gid: number;\n}\nexport interface ContainerPlanOptions {\n readonly config: ContainerOptions;\n readonly engine: ContainerEngine;\n readonly user: ContainerUser;\n readonly root: string;\n readonly name: string;\n readonly image: string;\n readonly volumes: readonly string[];\n readonly fileParents: ReadonlySet<string>;\n}\n"]}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { setTimeout } from "node:timers/promises";
|
|
1
2
|
import { randomUUID } from "node:crypto";
|
|
2
3
|
import { OutpostError } from "../domain/errors.js";
|
|
3
4
|
import { interruptible } from "../infrastructure/abort.js";
|
|
@@ -59,10 +60,12 @@ export function daytonaCommand(runtime) {
|
|
|
59
60
|
if (cancellation)
|
|
60
61
|
await cancellation;
|
|
61
62
|
signal.throwIfAborted();
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
63
|
+
while (true) {
|
|
64
|
+
const result = await interruptible(sandbox.process.getSessionCommand(id, response.cmdId), signal);
|
|
65
|
+
if (result.exitCode !== undefined)
|
|
66
|
+
return { status: result.exitCode, ...output };
|
|
67
|
+
await setTimeout(cloudDefaults.pollMs, undefined, { signal });
|
|
68
|
+
}
|
|
66
69
|
}
|
|
67
70
|
catch (cause) {
|
|
68
71
|
cancel();
|