const { roleAllows } = require("./permissions"); const ROLE_RANK = Object.freeze({ user: 1, mod: 2, admin: 3 }); const FORBIDDEN_DEFINITION_KEYS = Object.freeze([ "shell", "sql", "filesystem", "network", "code_execution", "eval" ]); function registerManagedTool(registry, metadata, definition) { validateManagedDefinition(metadata, definition); const metadataRole = metadataRequiredRole(metadata.permissions); const backendRole = normalizeRole(definition.required_role); const requiredRole = stricterRole(metadataRole, backendRole); const backendPermissionCheck = definition.permission_check; const mutating = definition.mutating === true || ["sensitive", "high", "destructive"].includes(String(definition.risk_level || metadata.risk_level || "").toLowerCase()); return registry.register({ ...definition, owning_plugin: metadata.tool_id, required_role: requiredRole, required_permission: String(definition.required_permission || `${metadata.tool_id}.use`), audit_category: String(definition.audit_category || metadata.tool_type || "ai_tool"), confirmation_required: mutating || metadata.confirmation_required === true ? true : definition.confirmation_required !== false, permission_check: (input) => { const actualRole = input.user?.isAdmin ? "admin" : input.user?.isMod ? "mod" : "user"; if (!roleAllows(actualRole, requiredRole)) return false; return backendPermissionCheck(input) === true; } }); } function validateManagedDefinition(metadata, definition) { if (!definition || typeof definition !== "object") throw new Error("AI tool definition is required."); if (!String(definition.tool_id || "").startsWith(`${metadata.tool_id}.`)) { throw new Error(`Registered tool IDs must use the ${metadata.tool_id}. namespace.`); } if (typeof definition.permission_check !== "function" || typeof definition.workflow_handler !== "function") { throw new Error("Managed AI tools require backend permission and workflow handlers."); } for (const key of FORBIDDEN_DEFINITION_KEYS) { if (definition[key] != null) throw new Error(`Managed AI tools cannot request generic ${key} access.`); } } function metadataRequiredRole(permissions) { if (typeof permissions === "string") return normalizeRole(permissions); if (Array.isArray(permissions)) { return permissions.map(normalizeRole).sort((a, b) => ROLE_RANK[b] - ROLE_RANK[a])[0] || "user"; } return normalizeRole(permissions?.required_role || permissions?.role); } function normalizeRole(value) { return Object.hasOwn(ROLE_RANK, value) ? value : "user"; } function stricterRole(left, right) { return ROLE_RANK[left] >= ROLE_RANK[right] ? left : right; } module.exports = { FORBIDDEN_DEFINITION_KEYS, registerManagedTool, validateManagedDefinition, metadataRequiredRole, stricterRole };