497faae3bf
Settings → AI tools → Tests on this server (admin, S3 only). Stored in /opt/agenthub/app/member-policy.json, which member-guard.js reads as the member at each Bash call — no restart; no file = blocked. GET/PUT /api/ai-tools/member-policy, audited, 409 ENOS3 outside S3.
57 lines
1.9 KiB
JavaScript
57 lines
1.9 KiB
JavaScript
/**
|
|
* @file member-policy.js
|
|
* @description Server mode, one Linux user per account (S3): the admin's
|
|
* switch for what members' Claude may run on this box — today whether test
|
|
* runners and container commands are allowed (`allowTests`, off by default).
|
|
* Kept in `<app root>/member-policy.json` (/opt/agenthub/app, host-owned,
|
|
* world-readable), because `scripts/member-guard.js` runs AS the member and
|
|
* reads it from there; a missing or unreadable file means the default, so
|
|
* tests stay blocked unless an admin turned them on.
|
|
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
|
|
*/
|
|
|
|
const fs = require("node:fs");
|
|
const path = require("node:path");
|
|
|
|
const FILE = "member-policy.json";
|
|
const DEFAULTS = Object.freeze({ allowTests: false });
|
|
|
|
const appRoot = () => process.env.AGENTHUB_APP_ROOT || "/opt/agenthub/app";
|
|
const file = () => path.join(appRoot(), FILE);
|
|
|
|
/** The policy in force (defaults for anything missing or unreadable). */
|
|
function read(p = file()) {
|
|
try {
|
|
const j = JSON.parse(fs.readFileSync(p, "utf8"));
|
|
return { allowTests: j?.allowTests === true };
|
|
} catch {
|
|
return { ...DEFAULTS };
|
|
}
|
|
}
|
|
|
|
/** Does it apply here? Only S3 runs members' panes as their own accounts. */
|
|
function available() {
|
|
try {
|
|
return require("./linux-accounts").s3Enabled();
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
function state() {
|
|
return { available: available(), ...read() };
|
|
}
|
|
|
|
/** Writes the switch (atomically, 0644: members' hooks read it). */
|
|
function setAllowTests(on) {
|
|
const next = { ...read(), allowTests: on === true };
|
|
fs.mkdirSync(appRoot(), { recursive: true });
|
|
const tmp = `${file()}.${process.pid}.tmp`;
|
|
fs.writeFileSync(tmp, JSON.stringify(next, null, 2) + "\n", { mode: 0o644 });
|
|
fs.chmodSync(tmp, 0o644);
|
|
fs.renameSync(tmp, file());
|
|
return state();
|
|
}
|
|
|
|
module.exports = { FILE, DEFAULTS, read, available, state, setAllowTests };
|