feat: guard de schemas de tablas en las file tools (redirige a las table tools)

This commit is contained in:
Jordan Diaz
2026-07-25 16:12:46 +00:00
parent 6dfedd07fc
commit 5e61124c65
4 changed files with 69 additions and 4 deletions

View File

@@ -11,11 +11,26 @@ const PROTECTED_LAYOUT_PATHS = [
"template/estandar/modulos/custom-footer/",
];
// Table schemas live here. They are the .ini.php mirror of the real MySQL
// structure: editing the file by hand does not run any DDL, so the schema and
// the database drift apart (and the CMS keeps serving stale cached metadata).
const SCHEMA_DIR_PREFIX = "cms/data/schema/";
// Normalizes a relative path: drops leading slashes and "./" segments so
// "/cms/...", "./cms/..." and "cms/..." all compare equal.
function normalizeRelPath(relPath) {
let norm = String(relPath).replace(/^\/+/, "");
while (norm.startsWith("./")) {
norm = norm.slice(2).replace(/^\/+/, "");
}
return norm;
}
// Returns true when `relPath` points at the layout.json or any of the
// generated custom-{header,footer}[-twig] module folders.
export function isProtectedLayoutPath(relPath) {
if (!relPath) return false;
const norm = String(relPath).replace(/^\/+/, "");
const norm = normalizeRelPath(relPath);
return PROTECTED_LAYOUT_PATHS.some(p => {
// Folder entries end with "/" -> prefix match on the normalized path.
// File entries (no trailing slash) -> exact match only.
@@ -37,3 +52,26 @@ export function buildProtectedLayoutPathError(relPath) {
isError: true,
};
}
// Returns true when `relPath` points inside cms/data/schema/ (the table schema
// directory), so file tools can bail out before hitting the Python endpoint.
export function isProtectedSchemaPath(relPath) {
if (!relPath) return false;
const norm = normalizeRelPath(relPath);
if (!norm) return false;
return norm === SCHEMA_DIR_PREFIX.slice(0, -1) || norm.startsWith(SCHEMA_DIR_PREFIX);
}
// Builds a consistent MCP error response pointing the agent to the table tools.
export function buildProtectedSchemaPathError(relPath) {
return {
content: [{
type: "text",
text: JSON.stringify({
success: false,
error: `Forbidden path: ${relPath} lives in ${SCHEMA_DIR_PREFIX} and table schemas are read-only through the file tools (acai-write, acai-line-replace, acai-delete). To change the structure use the table tools instead - create_table, create_field, update_field, delete_field, update_table_metadata, delete_table - which run the real DDL in MySQL and refresh the caches. To read a schema use get_table_schema or acai-view.`,
}, null, 2),
}],
isError: true,
};
}