openship 0.6.1 → 0.6.6
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-IWS2QHJ3.js → bare-OXJVW3AK.js} +11 -9
- package/dist/{chunk-VZ2ZHPS2.js → chunk-2YM3NI2E.js} +3 -9
- package/dist/chunk-4I2BM2DT.js +68 -0
- package/dist/{chunk-2NZSUXOB.js → chunk-5DMWSTOM.js} +310 -1459
- package/dist/{chunk-3FYIXVX5.js → chunk-77QDF6UD.js} +581 -122
- package/dist/{chunk-IOT5ZX23.js → chunk-A4GXYE4L.js} +449 -383
- package/dist/chunk-CBLD2HS5.js +428 -0
- package/dist/chunk-ELGRMZOW.js +25 -0
- package/dist/{chunk-TWJCLD4W.js → chunk-FE7ZZQSE.js} +5 -5
- package/dist/{chunk-3NZICQHF.js → chunk-HKRQXPTI.js} +31 -8
- package/dist/{chunk-IXM5245F.js → chunk-LFE5KQ7Y.js} +553 -538
- package/dist/{chunk-VDDMADOF.js → chunk-LH2PLRQO.js} +16 -2
- package/dist/{chunk-EMXI4UCU.js → chunk-LUKYPVJ4.js} +29 -10
- package/dist/{chunk-UC7YIEHT.js → chunk-MLYSEZQB.js} +352 -47
- package/dist/chunk-NK5N5LXN.js +1681 -0
- package/dist/{chunk-RRJJGVKE.js → chunk-OBPKYXQL.js} +75 -17
- package/dist/{chunk-6ODUBKUB.js → chunk-PCPVTH6M.js} +78 -88
- package/dist/chunk-Q7WGTQQ5.js +88 -0
- package/dist/{chunk-EW6KB2J7.js → chunk-QVW76WDL.js} +440 -74
- package/dist/{chunk-YIPMDGG6.js → chunk-RSR7PFIQ.js} +79 -23
- package/dist/{chunk-3LDWWY7U.js → chunk-SM26HDS2.js} +41 -7
- package/dist/{chunk-OTLSJYAC.js → chunk-UJ6JZM65.js} +5185 -341
- package/dist/chunk-UVNMQM7W.js +444 -0
- package/dist/chunk-VTGPEC6B.js +308 -0
- package/dist/chunk-WVAML4H6.js +2145 -0
- package/dist/{chunk-JIMUYEKN.js → chunk-YIMOCZBZ.js} +1 -1
- package/dist/chunk-YMMQRE5J.js +292 -0
- package/dist/cloud-75VIT4KV.js +37 -0
- package/dist/{detect-ALF4GXRX.js → detect-OIE5V3VZ.js} +3 -3
- package/dist/{docker-QECQJ5P4.js → docker-VTR2GK5Y.js} +16 -8
- package/dist/{docker-edge-executor-62N64MGS.js → docker-edge-executor-22IBXNYJ.js} +5 -5
- package/dist/{edge-import-SAYTRJLO.js → edge-import-WJUB4M7F.js} +27 -23
- package/dist/edge-preflight-GBNCPNVU.js +42 -0
- package/dist/{ensure-container-edge-CFSCPGZK.js → ensure-container-edge-KPI2CVXJ.js} +9 -8
- package/dist/{executor-PT6UEJ5M.js → executor-7LXXZPBR.js} +15 -5
- package/dist/host-channel-preflight-KE6OONYK.js +50 -0
- package/dist/index.js +3783 -4221
- package/dist/{nginx-YOEEFBTE.js → nginx-KUFMLMAC.js} +13 -5
- package/dist/node-bootstrap.js +241 -0
- package/dist/node-entry.js +52 -1
- package/dist/{openresty-lua-WGBO2M3Z.js → openresty-lua-ATTH35BE.js} +8 -2
- package/dist/privilege-I4W3ZNZK.js +19 -0
- package/dist/server/engine/samples/amavisd/amavisd.conf +25 -0
- package/dist/server/engine/samples/fail2ban/jail.d/sshd.local +4 -1
- package/dist/server/engine/samples/postfix/master.cf +14 -0
- package/dist/server/index.js +77659 -61909
- 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/0105_mail_inbound_rules.sql +80 -0
- package/dist/server/migrations/0106_mcp_call_tracking.sql +23 -0
- package/dist/server/migrations/0107_build_minute_metering_indexes.sql +20 -0
- package/dist/server/migrations/0108_credential.sql +68 -0
- package/dist/server/migrations/meta/_journal.json +77 -0
- package/dist/{setup-M2ZDGH3O.js → setup-XGLGUUFW.js} +10 -9
- package/dist/ssh-client-JBMA7SN4.js +28 -0
- package/dist/up-K4BV7466.js +57 -0
- package/package.json +4 -2
- package/dist/chunk-IW2UKBVF.js +0 -144
- package/dist/chunk-ZCFVHA25.js +0 -89
- package/dist/cloud-M2YLWEXO.js +0 -31
- /package/dist/{dist-es-JGBPABJI.js → dist-es-AXFRS7PS.js} +0 -0
|
@@ -5,25 +5,33 @@ const require = __ospCreateRequire(import.meta.url);
|
|
|
5
5
|
import {
|
|
6
6
|
MANAGED_STATIC_BASE,
|
|
7
7
|
NginxProvider,
|
|
8
|
+
VHOST_GENERATION,
|
|
8
9
|
acmeKeyArgs,
|
|
9
10
|
assertValidChallengeToken,
|
|
11
|
+
isAcmePortBindFailure,
|
|
12
|
+
readVhostGeneration,
|
|
10
13
|
renderGeoEntries,
|
|
11
14
|
renderProxyOptions,
|
|
12
15
|
renderProxyTlsOptions,
|
|
13
16
|
summarizeCertbotFailure
|
|
14
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-QVW76WDL.js";
|
|
18
|
+
import "./chunk-RSR7PFIQ.js";
|
|
15
19
|
import "./chunk-I3DPMTSF.js";
|
|
16
|
-
import "./chunk-
|
|
17
|
-
import "./chunk-
|
|
18
|
-
import "./chunk-YIPMDGG6.js";
|
|
20
|
+
import "./chunk-YMMQRE5J.js";
|
|
21
|
+
import "./chunk-UVNMQM7W.js";
|
|
19
22
|
import "./chunk-ZFJXPCQP.js";
|
|
20
|
-
import "./chunk-
|
|
23
|
+
import "./chunk-2YM3NI2E.js";
|
|
24
|
+
import "./chunk-SM26HDS2.js";
|
|
25
|
+
import "./chunk-UJ6JZM65.js";
|
|
21
26
|
import "./chunk-PXKCZB2I.js";
|
|
22
27
|
export {
|
|
23
28
|
MANAGED_STATIC_BASE,
|
|
24
29
|
NginxProvider,
|
|
30
|
+
VHOST_GENERATION,
|
|
25
31
|
acmeKeyArgs,
|
|
26
32
|
assertValidChallengeToken,
|
|
33
|
+
isAcmePortBindFailure,
|
|
34
|
+
readVhostGeneration,
|
|
27
35
|
renderGeoEntries,
|
|
28
36
|
renderProxyOptions,
|
|
29
37
|
renderProxyTlsOptions,
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
// src/node-bootstrap.ts
|
|
2
|
+
import { spawnSync as spawnSync2 } from "child_process";
|
|
3
|
+
import { existsSync as existsSync2 } from "fs";
|
|
4
|
+
import { join as join4 } from "path";
|
|
5
|
+
import { createInterface } from "readline";
|
|
6
|
+
|
|
7
|
+
// src/lib/node-runtime.ts
|
|
8
|
+
import { execFileSync, spawnSync } from "child_process";
|
|
9
|
+
import { chmodSync, existsSync, lstatSync, mkdirSync as mkdirSync2, rmSync, symlinkSync, writeFileSync } from "fs";
|
|
10
|
+
import { join as join3 } from "path";
|
|
11
|
+
|
|
12
|
+
// src/lib/cache.ts
|
|
13
|
+
import { createHash } from "crypto";
|
|
14
|
+
import { createReadStream, createWriteStream, mkdirSync } from "fs";
|
|
15
|
+
import { dirname, join as join2 } from "path";
|
|
16
|
+
|
|
17
|
+
// src/lib/paths.ts
|
|
18
|
+
import { homedir } from "os";
|
|
19
|
+
import { join, resolve } from "path";
|
|
20
|
+
var DEFAULT_HOME = join(homedir(), ".openship");
|
|
21
|
+
var override = process.env.OPENSHIP_HOME?.trim();
|
|
22
|
+
var OS_DIR = override ? resolve(override) : DEFAULT_HOME;
|
|
23
|
+
var DATA_DIR = join(OS_DIR, "data");
|
|
24
|
+
var LOG_DIR = join(OS_DIR, "logs");
|
|
25
|
+
var AUTH_SECRET_FILE = join(OS_DIR, "auth-secret");
|
|
26
|
+
var INTERNAL_TOKEN_FILE = join(OS_DIR, "internal-token");
|
|
27
|
+
|
|
28
|
+
// src/lib/cache.ts
|
|
29
|
+
var CACHE_DIR = join2(OS_DIR, "cache");
|
|
30
|
+
var RELEASES_DIR = join2(CACHE_DIR, "releases");
|
|
31
|
+
async function downloadToFile(url, dest, onProgress) {
|
|
32
|
+
const res = await fetch(url, { headers: { "User-Agent": "openship-cli" } });
|
|
33
|
+
if (!res.ok || !res.body) throw new Error(`HTTP ${res.status} for ${url}`);
|
|
34
|
+
mkdirSync(dirname(dest), { recursive: true });
|
|
35
|
+
const total = Number(res.headers.get("content-length")) || 0;
|
|
36
|
+
const hash = createHash("sha256");
|
|
37
|
+
const file = createWriteStream(dest);
|
|
38
|
+
const reader = res.body.getReader();
|
|
39
|
+
let received = 0;
|
|
40
|
+
try {
|
|
41
|
+
for (; ; ) {
|
|
42
|
+
const { done, value } = await reader.read();
|
|
43
|
+
if (done) break;
|
|
44
|
+
hash.update(value);
|
|
45
|
+
if (!file.write(Buffer.from(value))) {
|
|
46
|
+
await new Promise((r) => file.once("drain", r));
|
|
47
|
+
}
|
|
48
|
+
received += value.length;
|
|
49
|
+
onProgress?.(received, total);
|
|
50
|
+
}
|
|
51
|
+
} finally {
|
|
52
|
+
file.end();
|
|
53
|
+
}
|
|
54
|
+
await new Promise((resolve2, reject) => {
|
|
55
|
+
file.on("finish", () => resolve2());
|
|
56
|
+
file.on("error", reject);
|
|
57
|
+
});
|
|
58
|
+
return { sha256: hash.digest("hex"), size: received };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// src/lib/node-runtime.ts
|
|
62
|
+
var NODE_MAJOR = 22;
|
|
63
|
+
var NODE_DIST = "https://nodejs.org/dist";
|
|
64
|
+
var RUNTIME_DIR = join3(OS_DIR, "runtime");
|
|
65
|
+
var RUNTIME_CURRENT = join3(RUNTIME_DIR, "current");
|
|
66
|
+
var BIN_DIR = join3(OS_DIR, "bin");
|
|
67
|
+
var LAUNCHER_PATH = join3(BIN_DIR, "openship");
|
|
68
|
+
var LAUNCHER_SH = `#!/bin/sh
|
|
69
|
+
# Openship CLI launcher \u2014 runs the tarball-installed CLI under Node.
|
|
70
|
+
# Managed by scripts/install.sh and \`openship update\`; manual edits are overwritten.
|
|
71
|
+
SELF="$0"
|
|
72
|
+
while [ -L "$SELF" ]; do
|
|
73
|
+
_t="$(readlink "$SELF")"
|
|
74
|
+
case "$_t" in /*) SELF="$_t" ;; *) SELF="$(dirname "$SELF")/$_t" ;; esac
|
|
75
|
+
done
|
|
76
|
+
BIN_DIR="$(cd "$(dirname "$SELF")" && pwd)"
|
|
77
|
+
HOME_DIR="$(dirname "$BIN_DIR")"
|
|
78
|
+
CLI="$HOME_DIR/cli/current/dist/index.js"
|
|
79
|
+
VENDORED_NODE="$HOME_DIR/runtime/current/bin/node"
|
|
80
|
+
# Prefer a system node >= ${NODE_MAJOR}; fall back to the vendored runtime.
|
|
81
|
+
if command -v node >/dev/null 2>&1 && node -e 'process.exit(+process.versions.node.split(".")[0]>=${NODE_MAJOR}?0:1)' 2>/dev/null; then
|
|
82
|
+
exec node "$CLI" "$@"
|
|
83
|
+
elif [ -x "$VENDORED_NODE" ]; then
|
|
84
|
+
exec "$VENDORED_NODE" "$CLI" "$@"
|
|
85
|
+
else
|
|
86
|
+
echo "openship: no Node >= ${NODE_MAJOR} found (system or vendored). Reinstall: curl -fsSL https://get.openship.io | sh" >&2
|
|
87
|
+
exit 127
|
|
88
|
+
fi
|
|
89
|
+
`;
|
|
90
|
+
function nodeDistOs() {
|
|
91
|
+
if (process.platform === "darwin") return "darwin";
|
|
92
|
+
if (process.platform === "linux") return "linux";
|
|
93
|
+
throw new Error(`Unsupported platform for vendored Node: ${process.platform}`);
|
|
94
|
+
}
|
|
95
|
+
function nodeDistArch() {
|
|
96
|
+
if (process.arch === "x64") return "x64";
|
|
97
|
+
if (process.arch === "arm64") return "arm64";
|
|
98
|
+
throw new Error(`Unsupported arch for vendored Node: ${process.arch}`);
|
|
99
|
+
}
|
|
100
|
+
function majorOf(bin) {
|
|
101
|
+
try {
|
|
102
|
+
const out = execFileSync(bin, ["-e", "process.stdout.write(process.versions.node)"], {
|
|
103
|
+
encoding: "utf8",
|
|
104
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
105
|
+
});
|
|
106
|
+
const m = Number(out.trim().split(".")[0]);
|
|
107
|
+
return Number.isInteger(m) ? m : null;
|
|
108
|
+
} catch {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function repoint(link, target) {
|
|
113
|
+
try {
|
|
114
|
+
if (lstatSync(link)) rmSync(link, { recursive: true, force: true });
|
|
115
|
+
} catch {
|
|
116
|
+
}
|
|
117
|
+
symlinkSync(target, link);
|
|
118
|
+
}
|
|
119
|
+
async function resolveLatestNode() {
|
|
120
|
+
const res = await fetch(`${NODE_DIST}/index.json`, {
|
|
121
|
+
headers: { "User-Agent": "openship-cli" },
|
|
122
|
+
signal: AbortSignal.timeout(15e3)
|
|
123
|
+
});
|
|
124
|
+
if (!res.ok) throw new Error(`Node dist index lookup failed: HTTP ${res.status}`);
|
|
125
|
+
const rows = await res.json();
|
|
126
|
+
const prefix = `v${NODE_MAJOR}.`;
|
|
127
|
+
const row = rows.find((r) => r.version.startsWith(prefix) && r.lts) ?? rows.find((r) => r.version.startsWith(prefix));
|
|
128
|
+
if (!row) throw new Error(`No Node ${NODE_MAJOR}.x release found on nodejs.org`);
|
|
129
|
+
return row.version;
|
|
130
|
+
}
|
|
131
|
+
async function fetchVendoredNode(onLog) {
|
|
132
|
+
const ver = await resolveLatestNode();
|
|
133
|
+
const os = nodeDistOs();
|
|
134
|
+
const arch = nodeDistArch();
|
|
135
|
+
const name = `node-${ver}-${os}-${arch}.tar.gz`;
|
|
136
|
+
mkdirSync2(RUNTIME_DIR, { recursive: true });
|
|
137
|
+
const tarball = join3(RUNTIME_DIR, name);
|
|
138
|
+
onLog?.(`Fetching Node ${ver} (${os}-${arch}) from nodejs.org\u2026`);
|
|
139
|
+
const { sha256 } = await downloadToFile(`${NODE_DIST}/${ver}/${name}`, tarball);
|
|
140
|
+
const shaRes = await fetch(`${NODE_DIST}/${ver}/SHASUMS256.txt`, {
|
|
141
|
+
headers: { "User-Agent": "openship-cli" },
|
|
142
|
+
signal: AbortSignal.timeout(15e3)
|
|
143
|
+
});
|
|
144
|
+
if (!shaRes.ok) {
|
|
145
|
+
rmSync(tarball, { force: true });
|
|
146
|
+
throw new Error(`Node checksum list fetch failed: HTTP ${shaRes.status}`);
|
|
147
|
+
}
|
|
148
|
+
const expected = (await shaRes.text()).split("\n").map((l) => l.trim()).find((l) => l.endsWith(` ${name}`) || l.endsWith(` ${name}`))?.split(/\s+/)[0]?.toLowerCase();
|
|
149
|
+
if (!expected) {
|
|
150
|
+
rmSync(tarball, { force: true });
|
|
151
|
+
throw new Error(`No checksum for ${name} in SHASUMS256.txt`);
|
|
152
|
+
}
|
|
153
|
+
if (expected !== sha256) {
|
|
154
|
+
rmSync(tarball, { force: true });
|
|
155
|
+
throw new Error(`Node download checksum mismatch (expected ${expected}, got ${sha256}).`);
|
|
156
|
+
}
|
|
157
|
+
const unpacked = join3(RUNTIME_DIR, `node-${ver}-${os}-${arch}`);
|
|
158
|
+
rmSync(unpacked, { recursive: true, force: true });
|
|
159
|
+
const untar = spawnSync("tar", ["-xzf", tarball, "-C", RUNTIME_DIR], { stdio: "inherit" });
|
|
160
|
+
if (untar.status !== 0) throw new Error("Failed to extract the Node runtime (is `tar` available?).");
|
|
161
|
+
rmSync(tarball, { force: true });
|
|
162
|
+
const nodeBin = join3(unpacked, "bin", "node");
|
|
163
|
+
if (!existsSync(nodeBin)) throw new Error(`Node unpacked but ${nodeBin} is missing (unexpected layout).`);
|
|
164
|
+
repoint(RUNTIME_CURRENT, unpacked);
|
|
165
|
+
return nodeBin;
|
|
166
|
+
}
|
|
167
|
+
async function ensureNodeRuntime(onLog) {
|
|
168
|
+
if ((majorOf("node") ?? 0) >= NODE_MAJOR) return { node: "node", source: "system" };
|
|
169
|
+
const existing = join3(RUNTIME_CURRENT, "bin", "node");
|
|
170
|
+
if (existsSync(existing) && (majorOf(existing) ?? 0) >= NODE_MAJOR) {
|
|
171
|
+
return { node: existing, source: "vendored" };
|
|
172
|
+
}
|
|
173
|
+
return { node: await fetchVendoredNode(onLog), source: "vendored" };
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// src/node-bootstrap.ts
|
|
177
|
+
var NODE_REEXEC_ENV = "OPENSHIP_NODE_REEXEC";
|
|
178
|
+
var VENDOR_ENV = "OPENSHIP_VENDOR_NODE";
|
|
179
|
+
var vendoredNode = () => join4(OS_DIR, "runtime", "current", "bin", "node");
|
|
180
|
+
function majorOf2(bin) {
|
|
181
|
+
const out = spawnSync2(bin, ["-e", "process.stdout.write(process.versions.node)"], {
|
|
182
|
+
encoding: "utf8"
|
|
183
|
+
});
|
|
184
|
+
if (out.status !== 0) return 0;
|
|
185
|
+
return Number.parseInt(out.stdout.trim().split(".")[0] ?? "", 10) || 0;
|
|
186
|
+
}
|
|
187
|
+
function reexec(nodeBin, cliPath) {
|
|
188
|
+
const res = spawnSync2(nodeBin, [cliPath, ...process.argv.slice(2)], {
|
|
189
|
+
stdio: "inherit",
|
|
190
|
+
env: { ...process.env, [NODE_REEXEC_ENV]: "1" }
|
|
191
|
+
});
|
|
192
|
+
return { handled: true, status: res.status ?? 1 };
|
|
193
|
+
}
|
|
194
|
+
function isAffirmative(answer) {
|
|
195
|
+
return !/^n/i.test(answer.trim());
|
|
196
|
+
}
|
|
197
|
+
function ask(question) {
|
|
198
|
+
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
199
|
+
return new Promise((resolve2) => {
|
|
200
|
+
rl.question(question, (answer) => {
|
|
201
|
+
rl.close();
|
|
202
|
+
resolve2(isAffirmative(answer));
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
async function recoverOldNode(opts) {
|
|
207
|
+
const existing = vendoredNode();
|
|
208
|
+
if (existsSync2(existing) && majorOf2(existing) >= NODE_MAJOR) {
|
|
209
|
+
return reexec(existing, opts.cliPath);
|
|
210
|
+
}
|
|
211
|
+
if (!opts.offerDownload) return { handled: false };
|
|
212
|
+
if (process.platform === "win32") return { handled: false };
|
|
213
|
+
const forced = process.env[VENDOR_ENV]?.trim();
|
|
214
|
+
if (forced === "0") return { handled: false };
|
|
215
|
+
if (forced !== "1") {
|
|
216
|
+
if (!process.stdin.isTTY) return { handled: false };
|
|
217
|
+
const yes = await ask(
|
|
218
|
+
`
|
|
219
|
+
Openship can download its own Node ${NODE_MAJOR} (~50 MB) into ${OS_DIR}/runtime
|
|
220
|
+
and use it for Openship only \u2014 your system Node is left exactly as it is.
|
|
221
|
+
|
|
222
|
+
Download it now? [Y/n] `
|
|
223
|
+
);
|
|
224
|
+
if (!yes) return { handled: false };
|
|
225
|
+
}
|
|
226
|
+
let nodeBin;
|
|
227
|
+
try {
|
|
228
|
+
nodeBin = (await ensureNodeRuntime(opts.log)).node;
|
|
229
|
+
} catch (e) {
|
|
230
|
+
opts.log(`Could not set up Node ${NODE_MAJOR}: ${e.message}`);
|
|
231
|
+
return { handled: false };
|
|
232
|
+
}
|
|
233
|
+
if (nodeBin === "node") return { handled: false };
|
|
234
|
+
opts.log(`Using Node ${NODE_MAJOR} from ${OS_DIR}/runtime \u2014 future runs pick it up automatically.`);
|
|
235
|
+
return reexec(nodeBin, opts.cliPath);
|
|
236
|
+
}
|
|
237
|
+
export {
|
|
238
|
+
NODE_REEXEC_ENV,
|
|
239
|
+
isAffirmative,
|
|
240
|
+
recoverOldNode
|
|
241
|
+
};
|
package/dist/node-entry.js
CHANGED
|
@@ -1,4 +1,55 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/node-entry.ts
|
|
4
|
-
import "
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
5
|
+
var HARD_FLOOR = 20;
|
|
6
|
+
var SUPPORTED = 22;
|
|
7
|
+
var INSTALLER = "curl -fsSL https://get.openship.io | sh";
|
|
8
|
+
var CLI_PATH = fileURLToPath(new URL("./index.js", import.meta.url));
|
|
9
|
+
var log = (msg) => process.stderr.write(`${msg}
|
|
10
|
+
`);
|
|
11
|
+
var runningBun = typeof process.versions.bun === "string";
|
|
12
|
+
var major = Number.parseInt(process.versions.node?.split(".")[0] ?? "", 10);
|
|
13
|
+
var reexeced = process.env.OPENSHIP_NODE_REEXEC === "1";
|
|
14
|
+
var tooOld = !runningBun && !reexeced && Number.isFinite(major) && major < SUPPORTED;
|
|
15
|
+
if (tooOld) {
|
|
16
|
+
try {
|
|
17
|
+
const { recoverOldNode } = await import("./node-bootstrap.js");
|
|
18
|
+
const outcome = await recoverOldNode({
|
|
19
|
+
cliPath: CLI_PATH,
|
|
20
|
+
// 20 and 21 DO run: reuse a Node already on disk, but don't prompt to download
|
|
21
|
+
// one on every invocation to fix a setup that already works.
|
|
22
|
+
offerDownload: major < HARD_FLOOR,
|
|
23
|
+
log
|
|
24
|
+
});
|
|
25
|
+
if (outcome.handled) process.exit(outcome.status ?? 0);
|
|
26
|
+
} catch {
|
|
27
|
+
}
|
|
28
|
+
if (major < HARD_FLOOR) {
|
|
29
|
+
process.stderr.write(
|
|
30
|
+
`
|
|
31
|
+
Openship needs Node ${SUPPORTED} or newer \u2014 this is Node v${process.versions.node}.
|
|
32
|
+
|
|
33
|
+
Install Node ${SUPPORTED}+ and re-run, or use the official installer, which
|
|
34
|
+
brings its own Node and doesn't touch the one you have:
|
|
35
|
+
|
|
36
|
+
${INSTALLER}
|
|
37
|
+
|
|
38
|
+
Non-interactive (CI, a service)? Set OPENSHIP_VENDOR_NODE=1 and Openship
|
|
39
|
+
fetches its own Node ${SUPPORTED} without asking.
|
|
40
|
+
|
|
41
|
+
If you upgrade Node with a version manager (nvm, fnm, volta), global packages
|
|
42
|
+
live per Node version \u2014 reinstall the CLI afterwards or the command will go
|
|
43
|
+
missing: npm i -g openship
|
|
44
|
+
|
|
45
|
+
`
|
|
46
|
+
);
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
process.stderr.write(
|
|
50
|
+
`Warning: Node v${process.versions.node} is below Openship's supported floor (Node ${SUPPORTED}+). It may work; it isn't tested. Upgrade, or install with:
|
|
51
|
+
${INSTALLER}
|
|
52
|
+
`
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
await import("./index.js");
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
EDGE_CHALLENGE_LOCATION,
|
|
11
11
|
EDGE_CHALLENGE_ROOT,
|
|
12
12
|
EDGE_CHALLENGE_URL_PREFIX,
|
|
13
|
+
EDGE_CLIENT_MAX_BODY_SIZE,
|
|
13
14
|
EDGE_CONTAINER_MOUNTS,
|
|
14
15
|
EDGE_DEFAULT_CERT_CN,
|
|
15
16
|
EDGE_DEFAULT_CERT_DIRNAME,
|
|
@@ -18,6 +19,7 @@ import {
|
|
|
18
19
|
EDGE_HTTPS_REJECT_BLOCK,
|
|
19
20
|
EDGE_LUA_PACKAGE_PATH,
|
|
20
21
|
EDGE_MGMT_SERVER_BLOCK,
|
|
22
|
+
EDGE_SAME_PATH_MOUNTS,
|
|
21
23
|
EDGE_SERVER_NAMES_HASH_BUCKET_SIZE,
|
|
22
24
|
EDGE_SHARED_DICTS,
|
|
23
25
|
GEOIP_DB_PATH,
|
|
@@ -38,9 +40,11 @@ import {
|
|
|
38
40
|
ensureOpenRestyConfig,
|
|
39
41
|
luaSourceAvailable,
|
|
40
42
|
parseNginxVersion
|
|
41
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-RSR7PFIQ.js";
|
|
44
|
+
import "./chunk-YMMQRE5J.js";
|
|
45
|
+
import "./chunk-UVNMQM7W.js";
|
|
42
46
|
import "./chunk-ZFJXPCQP.js";
|
|
43
|
-
import "./chunk-
|
|
47
|
+
import "./chunk-UJ6JZM65.js";
|
|
44
48
|
import "./chunk-PXKCZB2I.js";
|
|
45
49
|
export {
|
|
46
50
|
ACME_CHALLENGE_LOCATION,
|
|
@@ -50,6 +54,7 @@ export {
|
|
|
50
54
|
EDGE_CHALLENGE_LOCATION,
|
|
51
55
|
EDGE_CHALLENGE_ROOT,
|
|
52
56
|
EDGE_CHALLENGE_URL_PREFIX,
|
|
57
|
+
EDGE_CLIENT_MAX_BODY_SIZE,
|
|
53
58
|
EDGE_CONTAINER_MOUNTS,
|
|
54
59
|
EDGE_DEFAULT_CERT_CN,
|
|
55
60
|
EDGE_DEFAULT_CERT_DIRNAME,
|
|
@@ -58,6 +63,7 @@ export {
|
|
|
58
63
|
EDGE_HTTPS_REJECT_BLOCK,
|
|
59
64
|
EDGE_LUA_PACKAGE_PATH,
|
|
60
65
|
EDGE_MGMT_SERVER_BLOCK,
|
|
66
|
+
EDGE_SAME_PATH_MOUNTS,
|
|
61
67
|
EDGE_SERVER_NAMES_HASH_BUCKET_SIZE,
|
|
62
68
|
EDGE_SHARED_DICTS,
|
|
63
69
|
GEOIP_DB_PATH,
|
|
@@ -0,0 +1,19 @@
|
|
|
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
|
+
privilegedExecutor,
|
|
7
|
+
rootChecked,
|
|
8
|
+
rootOrDegrade
|
|
9
|
+
} from "./chunk-4I2BM2DT.js";
|
|
10
|
+
import "./chunk-YMMQRE5J.js";
|
|
11
|
+
import "./chunk-UVNMQM7W.js";
|
|
12
|
+
import "./chunk-ZFJXPCQP.js";
|
|
13
|
+
import "./chunk-UJ6JZM65.js";
|
|
14
|
+
import "./chunk-PXKCZB2I.js";
|
|
15
|
+
export {
|
|
16
|
+
privilegedExecutor,
|
|
17
|
+
rootChecked,
|
|
18
|
+
rootOrDegrade
|
|
19
|
+
};
|
|
@@ -477,6 +477,31 @@ $bad_header_quarantine_to = 'bad-header-quarantine';
|
|
|
477
477
|
#$undecipherable_subject_tag = '***UNCHECKED*** '; # undef disables it
|
|
478
478
|
$undecipherable_subject_tag = undef;
|
|
479
479
|
|
|
480
|
+
# ─── What happens when NO virus scanner can be reached (GH-565) ──────────────
|
|
481
|
+
#
|
|
482
|
+
# With the settings above and @av_scanners_backup = () earlier in this file, a
|
|
483
|
+
# message that no scanner could examine is DELIVERED, with no subject tag and no
|
|
484
|
+
# admin notification. That is amavis' default and it is a deliberate choice here:
|
|
485
|
+
# clamd's signature load is memory-hungry and its socket is the most fragile part
|
|
486
|
+
# of the stack, so failing OPEN keeps mail flowing on small VPSes.
|
|
487
|
+
#
|
|
488
|
+
# It is a real trade-off, so know which side you are on. Note that amavis still
|
|
489
|
+
# adds its `X-Virus-Scanned` header on this path — the header records that amavis
|
|
490
|
+
# processed the message, NOT that a scanner passed it, and it must not be read as
|
|
491
|
+
# proof of a clean scan. The Emails → Health tab is the honest signal: it reports
|
|
492
|
+
# ClamAV as Crashed/Failed and says mail is being delivered without scanning.
|
|
493
|
+
#
|
|
494
|
+
# To fail CLOSED instead — mail queues (4xx tempfail) until a scanner is back,
|
|
495
|
+
# rather than arriving unscanned — uncomment ONE of these:
|
|
496
|
+
#
|
|
497
|
+
# $virus_scanners_failure_is_fatal = 1; # scanner failure => tempfail
|
|
498
|
+
# $final_unchecked_destiny = D_TEMPFAIL; # same, via the destiny table
|
|
499
|
+
#
|
|
500
|
+
# Before you do: while clamd is down this defers EVERY inbound message, and a
|
|
501
|
+
# queue that outlives the sender's retry window loses mail. Pair it with the
|
|
502
|
+
# subject tag above if you would rather label than defer.
|
|
503
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
504
|
+
|
|
480
505
|
# Hope to fix 'nested MAIL command' issue on high load server.
|
|
481
506
|
$smtp_connection_cache_enable = 0;
|
|
482
507
|
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
[sshd]
|
|
2
2
|
backend = polling
|
|
3
3
|
journalmatch=
|
|
4
|
-
|
|
4
|
+
# openship-mail runs no sshd (SSH is on the host, not in the mail container), so
|
|
5
|
+
# there is no /var/log/auth.log for this jail to tail — leaving it enabled makes
|
|
6
|
+
# fail2ban crash-loop on a missing logpath. Disabled for the containerized engine.
|
|
7
|
+
enabled = false
|
|
5
8
|
filter = sshd
|
|
6
9
|
logpath = PH_SSHD_LOGFILE tail
|
|
7
10
|
action = PH_FAIL2BAN_ACTION[name=sshd, port="PH_SSHD_PORT", protocol=tcp]
|
|
@@ -24,12 +24,26 @@ mlmmj unix - n n - - pipe
|
|
|
24
24
|
flags=ORhu user=PH_SYS_USER_MLMMJ:PH_SYS_GROUP_MLMMJ argv=PH_CMD_MLMMJ_AMIME_RECEIVE -L PH_MLMMJ_SPOOL_DIR/${nexthop}
|
|
25
25
|
|
|
26
26
|
# Amavisd integration.
|
|
27
|
+
#
|
|
28
|
+
# smtp_tls_security_level=none is REQUIRED, not an optimisation (GH-392). This
|
|
29
|
+
# is an smtp CLIENT service, so it inherits the global smtp_tls_security_level
|
|
30
|
+
# — and amavisd's :10024 listener does not offer STARTTLS. With the global set
|
|
31
|
+
# to `encrypt` every inbound message defers with "TLS is required, but was not
|
|
32
|
+
# offered": a complete INBOUND outage, from a setting that only looks like it
|
|
33
|
+
# concerns outbound delivery. Saving an outbound relay with scope "all" sets
|
|
34
|
+
# exactly that (apps/api/src/modules/mail/admin/outbound-relay.service.ts), and
|
|
35
|
+
# so does an operator hardening TLS by hand.
|
|
36
|
+
#
|
|
37
|
+
# TLS here would be meaningless anyway: the hop is loopback to a content filter
|
|
38
|
+
# on the same host. Pinning it at the transport keeps the guarantee local to the
|
|
39
|
+
# thing that needs it, instead of depending on every writer of the global.
|
|
27
40
|
smtp-amavis unix - - n - PH_AMAVISD_MAX_SERVERS smtp
|
|
28
41
|
-o syslog_name=postfix/amavis
|
|
29
42
|
-o local_header_rewrite_clients=
|
|
30
43
|
-o smtp_data_done_timeout=1200
|
|
31
44
|
-o smtp_send_xforward_command=yes
|
|
32
45
|
-o smtp_dns_support_level=disabled
|
|
46
|
+
-o smtp_tls_security_level=none
|
|
33
47
|
-o max_use=20
|
|
34
48
|
|
|
35
49
|
# smtp port used by Amavisd to re-inject scanned email back to Postfix
|