feat(settings): admin switch to allow or block members' test runs
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.
This commit is contained in:
@@ -8,7 +8,8 @@
|
||||
*
|
||||
* - `PreToolUse` (matcher Bash): denies a test run or a container command
|
||||
* (`isHeavy`) — the member commits, pulls the branch on their own machine
|
||||
* and runs it there. Claude gets the reason and stops trying.
|
||||
* and runs it there. Claude gets the reason and stops trying. An admin
|
||||
* can allow them again (Settings → AI tools, server/lib/member-policy.js).
|
||||
* - `UserPromptSubmit`: a member runs at most `MAX_AI_SESSIONS` AI sessions
|
||||
* at once (server/lib/ai-procs.js). The dashboard refuses a pane past the
|
||||
* limit itself (ESESSIONLIMIT); this catches a `claude` typed into a
|
||||
@@ -25,6 +26,7 @@ const os = require("node:os");
|
||||
const path = require("node:path");
|
||||
|
||||
const procs = require(path.join(__dirname, "..", "server", "lib", "ai-procs.js"));
|
||||
const policy = require(path.join(__dirname, "..", "server", "lib", "member-policy.js"));
|
||||
|
||||
/** Test runners and container tools, by the program a command segment runs. */
|
||||
const HEAVY_BINS = new Set([
|
||||
@@ -139,8 +141,12 @@ const DENY_REASON =
|
||||
"run them. Finish the change, tell the user which tests to run, and let them " +
|
||||
"commit, pull the branch on their own machine and test there.";
|
||||
|
||||
function guardTool(input) {
|
||||
if (input.tool_name !== "Bash" || !isHeavy(input.tool_input?.command)) return;
|
||||
/** The admin's switch (Settings → AI tools), beside this script in the app root. */
|
||||
const testsAllowed = () =>
|
||||
policy.read(path.join(__dirname, "..", policy.FILE)).allowTests === true;
|
||||
|
||||
function guardTool(input, allowed = testsAllowed()) {
|
||||
if (allowed || input.tool_name !== "Bash" || !isHeavy(input.tool_input?.command)) return;
|
||||
process.stdout.write(
|
||||
JSON.stringify({
|
||||
hookSpecificOutput: {
|
||||
|
||||
Reference in New Issue
Block a user