Lumi/scripts/production-diagnostics-client.js
2026-07-18 16:39:02 +02:00

67 lines
2.5 KiB
JavaScript

const fs = require("fs");
const path = require("path");
const root = path.join(__dirname, "..");
const allowedChecks = new Set(["system_health", "update_state", "plugins", "recent_errors", "benchmark"]);
const check = String(process.argv[2] || "system_health").trim();
if (!allowedChecks.has(check)) {
console.error(`Choose one of: ${Array.from(allowedChecks).join(", ")}`);
process.exit(2);
}
const configPath = path.resolve(process.env.LUMI_DIAGNOSTICS_CONFIG || path.join(root, ".secrets", "production-diagnostics.json"));
let fileConfig = {};
try {
fileConfig = JSON.parse(fs.readFileSync(configPath, "utf8"));
} catch (error) {
if (!process.env.LUMI_DIAGNOSTICS_URL || !process.env.LUMI_DIAGNOSTICS_KEY) {
console.error(`Diagnostics configuration was not found or is invalid: ${configPath}`);
process.exit(2);
}
}
const baseUrl = String(process.env.LUMI_DIAGNOSTICS_URL || fileConfig.base_url || "").trim();
const key = String(process.env.LUMI_DIAGNOSTICS_KEY || fileConfig.key || "").trim();
let endpoint;
try {
const parsed = new URL(baseUrl);
const isLoopback = ["localhost", "127.0.0.1", "::1", "[::1]"].includes(parsed.hostname);
if (parsed.protocol !== "https:" && !(parsed.protocol === "http:" && isLoopback)) {
throw new Error("Production diagnostics require HTTPS (HTTP is allowed only for loopback).");
}
if (parsed.username || parsed.password) throw new Error("Do not put credentials in the diagnostics URL.");
endpoint = new URL("/api/diagnostics/v1/run", parsed);
} catch (error) {
console.error(error.message || "Configure a valid production diagnostics URL.");
process.exit(2);
}
if (!key.startsWith("lumi_diag_")) {
console.error("The production diagnostics key is missing or invalid.");
process.exit(2);
}
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 15000);
fetch(endpoint, {
method: "POST",
headers: {
authorization: `Bearer ${key}`,
"content-type": "application/json",
accept: "application/json"
},
body: JSON.stringify({ check }),
signal: controller.signal
})
.then(async (response) => {
const body = await response.json().catch(() => null);
if (!response.ok || body?.ok !== true) {
throw new Error(body?.error || `Diagnostics request failed with HTTP ${response.status}.`);
}
console.log(JSON.stringify(body, null, 2));
})
.catch((error) => {
console.error(error.name === "AbortError" ? "Diagnostics request timed out." : error.message);
process.exitCode = 1;
})
.finally(() => clearTimeout(timeout));