warpmetal 0.8.6 → 0.8.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -0
- package/package.json +1 -1
- package/skills/warpmetal/SKILL.md +10 -0
- package/skills/warpmetal/references/cli-reference.md +12 -1
- package/skills/warpmetal/references/runtime.md +34 -0
- package/src/cli.js +21 -1
- package/src/installer.js +137 -20
package/README.md
CHANGED
|
@@ -349,6 +349,36 @@ warpmetal sandbox access keygen \
|
|
|
349
349
|
--json
|
|
350
350
|
```
|
|
351
351
|
|
|
352
|
+
WarpMetal CLI v0.8.7 with Agent Runtime v0.1.25 or newer can enable the narrowly
|
|
353
|
+
scoped AppArmor exception required by a verified workload that creates an inner
|
|
354
|
+
Bubblewrap PID namespace and private `/proc`:
|
|
355
|
+
|
|
356
|
+
```sh
|
|
357
|
+
warpmetal runtime install \
|
|
358
|
+
--server <serverId> \
|
|
359
|
+
--ssh-user root \
|
|
360
|
+
--confirm INSTALL \
|
|
361
|
+
--nested-private-procfs enable \
|
|
362
|
+
--wait \
|
|
363
|
+
--json
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
This is an explicit host-scoped opt-in for nested-Bubblewrap hosts, not a
|
|
367
|
+
requirement for ordinary VPS or Runtime workloads that use only the outer
|
|
368
|
+
sandbox. The default `preserve` action leaves the current policy state
|
|
369
|
+
unchanged. Use `disable` during an approved maintenance window to unload
|
|
370
|
+
WarpMetal's policy and restore the pre-install file and loaded-policy state.
|
|
371
|
+
Because Runtime sandboxes share one Unix owner, treat an enabled policy as
|
|
372
|
+
available to every sandbox on that Runtime host whose process matches the
|
|
373
|
+
signed, root-owned bwrap path; it is not a per-sandbox permission.
|
|
374
|
+
|
|
375
|
+
Common inner-boundary designs are planning with an exact read-only checkout,
|
|
376
|
+
coding with only one approved checkout and output directory writable, and QA
|
|
377
|
+
with an exact candidate plus isolated test processes and scratch space. The
|
|
378
|
+
boundary protects a persistent trusted runner from repository-controlled
|
|
379
|
+
commands and sibling attempts. GitHub access, installing Codex or another AI
|
|
380
|
+
CLI, and delegating to subagents do not by themselves require this capability.
|
|
381
|
+
|
|
352
382
|
Installation gives pre-existing Docker containers exact liveness checks and
|
|
353
383
|
tracks common container-runtime processes without collecting application
|
|
354
384
|
configuration. The signed installer uses `crun` for its private rootless Podman
|
package/package.json
CHANGED
|
@@ -283,6 +283,16 @@ sizes. Use `--runtime-file` to include sandbox intent in an unpaid order, or
|
|
|
283
283
|
`warpmetal runtime enable` after the VPS is ready. Supervisor installation is
|
|
284
284
|
separate and requires approval plus `--confirm INSTALL`.
|
|
285
285
|
|
|
286
|
+
For any verified workload that creates an inner Bubblewrap PID namespace and
|
|
287
|
+
private `/proc`, CLI 0.8.7 with Runtime 0.1.25 or newer may add
|
|
288
|
+
`--nested-private-procfs enable` to the approved Runtime install. Planning with
|
|
289
|
+
a read-only checkout, coding in one writable checkout, and independent QA are
|
|
290
|
+
common uses. GitHub access, an AI CLI, or subagent delegation alone does not
|
|
291
|
+
require it. Omission means `preserve`, which leaves policy state unchanged;
|
|
292
|
+
`disable` is an explicit maintenance action. The exception is host-scoped
|
|
293
|
+
rather than sandbox-scoped, so separate workloads onto different VPS hosts when
|
|
294
|
+
they must not share it.
|
|
295
|
+
|
|
286
296
|
Omitted lifetime means persistent. A temporary sandbox requires
|
|
287
297
|
`--confirm TEMPORARY`, expires 15 minutes to 24 hours after first reaching
|
|
288
298
|
running, and permanently deletes its workspace at expiry. Never describe a
|
|
@@ -212,7 +212,9 @@ warpmetal runtime enable --server <serverId> [--idempotency-key <key>] --json
|
|
|
212
212
|
warpmetal runtime get --server <serverId> [--wait] [--timeout-seconds <n>] --json
|
|
213
213
|
warpmetal runtime install \
|
|
214
214
|
--server <serverId> [--identity <owner-key>] --ssh-user root \
|
|
215
|
-
--confirm INSTALL
|
|
215
|
+
--confirm INSTALL \
|
|
216
|
+
[--nested-private-procfs <preserve|enable|disable>] \
|
|
217
|
+
[--wait] [--timeout-seconds <n>] --json
|
|
216
218
|
|
|
217
219
|
warpmetal sandbox create \
|
|
218
220
|
--server <serverId> --name <name> --size <small|medium|large|xlarge> \
|
|
@@ -230,6 +232,15 @@ warpmetal sandbox delete \
|
|
|
230
232
|
--server <serverId> --sandbox <sandboxId> --confirm DELETE [--wait] --json
|
|
231
233
|
```
|
|
232
234
|
|
|
235
|
+
The nested-private-procfs action requires CLI 0.8.7 and Runtime 0.1.25 or
|
|
236
|
+
newer. It defaults to `preserve`. `enable` is a host-level opt-in for any
|
|
237
|
+
verified workload that creates an inner Bubblewrap PID namespace and private
|
|
238
|
+
`/proc`; read-only planning, single-workspace coding, and independent QA are
|
|
239
|
+
common examples. GitHub use, an AI CLI, or subagent delegation alone does not
|
|
240
|
+
require it. `disable` unloads WarpMetal's policy and restores the recorded
|
|
241
|
+
pre-enable state. It is not a per-sandbox capability because Runtime sandboxes
|
|
242
|
+
share one Unix owner.
|
|
243
|
+
|
|
233
244
|
See [runtime.md](runtime.md) for capacity, lifetime, cleanup, polling, and
|
|
234
245
|
installation safety. Exit 8 means accepted or pending, never applied.
|
|
235
246
|
|
|
@@ -58,6 +58,7 @@ warpmetal runtime install \
|
|
|
58
58
|
--identity <owner-private-key-path> \
|
|
59
59
|
--ssh-user root \
|
|
60
60
|
--confirm INSTALL \
|
|
61
|
+
[--nested-private-procfs <preserve|enable|disable>] \
|
|
61
62
|
--wait \
|
|
62
63
|
--json
|
|
63
64
|
warpmetal runtime get --server <serverId> --wait --json
|
|
@@ -68,6 +69,29 @@ The CLI holds the one-time bootstrap only in memory, verifies the signed
|
|
|
68
69
|
artifact, uploads it through OpenSSH without a shell-enabled local spawn, and
|
|
69
70
|
does not print or store the bootstrap.
|
|
70
71
|
|
|
72
|
+
`--nested-private-procfs` is supported by `warpmetal` CLI 0.8.7 with Agent
|
|
73
|
+
Runtime 0.1.25 or newer. Its default is `preserve`, which makes no AppArmor
|
|
74
|
+
policy change. Select `enable` only when this VPS is intentionally dedicated to
|
|
75
|
+
a verified workload that creates an inner Bubblewrap PID namespace and private
|
|
76
|
+
procfs. Ordinary VPS users and Runtime workloads that rely only on the outer
|
|
77
|
+
sandbox do not need it. Select `disable` only during an approved maintenance
|
|
78
|
+
action to unload WarpMetal's policy and restore the exact file and loaded-policy
|
|
79
|
+
state that existed before enablement.
|
|
80
|
+
|
|
81
|
+
Examples include a planner with an exact read-only checkout, a coder with only
|
|
82
|
+
one approved checkout and output directory writable, and QA with an exact
|
|
83
|
+
candidate plus isolated test processes and scratch space. This protects a
|
|
84
|
+
persistent trusted runner from repository-controlled commands and sibling
|
|
85
|
+
attempts. GitHub access, installing an AI CLI, and subagent delegation alone do
|
|
86
|
+
not require nested private procfs.
|
|
87
|
+
|
|
88
|
+
This setting is host-scoped, not sandbox-scoped. Runtime sandboxes share one
|
|
89
|
+
Unix owner, so every sandbox on the host can use the exception only through the
|
|
90
|
+
signed, root-owned, fixed bwrap path matched by the policy. Enabling it does not
|
|
91
|
+
authorize arbitrary bwrap binaries or change the trust boundary for the
|
|
92
|
+
Runtime image selected by WarpMetal's authenticated backend. Isolate workloads
|
|
93
|
+
on separate VPS hosts if they must not share this host capability.
|
|
94
|
+
|
|
71
95
|
The signed installer is designed to preserve container workloads already
|
|
72
96
|
running on a supported host. It selects `crun` for WarpMetal's private rootless
|
|
73
97
|
Podman service, refuses APT removals and DNF erasures, protects installed
|
|
@@ -92,6 +116,16 @@ host automatically:
|
|
|
92
116
|
unexpectedly; stop and review the host package logs;
|
|
93
117
|
- `runtime_legacy_migration_required`: preview Podman state needs a separate,
|
|
94
118
|
explicitly reviewed migration and was not reset.
|
|
119
|
+
- `runtime_nested_private_procfs_architecture_unsupported`: the requested
|
|
120
|
+
coding-host policy is unsupported by this CPU architecture;
|
|
121
|
+
- `runtime_apparmor_state_unverifiable`: the host's current AppArmor state
|
|
122
|
+
cannot be established safely;
|
|
123
|
+
- `runtime_apparmor_policy_conflict`: an existing file or loaded-policy state
|
|
124
|
+
conflicts with WarpMetal's recorded transaction;
|
|
125
|
+
- `runtime_apparmor_policy_rollback_failed`: the installer could not restore
|
|
126
|
+
the exact prior AppArmor state; stop and perform operator recovery.
|
|
127
|
+
- `runtime_apparmor_policy_recovery_failed`: an interrupted prior policy
|
|
128
|
+
transaction could not be recovered; stop and perform operator recovery.
|
|
95
129
|
|
|
96
130
|
There is no force bypass. If `runtime_reboot_required` is returned, schedule
|
|
97
131
|
the reboot as a separate maintenance action and retry only after the host and
|
package/src/cli.js
CHANGED
|
@@ -110,7 +110,7 @@ Usage:
|
|
|
110
110
|
warpmetal operation get --operation <operationId> [--server <serverId>] [--wait]
|
|
111
111
|
warpmetal runtime enable|get --server <serverId> [--wait]
|
|
112
112
|
warpmetal runtime install --server <serverId> [--identity <owner-key>] --ssh-user <user>
|
|
113
|
-
--confirm INSTALL [--wait]
|
|
113
|
+
--confirm INSTALL [--nested-private-procfs <preserve|enable|disable>] [--wait]
|
|
114
114
|
warpmetal sandbox create --server <serverId> --name <name> --size <size>
|
|
115
115
|
[--lifetime temporary] [--expires-in-seconds <n>] [--confirm TEMPORARY] [--wait]
|
|
116
116
|
warpmetal sandbox create --server <serverId> --file <batch.json> [--confirm TEMPORARY]
|
|
@@ -132,6 +132,16 @@ Global options:
|
|
|
132
132
|
--help Show help
|
|
133
133
|
--version Show the CLI version
|
|
134
134
|
|
|
135
|
+
Nested private procfs (CLI 0.8.7+, Runtime 0.1.25+):
|
|
136
|
+
preserve Default; do not inspect or change AppArmor policy state
|
|
137
|
+
enable Enable the exact-path Bubblewrap policy on an amd64 host
|
|
138
|
+
disable Remove it and restore the recorded pre-enable policy state
|
|
139
|
+
|
|
140
|
+
Use enable once per dedicated Runtime host when a verified workload creates an
|
|
141
|
+
inner Bubblewrap PID namespace and private /proc. Planning, coding, and QA are
|
|
142
|
+
common examples. GitHub access, an AI CLI, and subagent delegation alone do not
|
|
143
|
+
require it. The capability is host-scoped, not per-sandbox.
|
|
144
|
+
|
|
135
145
|
Credential environment variables:
|
|
136
146
|
WARPMETAL_OWNER_TOKEN Recovery/bootstrap credential for one explicit command
|
|
137
147
|
WARPMETAL_ACCESS_TOKEN Short-lived SSH-derived credential for one explicit command
|
|
@@ -2140,6 +2150,14 @@ async function handleRuntimeInstall(client, store, options, context) {
|
|
|
2140
2150
|
stringOption(options, "identity"),
|
|
2141
2151
|
);
|
|
2142
2152
|
const sshUser = stringOption(options, "ssh-user", { required: true });
|
|
2153
|
+
const nestedPrivateProcfs =
|
|
2154
|
+
stringOption(options, "nested-private-procfs") || "preserve";
|
|
2155
|
+
if (!["preserve", "enable", "disable"].includes(nestedPrivateProcfs)) {
|
|
2156
|
+
throw new CliError(
|
|
2157
|
+
"--nested-private-procfs must be preserve, enable, or disable.",
|
|
2158
|
+
{ exitCode: 2 },
|
|
2159
|
+
);
|
|
2160
|
+
}
|
|
2143
2161
|
if (stringOption(options, "confirm", { required: true }) !== "INSTALL") {
|
|
2144
2162
|
throw new CliError(
|
|
2145
2163
|
"Confirm supervisor installation with --confirm INSTALL.",
|
|
@@ -2167,6 +2185,7 @@ async function handleRuntimeInstall(client, store, options, context) {
|
|
|
2167
2185
|
identity,
|
|
2168
2186
|
sshUser,
|
|
2169
2187
|
bootstrap: bootstrap.data,
|
|
2188
|
+
nestedPrivateProcfs,
|
|
2170
2189
|
fetchImpl: context.fetchImpl,
|
|
2171
2190
|
spawnImpl: context.spawnImpl,
|
|
2172
2191
|
});
|
|
@@ -2975,6 +2994,7 @@ async function dispatch(positionals, options, passthrough, context) {
|
|
|
2975
2994
|
"identity",
|
|
2976
2995
|
"ssh-user",
|
|
2977
2996
|
"confirm",
|
|
2997
|
+
"nested-private-procfs",
|
|
2978
2998
|
"idempotency-key",
|
|
2979
2999
|
"wait",
|
|
2980
3000
|
"timeout-seconds",
|
package/src/installer.js
CHANGED
|
@@ -5,14 +5,14 @@ import {
|
|
|
5
5
|
verify as verifySignature,
|
|
6
6
|
} from "node:crypto";
|
|
7
7
|
import { spawn as nodeSpawn } from "node:child_process";
|
|
8
|
-
import {
|
|
8
|
+
import { lstat, mkdtemp, readdir, rm, writeFile } from "node:fs/promises";
|
|
9
9
|
import { tmpdir } from "node:os";
|
|
10
10
|
import { join, resolve } from "node:path";
|
|
11
11
|
|
|
12
12
|
import { CliError } from "./errors.js";
|
|
13
13
|
|
|
14
14
|
const MAX_ARTIFACT_BYTES = 256 * 1024 * 1024;
|
|
15
|
-
const
|
|
15
|
+
const BASE_REQUIRED_FILES = [
|
|
16
16
|
"install.sh",
|
|
17
17
|
"warpmetal-agentctl",
|
|
18
18
|
"warpmetal-sandbox-gateway",
|
|
@@ -24,6 +24,26 @@ const REQUIRED_FILES = [
|
|
|
24
24
|
"warpmetal-sandbox.conf",
|
|
25
25
|
];
|
|
26
26
|
|
|
27
|
+
const NESTED_PRIVATE_PROCFS_FILES = [
|
|
28
|
+
"nested-private-procfs-oracle.sh",
|
|
29
|
+
"warpmetal-agent-runtime-bwrap",
|
|
30
|
+
"warpmetal-apparmor-policy.sh",
|
|
31
|
+
"warpmetal-policy-metadata",
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
function supportsNestedPrivateProcfs(version) {
|
|
35
|
+
const match = /^(\d+)\.(\d+)\.(\d+)/.exec(version);
|
|
36
|
+
if (!match) return false;
|
|
37
|
+
const [, major, minor, patch] = match.map(Number);
|
|
38
|
+
return major > 0 || minor > 1 || (minor === 1 && patch >= 25);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function requiredFiles(version) {
|
|
42
|
+
return supportsNestedPrivateProcfs(version)
|
|
43
|
+
? [...BASE_REQUIRED_FILES, ...NESTED_PRIVATE_PROCFS_FILES]
|
|
44
|
+
: BASE_REQUIRED_FILES;
|
|
45
|
+
}
|
|
46
|
+
|
|
27
47
|
const INSTALLER_ERROR_MESSAGES = new Map([
|
|
28
48
|
[
|
|
29
49
|
"runtime_install_lock_unavailable",
|
|
@@ -77,12 +97,75 @@ const INSTALLER_ERROR_MESSAGES = new Map([
|
|
|
77
97
|
"runtime_legacy_migration_required",
|
|
78
98
|
"Existing preview Agent Runtime state requires a separately reviewed migration; it was not reset.",
|
|
79
99
|
],
|
|
100
|
+
[
|
|
101
|
+
"runtime_nested_private_procfs_architecture_unsupported",
|
|
102
|
+
"Nested private procfs is unavailable on this host architecture.",
|
|
103
|
+
],
|
|
104
|
+
[
|
|
105
|
+
"runtime_nested_private_procfs_mode_invalid",
|
|
106
|
+
"The Agent Runtime installer rejected the nested-private-procfs action.",
|
|
107
|
+
],
|
|
108
|
+
[
|
|
109
|
+
"runtime_apparmor_policy_bundle_invalid",
|
|
110
|
+
"The signed Runtime bundle does not contain a valid nested-private-procfs policy set.",
|
|
111
|
+
],
|
|
112
|
+
[
|
|
113
|
+
"runtime_apparmor_state_unverifiable",
|
|
114
|
+
"The server's AppArmor state could not be verified safely.",
|
|
115
|
+
],
|
|
116
|
+
[
|
|
117
|
+
"runtime_apparmor_policy_unsupported",
|
|
118
|
+
"The server cannot safely enable the nested-private-procfs AppArmor policy.",
|
|
119
|
+
],
|
|
120
|
+
[
|
|
121
|
+
"runtime_apparmor_policy_backup_failed",
|
|
122
|
+
"The existing AppArmor policy state could not be preserved exactly.",
|
|
123
|
+
],
|
|
124
|
+
[
|
|
125
|
+
"runtime_apparmor_policy_conflict",
|
|
126
|
+
"The server has a conflicting nested-private-procfs AppArmor policy state.",
|
|
127
|
+
],
|
|
128
|
+
[
|
|
129
|
+
"runtime_apparmor_policy_parse_failed",
|
|
130
|
+
"The signed nested-private-procfs AppArmor policy did not pass host validation.",
|
|
131
|
+
],
|
|
132
|
+
[
|
|
133
|
+
"runtime_apparmor_policy_install_failed",
|
|
134
|
+
"The nested-private-procfs AppArmor policy could not be installed safely.",
|
|
135
|
+
],
|
|
136
|
+
[
|
|
137
|
+
"runtime_apparmor_policy_load_failed",
|
|
138
|
+
"The nested-private-procfs AppArmor policy could not be loaded and verified.",
|
|
139
|
+
],
|
|
140
|
+
[
|
|
141
|
+
"runtime_apparmor_policy_disable_failed",
|
|
142
|
+
"The nested-private-procfs AppArmor policy could not be disabled and restored safely.",
|
|
143
|
+
],
|
|
144
|
+
[
|
|
145
|
+
"runtime_apparmor_policy_rollback_failed",
|
|
146
|
+
"The AppArmor policy transaction could not restore its prior state; operator recovery is required.",
|
|
147
|
+
],
|
|
148
|
+
[
|
|
149
|
+
"runtime_apparmor_policy_recovery_failed",
|
|
150
|
+
"A prior interrupted AppArmor policy transaction could not be recovered; operator recovery is required.",
|
|
151
|
+
],
|
|
80
152
|
]);
|
|
81
153
|
|
|
154
|
+
const RECOVERY_ERROR_PRIORITY = [
|
|
155
|
+
"runtime_apparmor_policy_rollback_failed",
|
|
156
|
+
"runtime_apparmor_policy_recovery_failed",
|
|
157
|
+
];
|
|
158
|
+
|
|
82
159
|
function mappedInstallerError(result) {
|
|
83
160
|
const lines = `${result.stderr}\n${result.stdout}`
|
|
84
161
|
.split(/\r?\n/)
|
|
85
162
|
.map((line) => line.trim());
|
|
163
|
+
for (const code of RECOVERY_ERROR_PRIORITY) {
|
|
164
|
+
if (lines.includes(code)) {
|
|
165
|
+
const message = INSTALLER_ERROR_MESSAGES.get(code);
|
|
166
|
+
return { code, message: `${message} (${code})` };
|
|
167
|
+
}
|
|
168
|
+
}
|
|
86
169
|
for (const [code, message] of INSTALLER_ERROR_MESSAGES) {
|
|
87
170
|
if (lines.includes(code)) return { code, message: `${message} (${code})` };
|
|
88
171
|
}
|
|
@@ -271,6 +354,7 @@ export async function installRuntime({
|
|
|
271
354
|
identity,
|
|
272
355
|
sshUser,
|
|
273
356
|
bootstrap,
|
|
357
|
+
nestedPrivateProcfs = "preserve",
|
|
274
358
|
fetchImpl = globalThis.fetch,
|
|
275
359
|
spawnImpl = nodeSpawn,
|
|
276
360
|
}) {
|
|
@@ -284,6 +368,20 @@ export async function installRuntime({
|
|
|
284
368
|
});
|
|
285
369
|
}
|
|
286
370
|
const metadata = validateArtifact(bootstrap?.artifact);
|
|
371
|
+
if (!new Set(["preserve", "enable", "disable"]).has(nestedPrivateProcfs)) {
|
|
372
|
+
throw new CliError("The nested private procfs action is invalid.", {
|
|
373
|
+
exitCode: 2,
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
if (
|
|
377
|
+
nestedPrivateProcfs !== "preserve" &&
|
|
378
|
+
!supportsNestedPrivateProcfs(metadata.version)
|
|
379
|
+
) {
|
|
380
|
+
throw new CliError(
|
|
381
|
+
`Agent Runtime ${metadata.version} does not support nested private procfs actions.`,
|
|
382
|
+
{ exitCode: 4 },
|
|
383
|
+
);
|
|
384
|
+
}
|
|
287
385
|
const bootstrapToken = bootstrap?.bootstrapToken;
|
|
288
386
|
if (
|
|
289
387
|
typeof bootstrapToken !== "string" ||
|
|
@@ -316,16 +414,26 @@ export async function installRuntime({
|
|
|
316
414
|
spawnImpl,
|
|
317
415
|
},
|
|
318
416
|
);
|
|
319
|
-
|
|
320
|
-
const
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
417
|
+
const expectedFiles = requiredFiles(metadata.version);
|
|
418
|
+
const actualFiles = await readdir(extractPath);
|
|
419
|
+
const exactNames =
|
|
420
|
+
actualFiles.length === expectedFiles.length &&
|
|
421
|
+
expectedFiles.every((name) => actualFiles.includes(name));
|
|
422
|
+
if (!exactNames) {
|
|
324
423
|
throw new CliError(
|
|
325
|
-
"The signed runtime bundle
|
|
424
|
+
"The signed runtime bundle files do not match this CLI version.",
|
|
326
425
|
{ exitCode: 4 },
|
|
327
426
|
);
|
|
328
427
|
}
|
|
428
|
+
for (const file of expectedFiles) {
|
|
429
|
+
const metadata = await lstat(join(extractPath, file));
|
|
430
|
+
if (!metadata.isFile() || metadata.isSymbolicLink()) {
|
|
431
|
+
throw new CliError(
|
|
432
|
+
"The signed runtime bundle files do not match this CLI version.",
|
|
433
|
+
{ exitCode: 4 },
|
|
434
|
+
);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
329
437
|
remoteTouched = true;
|
|
330
438
|
await spawnChecked(
|
|
331
439
|
"scp",
|
|
@@ -351,19 +459,23 @@ export async function installRuntime({
|
|
|
351
459
|
],
|
|
352
460
|
{ spawnImpl },
|
|
353
461
|
);
|
|
462
|
+
const installerArguments = [
|
|
463
|
+
...ssh,
|
|
464
|
+
"sudo",
|
|
465
|
+
`${remoteBundle}/install.sh`,
|
|
466
|
+
"--api",
|
|
467
|
+
client.baseUrl,
|
|
468
|
+
"--server",
|
|
469
|
+
serverId,
|
|
470
|
+
"--bundle",
|
|
471
|
+
remoteBundle,
|
|
472
|
+
];
|
|
473
|
+
if (nestedPrivateProcfs !== "preserve") {
|
|
474
|
+
installerArguments.push("--nested-private-procfs", nestedPrivateProcfs);
|
|
475
|
+
}
|
|
354
476
|
await spawnChecked(
|
|
355
477
|
"ssh",
|
|
356
|
-
|
|
357
|
-
...ssh,
|
|
358
|
-
"sudo",
|
|
359
|
-
`${remoteBundle}/install.sh`,
|
|
360
|
-
"--api",
|
|
361
|
-
client.baseUrl,
|
|
362
|
-
"--server",
|
|
363
|
-
serverId,
|
|
364
|
-
"--bundle",
|
|
365
|
-
remoteBundle,
|
|
366
|
-
],
|
|
478
|
+
installerArguments,
|
|
367
479
|
{
|
|
368
480
|
stdin: `${bootstrapToken}\n`,
|
|
369
481
|
spawnImpl,
|
|
@@ -378,7 +490,12 @@ export async function installRuntime({
|
|
|
378
490
|
spawnImpl,
|
|
379
491
|
},
|
|
380
492
|
);
|
|
381
|
-
return {
|
|
493
|
+
return {
|
|
494
|
+
serverId,
|
|
495
|
+
supervisorVersion: metadata.version,
|
|
496
|
+
installed: true,
|
|
497
|
+
nestedPrivateProcfsAction: nestedPrivateProcfs,
|
|
498
|
+
};
|
|
382
499
|
} catch (error) {
|
|
383
500
|
operationFailed = true;
|
|
384
501
|
throw error;
|