openship 0.6.0 → 0.6.5
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 +7 -2
- package/dist/{bare-FSUAM5V5.js → bare-XQIPDO4R.js} +10 -9
- package/dist/{chunk-PSZSKEPA.js → chunk-3ZAGC5NT.js} +64 -17
- package/dist/{chunk-6ODUBKUB.js → chunk-5OUWIPOB.js} +69 -7
- package/dist/chunk-6HOA5JT7.js +124 -0
- package/dist/{chunk-TWJCLD4W.js → chunk-6JELW75A.js} +4 -4
- package/dist/{chunk-GUQ3QCJ7.js → chunk-7334NSJL.js} +399 -369
- package/dist/chunk-7S4USQYF.js +1753 -0
- package/dist/{chunk-3LDWWY7U.js → chunk-A7EWM2KA.js} +41 -7
- package/dist/chunk-ELGRMZOW.js +25 -0
- package/dist/chunk-EZPPTWJQ.js +292 -0
- package/dist/{chunk-IXM5245F.js → chunk-GRTXMUHA.js} +553 -538
- package/dist/chunk-HPXP6LXZ.js +428 -0
- package/dist/{chunk-OTLSJYAC.js → chunk-LEYSL46B.js} +2135 -85
- package/dist/{chunk-EMXI4UCU.js → chunk-LFCSC4IU.js} +29 -10
- package/dist/{chunk-JIMUYEKN.js → chunk-MSZUCNPV.js} +1 -1
- package/dist/{chunk-OGY63DGD.js → chunk-PZRRL5PC.js} +71 -28
- package/dist/{chunk-VE2YOK4I.js → chunk-QLX7NBEA.js} +1218 -588
- package/dist/chunk-RFWJE7ZN.js +68 -0
- package/dist/{chunk-VDDMADOF.js → chunk-TM2IQPYU.js} +16 -2
- package/dist/{chunk-3FYIXVX5.js → chunk-VDESJSG6.js} +451 -106
- package/dist/{chunk-B3CE2OMR.js → chunk-VHMOQL5Y.js} +276 -50
- package/dist/{chunk-QEH4QUBX.js → chunk-VLQ3UIVO.js} +393 -53
- package/dist/{chunk-VZ2ZHPS2.js → chunk-WE7BXW6L.js} +3 -9
- package/dist/chunk-WFRXYWK2.js +444 -0
- package/dist/chunk-XRNRT37W.js +316 -0
- package/dist/{chunk-EP2TNALB.js → chunk-XVOBL7BC.js} +31 -8
- package/dist/cloud-3DODOWTR.js +36 -0
- package/dist/{detect-ALF4GXRX.js → detect-P4CIQBRH.js} +3 -3
- package/dist/{docker-QECQJ5P4.js → docker-3K2NEBD6.js} +15 -8
- package/dist/{docker-edge-executor-62N64MGS.js → docker-edge-executor-YZZ6P7IC.js} +5 -5
- package/dist/{edge-import-CQWHN2Q3.js → edge-import-MCJNVTZ2.js} +26 -23
- package/dist/edge-preflight-ES6FH4JK.js +42 -0
- package/dist/{ensure-container-edge-MJVXJQG5.js → ensure-container-edge-YPITNH45.js} +9 -8
- package/dist/{executor-JELARVKC.js → executor-DZGX55K2.js} +12 -5
- package/dist/host-channel-preflight-MUXE3KZU.js +49 -0
- package/dist/index.js +3668 -4063
- package/dist/{nginx-AXGNWRKZ.js → nginx-NSAHWGJV.js} +11 -5
- package/dist/node-bootstrap.js +241 -0
- package/dist/node-entry.js +52 -1
- package/dist/{openresty-lua-IE4P5YQX.js → openresty-lua-DR4D3EZ6.js} +6 -2
- package/dist/privilege-YTVI4SKF.js +19 -0
- package/dist/server/engine/samples/fail2ban/jail.d/sshd.local +4 -1
- package/dist/server/index.js +21501 -13137
- package/dist/server/lua/geo_country.lua +4 -3
- package/dist/server/lua/pipe_stream.lua +52 -39
- package/dist/server/lua/site_logger.lua +22 -24
- package/dist/server/migrations/0098_instance_product_mode.sql +12 -0
- package/dist/server/migrations/0099_mail_webmail_project.sql +24 -0
- package/dist/server/migrations/0100_server_ssh_private_key.sql +11 -0
- package/dist/server/migrations/0101_mail_resume_step.sql +12 -0
- package/dist/server/migrations/0102_project_workload_axes.sql +19 -0
- package/dist/server/migrations/0103_dns_credential.sql +41 -0
- package/dist/server/migrations/0104_instance_host_control.sql +15 -0
- package/dist/server/migrations/meta/_journal.json +49 -0
- package/dist/{setup-FA4PW4NU.js → setup-WUUZURHS.js} +10 -9
- package/dist/up-XEO3SR6Z.js +58 -0
- package/package.json +4 -2
- package/dist/chunk-IW2UKBVF.js +0 -144
- package/dist/chunk-ZCFVHA25.js +0 -89
- package/dist/cloud-E5M6VMCG.js +0 -31
- package/dist/server/lua/pipe_log.lua +0 -77
- /package/dist/{dist-es-JGBPABJI.js → dist-es-ZP5QDSJ3.js} +0 -0
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
#!/usr/bin/env sh
|
|
2
|
+
":" //# ; exec "$(command -v node || command -v bun)" "$0" "$@"
|
|
3
|
+
import { createRequire as __ospCreateRequire } from "node:module";
|
|
4
|
+
const require = __ospCreateRequire(import.meta.url);
|
|
5
|
+
import {
|
|
6
|
+
composeHostChannel,
|
|
7
|
+
composeHostChannelExpected,
|
|
8
|
+
composePaths,
|
|
9
|
+
thisHost
|
|
10
|
+
} from "./chunk-QLX7NBEA.js";
|
|
11
|
+
import {
|
|
12
|
+
HOST_CHANNEL_BLOCKED,
|
|
13
|
+
HOST_CHANNEL_NOT_PROVISIONED,
|
|
14
|
+
HOST_CHANNEL_OPT_OUT,
|
|
15
|
+
HOST_CHANNEL_RECHECK,
|
|
16
|
+
HOST_CHANNEL_SYMPTOM,
|
|
17
|
+
HOST_CHANNEL_UNAFFECTED,
|
|
18
|
+
HOST_CHANNEL_UNPROVISIONED,
|
|
19
|
+
explainHostChannelCause,
|
|
20
|
+
firewallAllowSteps,
|
|
21
|
+
firewallManager,
|
|
22
|
+
firewallPersists,
|
|
23
|
+
hostChannelRuleScope,
|
|
24
|
+
hostFirewallRule,
|
|
25
|
+
hostFirewallRuleRemoval,
|
|
26
|
+
wrapText
|
|
27
|
+
} from "./chunk-LEYSL46B.js";
|
|
28
|
+
|
|
29
|
+
// src/lib/host-channel-preflight.ts
|
|
30
|
+
import { spawnSync } from "child_process";
|
|
31
|
+
import chalk from "chalk";
|
|
32
|
+
import { confirm, isCancel } from "@clack/prompts";
|
|
33
|
+
var INDENT = " ";
|
|
34
|
+
function dimWrapped(text, width = 84) {
|
|
35
|
+
return wrapText(text, width).map((l) => chalk.dim(`${INDENT}${l}
|
|
36
|
+
`)).join("");
|
|
37
|
+
}
|
|
38
|
+
function blockedTail() {
|
|
39
|
+
return "\n" + dimWrapped(HOST_CHANNEL_RECHECK) + dimWrapped(HOST_CHANNEL_OPT_OUT);
|
|
40
|
+
}
|
|
41
|
+
var PROBE_SCRIPT = `const net = require("node:net");
|
|
42
|
+
const s = net.connect({ host: process.env.OPENSHIP_PROBE_HOST, port: Number(process.env.OPENSHIP_PROBE_PORT) });
|
|
43
|
+
const done = (m) => { console.log("openship-probe:" + m); try { s.destroy(); } catch {} process.exit(0); };
|
|
44
|
+
s.setTimeout(Number(process.env.OPENSHIP_PROBE_TIMEOUT || 4000));
|
|
45
|
+
s.on("connect", () => done("open"));
|
|
46
|
+
s.on("timeout", () => done("timeout"));
|
|
47
|
+
s.on("error", (e) => done("error:" + (e && e.code ? e.code : String(e && e.message))));`;
|
|
48
|
+
async function realProbe(host, port) {
|
|
49
|
+
const r = spawnSync(
|
|
50
|
+
"docker",
|
|
51
|
+
[
|
|
52
|
+
"compose",
|
|
53
|
+
"-f",
|
|
54
|
+
composePaths.file,
|
|
55
|
+
"exec",
|
|
56
|
+
"-T",
|
|
57
|
+
"-e",
|
|
58
|
+
`OPENSHIP_PROBE_HOST=${host}`,
|
|
59
|
+
"-e",
|
|
60
|
+
`OPENSHIP_PROBE_PORT=${port}`,
|
|
61
|
+
"api",
|
|
62
|
+
"bun",
|
|
63
|
+
"-e",
|
|
64
|
+
PROBE_SCRIPT
|
|
65
|
+
],
|
|
66
|
+
{ cwd: composePaths.dir, encoding: "utf8", timeout: 3e4 }
|
|
67
|
+
);
|
|
68
|
+
const token = (r.stdout || "").match(/openship-probe:(\S+)/)?.[1];
|
|
69
|
+
if (!token) {
|
|
70
|
+
const why = (r.stderr || r.stdout || r.error?.message || "").trim().split("\n").pop();
|
|
71
|
+
return { code: "unavailable", detail: why || void 0 };
|
|
72
|
+
}
|
|
73
|
+
if (token === "open" || token === "timeout") return { code: token };
|
|
74
|
+
const errno = token.startsWith("error:") ? token.slice("error:".length) : token;
|
|
75
|
+
if (errno === "ECONNREFUSED" || errno === "ECONNRESET") return { code: "refused", detail: errno };
|
|
76
|
+
if (errno === "ENOTFOUND" || errno === "EAI_AGAIN") return { code: "unresolved", detail: errno };
|
|
77
|
+
if (errno === "ENETUNREACH" || errno === "EHOSTUNREACH" || errno === "EHOSTDOWN") {
|
|
78
|
+
return { code: "no_route", detail: errno };
|
|
79
|
+
}
|
|
80
|
+
return { code: "error", detail: errno };
|
|
81
|
+
}
|
|
82
|
+
function realSourceCidrs() {
|
|
83
|
+
const id = spawnSync("docker", ["compose", "-f", composePaths.file, "ps", "-q", "api"], {
|
|
84
|
+
cwd: composePaths.dir,
|
|
85
|
+
encoding: "utf8"
|
|
86
|
+
}).stdout?.trim().split("\n")[0];
|
|
87
|
+
if (!id) return [];
|
|
88
|
+
const nets = spawnSync(
|
|
89
|
+
"docker",
|
|
90
|
+
["inspect", id, "--format", "{{range $k, $v := .NetworkSettings.Networks}}{{$k}}\n{{end}}"],
|
|
91
|
+
{ encoding: "utf8" }
|
|
92
|
+
).stdout;
|
|
93
|
+
const cidrs = /* @__PURE__ */ new Set();
|
|
94
|
+
for (const net of (nets || "").split("\n").map((n) => n.trim()).filter(Boolean)) {
|
|
95
|
+
const subnets = spawnSync(
|
|
96
|
+
"docker",
|
|
97
|
+
["network", "inspect", net, "--format", "{{range .IPAM.Config}}{{.Subnet}}\n{{end}}"],
|
|
98
|
+
{ encoding: "utf8" }
|
|
99
|
+
).stdout;
|
|
100
|
+
for (const s of (subnets || "").split("\n").map((v) => v.trim())) {
|
|
101
|
+
if (/^\d+\.\d+\.\d+\.\d+\/\d+$/.test(s)) cidrs.add(s);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return [...cidrs];
|
|
105
|
+
}
|
|
106
|
+
function sudoPrefix() {
|
|
107
|
+
if (typeof process.getuid === "function" && process.getuid() === 0) return [];
|
|
108
|
+
return process.stdin.isTTY ? ["sudo"] : ["sudo", "-n"];
|
|
109
|
+
}
|
|
110
|
+
function realApplyRule(fw, cidrs, port) {
|
|
111
|
+
const steps = firewallAllowSteps(fw, hostChannelRuleScope(cidrs, port));
|
|
112
|
+
if (!steps.supported) return { ok: false, detail: steps.reason };
|
|
113
|
+
for (const step of steps.value) {
|
|
114
|
+
const [cmd, ...rest] = [...sudoPrefix(), "sh", "-c", step];
|
|
115
|
+
const r = spawnSync(cmd, rest, { encoding: "utf8", stdio: ["inherit", "pipe", "pipe"] });
|
|
116
|
+
if (r.status !== 0) {
|
|
117
|
+
return { ok: false, detail: (r.stderr || r.stdout || "").trim().split("\n").pop() };
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return { ok: true };
|
|
121
|
+
}
|
|
122
|
+
function defaultDeps() {
|
|
123
|
+
return {
|
|
124
|
+
platform: process.platform,
|
|
125
|
+
interactive: Boolean(process.stdin.isTTY && process.stdout.isTTY),
|
|
126
|
+
channel: composeHostChannel,
|
|
127
|
+
expected: composeHostChannelExpected,
|
|
128
|
+
probe: realProbe,
|
|
129
|
+
sourceCidrs: realSourceCidrs,
|
|
130
|
+
// All three off the one resolver, which measures this box once. This file used to
|
|
131
|
+
// run its own `command -v ufw` + `ufw status` ladder, so the CLI and the API could
|
|
132
|
+
// reach different conclusions about the same host — and it had no way at all to
|
|
133
|
+
// report nftables, the RHEL-family default.
|
|
134
|
+
firewall: () => thisHost().profile.firewall,
|
|
135
|
+
distroFamily: () => thisHost().profile.distroFamily,
|
|
136
|
+
sshdEnableHint: () => thisHost().sshdEnableHint(),
|
|
137
|
+
applyRule: realApplyRule,
|
|
138
|
+
confirmOpen: async ({ rule, port }) => {
|
|
139
|
+
const ok = await confirm({
|
|
140
|
+
message: `Open the host firewall so containers can reach port ${port}?`,
|
|
141
|
+
// Never default-yes: this edits the host's firewall.
|
|
142
|
+
initialValue: false
|
|
143
|
+
});
|
|
144
|
+
return !isCancel(ok) && ok === true;
|
|
145
|
+
},
|
|
146
|
+
print: (text) => console.log(text)
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
function impactLines() {
|
|
150
|
+
return dimWrapped(HOST_CHANNEL_UNAFFECTED) + chalk.dim(`${INDENT}Blocked until the channel works:
|
|
151
|
+
`) + HOST_CHANNEL_BLOCKED.map((l) => chalk.dim(`${INDENT} \xB7 ${l}
|
|
152
|
+
`)).join("") + dimWrapped(HOST_CHANNEL_SYMPTOM);
|
|
153
|
+
}
|
|
154
|
+
function causeOf(code) {
|
|
155
|
+
switch (code) {
|
|
156
|
+
case "timeout":
|
|
157
|
+
case "refused":
|
|
158
|
+
case "unresolved":
|
|
159
|
+
case "no_route":
|
|
160
|
+
case "error":
|
|
161
|
+
return code;
|
|
162
|
+
default:
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
function diagnose(target, probe, sshdEnableHint) {
|
|
167
|
+
const cause = causeOf(probe.code);
|
|
168
|
+
if (!cause) {
|
|
169
|
+
return {
|
|
170
|
+
firewall: false,
|
|
171
|
+
text: chalk.yellow(`${INDENT}${target} \u2014 ${probe.detail || "the connection failed"}
|
|
172
|
+
`)
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
const { headline, body, firewallShaped } = explainHostChannelCause(cause, {
|
|
176
|
+
target,
|
|
177
|
+
host: target.split(":")[0],
|
|
178
|
+
detail: probe.detail,
|
|
179
|
+
sshdEnableHint
|
|
180
|
+
});
|
|
181
|
+
return {
|
|
182
|
+
firewall: firewallShaped,
|
|
183
|
+
text: chalk.yellow(`${INDENT}${headline}
|
|
184
|
+
|
|
185
|
+
`) + (body ? dimWrapped(body) : "")
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
async function checkHostChannel(overrides = {}) {
|
|
189
|
+
const deps = { ...defaultDeps(), ...overrides };
|
|
190
|
+
if (deps.platform !== "linux") return { configured: false };
|
|
191
|
+
const channel = deps.channel();
|
|
192
|
+
if (!channel) return { configured: false, unprovisioned: deps.expected() };
|
|
193
|
+
const probe = await deps.probe(channel.host, channel.port);
|
|
194
|
+
return {
|
|
195
|
+
configured: true,
|
|
196
|
+
target: `${channel.host}:${channel.port}`,
|
|
197
|
+
code: probe.code,
|
|
198
|
+
detail: probe.detail
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
async function verifyHostChannel(opts = {}, overrides = {}) {
|
|
202
|
+
const deps = { ...defaultDeps(), ...overrides };
|
|
203
|
+
if (deps.platform !== "linux") return { status: "skipped" };
|
|
204
|
+
const channel = deps.channel();
|
|
205
|
+
if (!channel) {
|
|
206
|
+
if (!deps.expected()) return { status: "skipped" };
|
|
207
|
+
deps.print(
|
|
208
|
+
chalk.yellow(`
|
|
209
|
+
${INDENT}Host control was not provisioned on this box.
|
|
210
|
+
|
|
211
|
+
`) + dimWrapped(HOST_CHANNEL_UNPROVISIONED) + "\n" + impactLines() + // The remedy, not a firewall rule: nothing was dialed, so no packet filter has
|
|
212
|
+
// been established — the same line core's `firewallShaped` draws. It carries the
|
|
213
|
+
// recheck command itself, so `blockedTail` would only repeat it.
|
|
214
|
+
chalk.dim(`
|
|
215
|
+
${INDENT}Fix:
|
|
216
|
+
`) + dimWrapped(HOST_CHANNEL_NOT_PROVISIONED) + dimWrapped(HOST_CHANNEL_OPT_OUT)
|
|
217
|
+
);
|
|
218
|
+
return { status: "unprovisioned" };
|
|
219
|
+
}
|
|
220
|
+
const target = `${channel.host}:${channel.port}`;
|
|
221
|
+
const probe = await deps.probe(channel.host, channel.port);
|
|
222
|
+
if (probe.code === "open") return { status: "ok", code: "open" };
|
|
223
|
+
if (probe.code === "unavailable") {
|
|
224
|
+
deps.print(
|
|
225
|
+
chalk.dim(
|
|
226
|
+
`
|
|
227
|
+
${INDENT}Couldn't check the host channel from the api container${probe.detail ? ` (${probe.detail})` : ""}.
|
|
228
|
+
${INDENT}Verify it later with \`openship doctor\`.
|
|
229
|
+
`
|
|
230
|
+
)
|
|
231
|
+
);
|
|
232
|
+
return { status: "skipped", code: "unavailable" };
|
|
233
|
+
}
|
|
234
|
+
const { text, firewall: firewallShaped } = diagnose(target, probe, deps.sshdEnableHint());
|
|
235
|
+
deps.print(
|
|
236
|
+
chalk.yellow(`
|
|
237
|
+
${INDENT}Host control is configured, but the api container can't reach it.
|
|
238
|
+
|
|
239
|
+
`) + text + "\n" + impactLines()
|
|
240
|
+
);
|
|
241
|
+
if (!firewallShaped) {
|
|
242
|
+
deps.print(blockedTail());
|
|
243
|
+
return { status: "blocked", code: probe.code };
|
|
244
|
+
}
|
|
245
|
+
const cidrs = deps.sourceCidrs();
|
|
246
|
+
const firewall = deps.firewall();
|
|
247
|
+
const rule = hostFirewallRule(firewall, cidrs, channel.port, deps.distroFamily());
|
|
248
|
+
const ruleBlock = chalk.dim(`
|
|
249
|
+
${INDENT}Rule to allow it${cidrs.length ? "" : ` (docker's default pool \u2014 the exact subnet couldn't be read)`}:
|
|
250
|
+
`) + rule.split("\n").map((l) => `${INDENT} ${chalk.cyan(l)}`).join("\n") + "\n";
|
|
251
|
+
const offerOnly = (why) => {
|
|
252
|
+
deps.print(ruleBlock + "\n" + dimWrapped(why) + blockedTail());
|
|
253
|
+
return { status: "blocked", code: probe.code, rule };
|
|
254
|
+
};
|
|
255
|
+
const manager = firewallManager(firewall);
|
|
256
|
+
if (!manager.supported) return offerOnly(manager.reason);
|
|
257
|
+
if (!firewallPersists(firewall)) {
|
|
258
|
+
return offerOnly(
|
|
259
|
+
`Openship won't add this ${firewall} rule for you: it lives in the running ruleset only, so it would not survive a reboot unless something saves it \u2014 and where that is depends on this box. A rule that quietly disappears is worse than one you installed knowing where it lives.`
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
deps.print(ruleBlock);
|
|
263
|
+
const consented = opts.openFirewall ? true : deps.interactive ? await deps.confirmOpen({ rule, port: channel.port }) : false;
|
|
264
|
+
if (!consented) {
|
|
265
|
+
deps.print(
|
|
266
|
+
chalk.dim(
|
|
267
|
+
`
|
|
268
|
+
${INDENT}Left the firewall alone \u2014 apply the rule above when you're ready.
|
|
269
|
+
` + (deps.interactive ? "" : `${INDENT}To have \`openship up\` add it for you: --open-host-firewall
|
|
270
|
+
`)
|
|
271
|
+
) + blockedTail()
|
|
272
|
+
);
|
|
273
|
+
return { status: "blocked", code: probe.code, rule };
|
|
274
|
+
}
|
|
275
|
+
const applied = deps.applyRule(manager.value, cidrs, channel.port);
|
|
276
|
+
if (!applied.ok) {
|
|
277
|
+
deps.print(
|
|
278
|
+
chalk.red(
|
|
279
|
+
`
|
|
280
|
+
${INDENT}Couldn't add the rule${applied.detail ? `: ${applied.detail}` : "."}
|
|
281
|
+
`
|
|
282
|
+
) + chalk.dim(`${INDENT}Run it yourself with the command above.
|
|
283
|
+
`) + blockedTail()
|
|
284
|
+
);
|
|
285
|
+
return { status: "blocked", code: probe.code, rule };
|
|
286
|
+
}
|
|
287
|
+
const again = await deps.probe(channel.host, channel.port);
|
|
288
|
+
if (again.code === "open") {
|
|
289
|
+
deps.print(chalk.green(`
|
|
290
|
+
${INDENT}Opened \u2014 the host channel is reachable.
|
|
291
|
+
`));
|
|
292
|
+
return { status: "fixed", code: "open", rule };
|
|
293
|
+
}
|
|
294
|
+
deps.print(
|
|
295
|
+
chalk.yellow(`
|
|
296
|
+
${INDENT}Rule added, but ${target} still isn't reachable.
|
|
297
|
+
|
|
298
|
+
`) + (again.code === probe.code ? chalk.dim(
|
|
299
|
+
`${INDENT}Nothing changed, so something ahead of ${firewall} is dropping it \u2014 check
|
|
300
|
+
${INDENT}the DOCKER-USER chain and any cloud/provider firewall.
|
|
301
|
+
`
|
|
302
|
+
) : diagnose(target, again, deps.sshdEnableHint()).text) + // The rule is a host change made on the premise that it was the blocker, so it
|
|
303
|
+
// must not be left invisible. It is deliberately NOT reverted for us: a failure
|
|
304
|
+
// that changed shape means the rule did something, and it may well be needed
|
|
305
|
+
// once the real cause is fixed.
|
|
306
|
+
chalk.dim(`
|
|
307
|
+
${INDENT}The rule is in place; to undo it:
|
|
308
|
+
`) + hostFirewallRuleRemoval(firewall, cidrs, channel.port).split("\n").map((l) => `${INDENT} ${chalk.cyan(l)}`).join("\n") + "\n" + blockedTail()
|
|
309
|
+
);
|
|
310
|
+
return { status: "blocked", code: again.code, rule };
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
export {
|
|
314
|
+
checkHostChannel,
|
|
315
|
+
verifyHostChannel
|
|
316
|
+
};
|
|
@@ -3,10 +3,11 @@
|
|
|
3
3
|
import { createRequire as __ospCreateRequire } from "node:module";
|
|
4
4
|
const require = __ospCreateRequire(import.meta.url);
|
|
5
5
|
import {
|
|
6
|
+
COMPONENT_CHECKS,
|
|
6
7
|
COMPONENT_INSTALLERS,
|
|
7
8
|
checkAll,
|
|
8
9
|
checkComponents
|
|
9
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-7334NSJL.js";
|
|
10
11
|
|
|
11
12
|
// ../../packages/adapters/src/system/state.ts
|
|
12
13
|
var DEFAULT_STATE_PATH = "/etc/openship/setup-state.json";
|
|
@@ -69,6 +70,8 @@ var SystemManager = class {
|
|
|
69
70
|
assumeInstalled;
|
|
70
71
|
/** In-memory cache to avoid even reading from disk/DB on hot paths. */
|
|
71
72
|
cachedState = null;
|
|
73
|
+
/** In-flight background re-verification, if any (see kickBackgroundVerify). */
|
|
74
|
+
verifyInFlight = null;
|
|
72
75
|
constructor(mode, opts) {
|
|
73
76
|
this.mode = mode;
|
|
74
77
|
this.executor = opts.executor;
|
|
@@ -86,18 +89,16 @@ var SystemManager = class {
|
|
|
86
89
|
* Returns false if:
|
|
87
90
|
* - No cached state (first boot)
|
|
88
91
|
* - Cached state says setupComplete = false
|
|
89
|
-
*
|
|
92
|
+
*
|
|
93
|
+
* A stale cache (> 24h) still answers true, with a re-verification kicked behind
|
|
94
|
+
* the call — this must never block.
|
|
90
95
|
*
|
|
91
96
|
* Use this on hot paths (every request). It's essentially free.
|
|
92
97
|
*/
|
|
93
98
|
async isReady() {
|
|
94
99
|
const state = await this.loadState();
|
|
95
100
|
if (!state?.setupComplete) return false;
|
|
96
|
-
if (this.isStale(state))
|
|
97
|
-
this.verify().catch(() => {
|
|
98
|
-
});
|
|
99
|
-
return true;
|
|
100
|
-
}
|
|
101
|
+
if (this.isStale(state)) this.kickBackgroundVerify();
|
|
101
102
|
return true;
|
|
102
103
|
}
|
|
103
104
|
/**
|
|
@@ -145,6 +146,7 @@ var SystemManager = class {
|
|
|
145
146
|
(name) => state.components[name]?.healthy === true
|
|
146
147
|
);
|
|
147
148
|
if (allPresent) {
|
|
149
|
+
if (this.isStale(state)) this.kickBackgroundVerify();
|
|
148
150
|
return { feature, ready: true, missing: [], message: `${feature} is ready` };
|
|
149
151
|
}
|
|
150
152
|
}
|
|
@@ -295,6 +297,21 @@ var SystemManager = class {
|
|
|
295
297
|
this.cachedState = await this.stateStore.get();
|
|
296
298
|
return this.cachedState;
|
|
297
299
|
}
|
|
300
|
+
/**
|
|
301
|
+
* Run the staleness re-verification behind the caller — one at a time.
|
|
302
|
+
*
|
|
303
|
+
* The dedup is the point: a single deploy gates several features in a row, and
|
|
304
|
+
* every request calls isReady(), so an un-guarded kick would stack one full
|
|
305
|
+
* checkAll per call — each fanning 4 concurrent probes onto the same ssh
|
|
306
|
+
* connection, against sshd's MaxSessions (see mapWithConcurrency in checks.ts).
|
|
307
|
+
*/
|
|
308
|
+
kickBackgroundVerify() {
|
|
309
|
+
if (this.verifyInFlight) return;
|
|
310
|
+
this.verifyInFlight = this.verify().catch(() => {
|
|
311
|
+
}).finally(() => {
|
|
312
|
+
this.verifyInFlight = null;
|
|
313
|
+
});
|
|
314
|
+
}
|
|
298
315
|
isStale(state) {
|
|
299
316
|
if (!state.lastVerifiedAt) return true;
|
|
300
317
|
const age = Date.now() - new Date(state.lastVerifiedAt).getTime();
|
|
@@ -315,7 +332,13 @@ var SystemManager = class {
|
|
|
315
332
|
(name) => existing.components[name]?.installed
|
|
316
333
|
);
|
|
317
334
|
existing.setupComplete = allRequired;
|
|
318
|
-
|
|
335
|
+
const checked = new Set(components.map((c) => c.name));
|
|
336
|
+
const coveredAll = this.required.every(
|
|
337
|
+
(name) => checked.has(name) || !COMPONENT_CHECKS[name]
|
|
338
|
+
);
|
|
339
|
+
if (coveredAll) {
|
|
340
|
+
existing.lastVerifiedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
341
|
+
}
|
|
319
342
|
existing.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
320
343
|
this.cachedState = existing;
|
|
321
344
|
await this.stateStore.set(existing);
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env sh
|
|
2
|
+
":" //# ; exec "$(command -v node || command -v bun)" "$0" "$@"
|
|
3
|
+
import { createRequire as __ospCreateRequire } from "node:module";
|
|
4
|
+
const require = __ospCreateRequire(import.meta.url);
|
|
5
|
+
import {
|
|
6
|
+
CloudRuntime,
|
|
7
|
+
HostBuildForbiddenError,
|
|
8
|
+
PAGE_CONTAINER_PREFIX,
|
|
9
|
+
isHostBuildForbiddenError,
|
|
10
|
+
provisionCloudWorkspace
|
|
11
|
+
} from "./chunk-3ZAGC5NT.js";
|
|
12
|
+
import "./chunk-7334NSJL.js";
|
|
13
|
+
import "./chunk-VLQ3UIVO.js";
|
|
14
|
+
import "./chunk-I3DPMTSF.js";
|
|
15
|
+
import "./chunk-LFCSC4IU.js";
|
|
16
|
+
import "./chunk-MSZUCNPV.js";
|
|
17
|
+
import "./chunk-TM2IQPYU.js";
|
|
18
|
+
import "./chunk-VHMOQL5Y.js";
|
|
19
|
+
import "./chunk-5OUWIPOB.js";
|
|
20
|
+
import "./chunk-6FH4AXVY.js";
|
|
21
|
+
import "./chunk-RFWJE7ZN.js";
|
|
22
|
+
import "./chunk-WE7BXW6L.js";
|
|
23
|
+
import "./chunk-A7EWM2KA.js";
|
|
24
|
+
import "./chunk-PZRRL5PC.js";
|
|
25
|
+
import "./chunk-EZPPTWJQ.js";
|
|
26
|
+
import "./chunk-WFRXYWK2.js";
|
|
27
|
+
import "./chunk-ZFJXPCQP.js";
|
|
28
|
+
import "./chunk-LEYSL46B.js";
|
|
29
|
+
import "./chunk-PXKCZB2I.js";
|
|
30
|
+
export {
|
|
31
|
+
CloudRuntime,
|
|
32
|
+
HostBuildForbiddenError,
|
|
33
|
+
PAGE_CONTAINER_PREFIX,
|
|
34
|
+
isHostBuildForbiddenError,
|
|
35
|
+
provisionCloudWorkspace
|
|
36
|
+
};
|
|
@@ -20,9 +20,9 @@ import {
|
|
|
20
20
|
sanitizeEdgeVhosts,
|
|
21
21
|
sq,
|
|
22
22
|
stopTargetsForStatus
|
|
23
|
-
} from "./chunk-
|
|
24
|
-
import "./chunk-
|
|
25
|
-
import "./chunk-
|
|
23
|
+
} from "./chunk-WE7BXW6L.js";
|
|
24
|
+
import "./chunk-A7EWM2KA.js";
|
|
25
|
+
import "./chunk-LEYSL46B.js";
|
|
26
26
|
import "./chunk-PXKCZB2I.js";
|
|
27
27
|
export {
|
|
28
28
|
EDGE_CONTAINER_NAME,
|
|
@@ -6,27 +6,34 @@ import {
|
|
|
6
6
|
DockerRuntime,
|
|
7
7
|
buildInContainerExecCmd,
|
|
8
8
|
buildNetworkAliases,
|
|
9
|
+
gracefulStopForGrace,
|
|
9
10
|
ownsBuiltImage,
|
|
10
11
|
packBuildContext,
|
|
11
12
|
parseContainerEventLine,
|
|
12
13
|
parsePortBindings,
|
|
13
14
|
resolveExecExitCode,
|
|
14
|
-
splitDockerFrames
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
import "./chunk-
|
|
19
|
-
import "./chunk-
|
|
20
|
-
import "./chunk-
|
|
15
|
+
splitDockerFrames,
|
|
16
|
+
toDockerHealthcheck,
|
|
17
|
+
toStopConfig
|
|
18
|
+
} from "./chunk-VDESJSG6.js";
|
|
19
|
+
import "./chunk-LFCSC4IU.js";
|
|
20
|
+
import "./chunk-TM2IQPYU.js";
|
|
21
|
+
import "./chunk-5OUWIPOB.js";
|
|
22
|
+
import "./chunk-WFRXYWK2.js";
|
|
23
|
+
import "./chunk-ZFJXPCQP.js";
|
|
24
|
+
import "./chunk-LEYSL46B.js";
|
|
21
25
|
import "./chunk-PXKCZB2I.js";
|
|
22
26
|
export {
|
|
23
27
|
DockerRuntime,
|
|
24
28
|
buildInContainerExecCmd,
|
|
25
29
|
buildNetworkAliases,
|
|
30
|
+
gracefulStopForGrace,
|
|
26
31
|
ownsBuiltImage,
|
|
27
32
|
packBuildContext,
|
|
28
33
|
parseContainerEventLine,
|
|
29
34
|
parsePortBindings,
|
|
30
35
|
resolveExecExitCode,
|
|
31
|
-
splitDockerFrames
|
|
36
|
+
splitDockerFrames,
|
|
37
|
+
toDockerHealthcheck,
|
|
38
|
+
toStopConfig
|
|
32
39
|
};
|
|
@@ -4,13 +4,13 @@ import { createRequire as __ospCreateRequire } from "node:module";
|
|
|
4
4
|
const require = __ospCreateRequire(import.meta.url);
|
|
5
5
|
import {
|
|
6
6
|
DockerEdgeExecutor
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-6FH4AXVY.js";
|
|
7
|
+
} from "./chunk-6JELW75A.js";
|
|
9
8
|
import "./chunk-I3DPMTSF.js";
|
|
10
|
-
import "./chunk-
|
|
11
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-6FH4AXVY.js";
|
|
10
|
+
import "./chunk-WE7BXW6L.js";
|
|
11
|
+
import "./chunk-A7EWM2KA.js";
|
|
12
12
|
import "./chunk-ZFJXPCQP.js";
|
|
13
|
-
import "./chunk-
|
|
13
|
+
import "./chunk-LEYSL46B.js";
|
|
14
14
|
import "./chunk-PXKCZB2I.js";
|
|
15
15
|
export {
|
|
16
16
|
DockerEdgeExecutor
|
|
@@ -6,40 +6,43 @@ import {
|
|
|
6
6
|
importMigratedSites,
|
|
7
7
|
waitForApiHealth,
|
|
8
8
|
waitForEdgeRunning
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-6HOA5JT7.js";
|
|
10
|
+
import "./chunk-QLX7NBEA.js";
|
|
11
|
+
import "./chunk-QWHBRY2K.js";
|
|
12
|
+
import "./chunk-ELGRMZOW.js";
|
|
13
|
+
import "./chunk-ONKEYSMY.js";
|
|
10
14
|
import "./chunk-XZYFZ6A5.js";
|
|
11
15
|
import "./chunk-PDW4L3NV.js";
|
|
12
|
-
import "./chunk-QWHBRY2K.js";
|
|
13
16
|
import "./chunk-DOD2BXHQ.js";
|
|
14
17
|
import "./chunk-42WQABXM.js";
|
|
15
18
|
import "./chunk-DRK3MEDS.js";
|
|
16
19
|
import "./chunk-3NQQXMDR.js";
|
|
17
|
-
import "./chunk-
|
|
18
|
-
import "./chunk-
|
|
20
|
+
import "./chunk-ZWLDLTJP.js";
|
|
21
|
+
import "./chunk-6JELW75A.js";
|
|
22
|
+
import "./chunk-3ZAGC5NT.js";
|
|
19
23
|
import "./chunk-WNWQBB7F.js";
|
|
20
24
|
import "./chunk-2GWYYHOR.js";
|
|
21
25
|
import "./chunk-RXQBD4ZY.js";
|
|
22
|
-
import "./chunk-
|
|
23
|
-
import "./chunk-
|
|
24
|
-
import "./chunk-
|
|
25
|
-
import "./chunk-ZWLDLTJP.js";
|
|
26
|
-
import "./chunk-3FYIXVX5.js";
|
|
27
|
-
import "./chunk-EMXI4UCU.js";
|
|
28
|
-
import "./chunk-IXM5245F.js";
|
|
29
|
-
import "./chunk-JIMUYEKN.js";
|
|
30
|
-
import "./chunk-IW2UKBVF.js";
|
|
31
|
-
import "./chunk-VDDMADOF.js";
|
|
32
|
-
import "./chunk-B3CE2OMR.js";
|
|
33
|
-
import "./chunk-6ODUBKUB.js";
|
|
34
|
-
import "./chunk-ZCFVHA25.js";
|
|
35
|
-
import "./chunk-6FH4AXVY.js";
|
|
36
|
-
import "./chunk-QEH4QUBX.js";
|
|
26
|
+
import "./chunk-XVOBL7BC.js";
|
|
27
|
+
import "./chunk-7334NSJL.js";
|
|
28
|
+
import "./chunk-VLQ3UIVO.js";
|
|
37
29
|
import "./chunk-I3DPMTSF.js";
|
|
38
|
-
import "./chunk-
|
|
39
|
-
import "./chunk-
|
|
40
|
-
import "./chunk-
|
|
30
|
+
import "./chunk-VDESJSG6.js";
|
|
31
|
+
import "./chunk-LFCSC4IU.js";
|
|
32
|
+
import "./chunk-GRTXMUHA.js";
|
|
33
|
+
import "./chunk-MSZUCNPV.js";
|
|
34
|
+
import "./chunk-TM2IQPYU.js";
|
|
35
|
+
import "./chunk-VHMOQL5Y.js";
|
|
36
|
+
import "./chunk-5OUWIPOB.js";
|
|
37
|
+
import "./chunk-6FH4AXVY.js";
|
|
38
|
+
import "./chunk-RFWJE7ZN.js";
|
|
39
|
+
import "./chunk-WE7BXW6L.js";
|
|
40
|
+
import "./chunk-A7EWM2KA.js";
|
|
41
|
+
import "./chunk-PZRRL5PC.js";
|
|
42
|
+
import "./chunk-EZPPTWJQ.js";
|
|
43
|
+
import "./chunk-WFRXYWK2.js";
|
|
41
44
|
import "./chunk-ZFJXPCQP.js";
|
|
42
|
-
import "./chunk-
|
|
45
|
+
import "./chunk-LEYSL46B.js";
|
|
43
46
|
import "./chunk-PXKCZB2I.js";
|
|
44
47
|
export {
|
|
45
48
|
importMigratedSites,
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#!/usr/bin/env sh
|
|
2
|
+
":" //# ; exec "$(command -v node || command -v bun)" "$0" "$@"
|
|
3
|
+
import { createRequire as __ospCreateRequire } from "node:module";
|
|
4
|
+
const require = __ospCreateRequire(import.meta.url);
|
|
5
|
+
import {
|
|
6
|
+
completeHostEdge,
|
|
7
|
+
confirmEdgeAction,
|
|
8
|
+
diagnoseEdge,
|
|
9
|
+
markStoppedProxyImported,
|
|
10
|
+
planAndApplyHostEdge,
|
|
11
|
+
previewHostEdge,
|
|
12
|
+
remediateUnreachableStaticRoots,
|
|
13
|
+
renderEdgeConflict,
|
|
14
|
+
repairEdgeConflict,
|
|
15
|
+
rollbackHostEdge
|
|
16
|
+
} from "./chunk-HPXP6LXZ.js";
|
|
17
|
+
import "./chunk-ELGRMZOW.js";
|
|
18
|
+
import "./chunk-7334NSJL.js";
|
|
19
|
+
import "./chunk-VLQ3UIVO.js";
|
|
20
|
+
import "./chunk-I3DPMTSF.js";
|
|
21
|
+
import "./chunk-6FH4AXVY.js";
|
|
22
|
+
import "./chunk-RFWJE7ZN.js";
|
|
23
|
+
import "./chunk-WE7BXW6L.js";
|
|
24
|
+
import "./chunk-A7EWM2KA.js";
|
|
25
|
+
import "./chunk-PZRRL5PC.js";
|
|
26
|
+
import "./chunk-EZPPTWJQ.js";
|
|
27
|
+
import "./chunk-WFRXYWK2.js";
|
|
28
|
+
import "./chunk-ZFJXPCQP.js";
|
|
29
|
+
import "./chunk-LEYSL46B.js";
|
|
30
|
+
import "./chunk-PXKCZB2I.js";
|
|
31
|
+
export {
|
|
32
|
+
completeHostEdge,
|
|
33
|
+
confirmEdgeAction,
|
|
34
|
+
diagnoseEdge,
|
|
35
|
+
markStoppedProxyImported,
|
|
36
|
+
planAndApplyHostEdge,
|
|
37
|
+
previewHostEdge,
|
|
38
|
+
remediateUnreachableStaticRoots,
|
|
39
|
+
renderEdgeConflict,
|
|
40
|
+
repairEdgeConflict,
|
|
41
|
+
rollbackHostEdge
|
|
42
|
+
};
|
|
@@ -10,16 +10,17 @@ import {
|
|
|
10
10
|
resolveEdgeImage,
|
|
11
11
|
setDefaultEdgeImage,
|
|
12
12
|
verifyEdgeServing
|
|
13
|
-
} from "./chunk-
|
|
14
|
-
import "./chunk-
|
|
15
|
-
import "./chunk-ZCFVHA25.js";
|
|
16
|
-
import "./chunk-QEH4QUBX.js";
|
|
13
|
+
} from "./chunk-7334NSJL.js";
|
|
14
|
+
import "./chunk-VLQ3UIVO.js";
|
|
17
15
|
import "./chunk-I3DPMTSF.js";
|
|
18
|
-
import "./chunk-
|
|
19
|
-
import "./chunk-
|
|
20
|
-
import "./chunk-
|
|
16
|
+
import "./chunk-RFWJE7ZN.js";
|
|
17
|
+
import "./chunk-WE7BXW6L.js";
|
|
18
|
+
import "./chunk-A7EWM2KA.js";
|
|
19
|
+
import "./chunk-PZRRL5PC.js";
|
|
20
|
+
import "./chunk-EZPPTWJQ.js";
|
|
21
|
+
import "./chunk-WFRXYWK2.js";
|
|
21
22
|
import "./chunk-ZFJXPCQP.js";
|
|
22
|
-
import "./chunk-
|
|
23
|
+
import "./chunk-LEYSL46B.js";
|
|
23
24
|
import "./chunk-PXKCZB2I.js";
|
|
24
25
|
export {
|
|
25
26
|
buildEdgeRunCommand,
|