Production readiness hardening and ops tooling

This commit is contained in:
2026-05-29 10:10:12 +07:00
parent e0b8f9af9a
commit 648e77cee9
68 changed files with 12222 additions and 848 deletions

View File

@ -0,0 +1,71 @@
#!/usr/bin/env node
import fs from "node:fs";
const args = process.argv.slice(2);
function getArg(name) {
const index = args.indexOf(name);
return index >= 0 ? args[index + 1] : undefined;
}
function hasFlag(name) {
return args.includes(name);
}
function usage() {
console.log(`Usage:
node scripts/check-mqtt-acl.mjs --file /etc/mosquitto/acl
node scripts/check-mqtt-acl.mjs --print-template
Required Mosquitto ACL rules:
pattern readwrite devices/%u/uplink/#
pattern read devices/%u/downlink/#
user qris-backend
topic read devices/+/uplink/#
topic write devices/+/downlink/#
`);
}
const requiredLines = [
"pattern readwrite devices/%u/uplink/#",
"pattern read devices/%u/downlink/#",
"user qris-backend",
"topic read devices/+/uplink/#",
"topic write devices/+/downlink/#"
];
if (hasFlag("--help") || hasFlag("-h")) {
usage();
process.exit(0);
}
if (hasFlag("--print-template")) {
console.log(`# QRIS Soundbox Mosquitto ACL
# Device username must equal platform device_id.
${requiredLines.join("\n")}
`);
process.exit(0);
}
const aclFile = getArg("--file") || process.env.MOSQUITTO_ACL_FILE;
if (!aclFile) {
usage();
process.exit(1);
}
const content = fs.readFileSync(aclFile, "utf8");
const normalized = content
.split(/\r?\n/)
.map((line) => line.trim())
.filter((line) => line && !line.startsWith("#"));
const missing = requiredLines.filter((line) => !normalized.includes(line));
const result = {
file: aclFile,
ok: missing.length === 0,
missing,
required: requiredLines
};
console.log(JSON.stringify(result, null, 2));
process.exit(result.ok ? 0 : 1);