funifier-mcp 0.3.10 → 0.3.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cursor/rules/funifier.mdc +1 -0
- package/.github/copilot-instructions.md +1 -0
- package/AGENTS.md +2 -1
- package/README.md +13 -2
- package/datasource-funifier-docs/.coverage.json +1 -1
- package/dist/cli/config-writers.d.ts +3 -3
- package/dist/cli/config-writers.d.ts.map +1 -1
- package/dist/cli/config-writers.js +22 -24
- package/dist/cli/config-writers.js.map +1 -1
- package/dist/cli/config-writers.test.js +7 -2
- package/dist/cli/config-writers.test.js.map +1 -1
- package/dist/cli/init.d.ts.map +1 -1
- package/dist/cli/init.js +11 -9
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/init.test.js +26 -0
- package/dist/cli/init.test.js.map +1 -1
- package/dist/core/api-client.d.ts +4 -0
- package/dist/core/api-client.d.ts.map +1 -1
- package/dist/core/api-client.js +23 -0
- package/dist/core/api-client.js.map +1 -1
- package/dist/mcp/bundle.js +105 -102
- package/dist/mcp/tools/_backup.d.ts +74 -0
- package/dist/mcp/tools/_backup.d.ts.map +1 -0
- package/dist/mcp/tools/_backup.js +205 -0
- package/dist/mcp/tools/_backup.js.map +1 -0
- package/dist/mcp/tools/_backup.test.d.ts +2 -0
- package/dist/mcp/tools/_backup.test.d.ts.map +1 -0
- package/dist/mcp/tools/_backup.test.js +204 -0
- package/dist/mcp/tools/_backup.test.js.map +1 -0
- package/dist/mcp/tools/list-tools.d.ts.map +1 -1
- package/dist/mcp/tools/list-tools.js +3 -2
- package/dist/mcp/tools/list-tools.js.map +1 -1
- package/dist/mcp/tools/permissions.d.ts.map +1 -1
- package/dist/mcp/tools/permissions.js +138 -2
- package/dist/mcp/tools/permissions.js.map +1 -1
- package/dist/mcp/tools/permissions.test.js +263 -7
- package/dist/mcp/tools/permissions.test.js.map +1 -1
- package/package.json +1 -1
- package/skills/funifier/references/configure-security.md +18 -0
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.registerPermissionsTool = registerPermissionsTool;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
|
+
const _backup_1 = require("./_backup");
|
|
5
6
|
function parseJsonObject(value, label) {
|
|
6
7
|
if (!value) {
|
|
7
8
|
throw new Error(`'${label}' is required as a JSON object.`);
|
|
@@ -86,13 +87,121 @@ function upsertBy(items, candidate, matches) {
|
|
|
86
87
|
function removeBy(items, matches) {
|
|
87
88
|
return (Array.isArray(items) ? items : []).filter((item) => !matches(item));
|
|
88
89
|
}
|
|
90
|
+
/** The whole security document is the replayable unit for the 4 security-doc branches. */
|
|
91
|
+
function securityPreImage(security) {
|
|
92
|
+
// Clone so the branch can mutate `security` afterwards without corrupting the snapshot.
|
|
93
|
+
return { existedBefore: true, preImage: structuredClone(security), resourceId: security._id };
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Current studio role by `_id` (delete) or by full natural key `name`+`type`+`item` (save).
|
|
97
|
+
* Matching on `name` alone can hit the wrong role when a name repeats across `(type,item)`.
|
|
98
|
+
* Always records the natural key so a restore-to-absent can resolve the server `_id` later.
|
|
99
|
+
*/
|
|
100
|
+
async function rolePreImage(api, role) {
|
|
101
|
+
let found = null;
|
|
102
|
+
if (role._id) {
|
|
103
|
+
const byId = await api.getRoleById(role._id);
|
|
104
|
+
if (!byId) {
|
|
105
|
+
throw new Error(`Studio role '${role._id}' not found or unreadable. Mutation aborted to avoid a restore that would delete a live role.`);
|
|
106
|
+
}
|
|
107
|
+
found = byId;
|
|
108
|
+
}
|
|
109
|
+
else if (role.name && role.type && role.item) {
|
|
110
|
+
const roles = await api.listRolesStrict();
|
|
111
|
+
found = roles.find((r) => r.name === role.name && r.type === role.type && r.item === role.item) ?? null;
|
|
112
|
+
}
|
|
113
|
+
const naturalKey = found
|
|
114
|
+
? { name: found.name, type: found.type, item: found.item }
|
|
115
|
+
: { name: role.name ?? "", type: role.type ?? "", item: role.item ?? "" };
|
|
116
|
+
return {
|
|
117
|
+
existedBefore: found !== null,
|
|
118
|
+
preImage: found,
|
|
119
|
+
resourceId: found?._id ?? role._id ?? naturalKey.name,
|
|
120
|
+
naturalKey,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
/** Current assignment state for a principal, matched in `listRoleAssignments(item)`. */
|
|
124
|
+
async function assignmentPreImage(api, pr) {
|
|
125
|
+
const assignments = await api.listRoleAssignmentsStrict(pr.item);
|
|
126
|
+
const found = assignments.find((a) => a.type === pr.type && a.item === pr.item && a.role === pr.role) ?? null;
|
|
127
|
+
return {
|
|
128
|
+
existedBefore: found !== null,
|
|
129
|
+
preImage: found,
|
|
130
|
+
resourceId: `${pr.type}:${pr.item}:${pr.role}`,
|
|
131
|
+
naturalKey: { type: pr.type, item: pr.item, role: pr.role },
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* The single chokepoint: serialize a pre-image to disk BEFORE the remote mutation.
|
|
136
|
+
* Throws (via {@link captureBackup}) on any IO/serialization failure, which the handler's
|
|
137
|
+
* try/catch turns into an `isError` response — aborting the mutation.
|
|
138
|
+
*/
|
|
139
|
+
function backupBeforeMutation(action, category, pre, serverUrl) {
|
|
140
|
+
const snapshot = {
|
|
141
|
+
version: 1,
|
|
142
|
+
action,
|
|
143
|
+
category,
|
|
144
|
+
resourceId: pre.resourceId,
|
|
145
|
+
naturalKey: pre.naturalKey,
|
|
146
|
+
existedBefore: pre.existedBefore,
|
|
147
|
+
capturedAt: new Date().toISOString(),
|
|
148
|
+
serverUrl,
|
|
149
|
+
preImage: pre.preImage,
|
|
150
|
+
};
|
|
151
|
+
try {
|
|
152
|
+
(0, _backup_1.captureBackup)(snapshot);
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
throw new Error(`Backup write failed (mutation aborted): ${error.message}`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
async function capturePreImage(action, fn) {
|
|
159
|
+
try {
|
|
160
|
+
return await fn();
|
|
161
|
+
}
|
|
162
|
+
catch (error) {
|
|
163
|
+
throw new Error(`Failed to capture pre-image for ${action}: ${error.message}`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/** Block cross-tenant restore when both snapshot and current connection record a serverUrl. */
|
|
167
|
+
function assertSnapshotServerMatches(snapshot, currentServerUrl) {
|
|
168
|
+
if (snapshot.serverUrl && currentServerUrl && snapshot.serverUrl !== currentServerUrl) {
|
|
169
|
+
throw new Error(`Backup serverUrl mismatch: snapshot was captured from '${snapshot.serverUrl}' but current connection is '${currentServerUrl}'. Refusing cross-server restore.`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
/** Fetch the CURRENT state of the resource a snapshot targets — used for restore's own pre-write backup. */
|
|
173
|
+
async function currentPreImage(api, snapshot) {
|
|
174
|
+
switch (snapshot.category) {
|
|
175
|
+
case "security":
|
|
176
|
+
return securityPreImage(await loadSecurityDocument(api));
|
|
177
|
+
case "studio-role": {
|
|
178
|
+
const nk = snapshot.naturalKey;
|
|
179
|
+
if (!nk || !nk.name) {
|
|
180
|
+
throw new Error("Studio-role snapshot missing naturalKey.");
|
|
181
|
+
}
|
|
182
|
+
return rolePreImage(api, nk);
|
|
183
|
+
}
|
|
184
|
+
case "studio-assignment": {
|
|
185
|
+
const key = snapshot.naturalKey;
|
|
186
|
+
if (!key || !key.type || !key.item || !key.role) {
|
|
187
|
+
throw new Error("Studio-assignment snapshot missing naturalKey.");
|
|
188
|
+
}
|
|
189
|
+
return assignmentPreImage(api, { type: key.type, item: key.item, role: key.role });
|
|
190
|
+
}
|
|
191
|
+
default:
|
|
192
|
+
throw new Error(`Unknown backup category: ${snapshot.category}`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
89
195
|
function registerPermissionsTool(server, apiHolder) {
|
|
90
196
|
server.registerTool("funifier_permissions", {
|
|
91
197
|
title: "Funifier Permissions Manager",
|
|
92
198
|
description: "Manage Funifier permissions without mixing models. " +
|
|
93
199
|
"API access permissions are stored in the gamification security document (apps[] and roles[] scopes). " +
|
|
94
200
|
"Studio/UI permissions are stored in system roles (role collection) and assignments (principal_role). " +
|
|
95
|
-
"Use API actions for app_secret/scope/whitelist management, and Studio actions for page/api/limit permissions and role assignments."
|
|
201
|
+
"Use API actions for app_secret/scope/whitelist management, and Studio actions for page/api/limit permissions and role assignments. " +
|
|
202
|
+
"Every mutating action writes a complete pre-image snapshot under .funifier/backups/ (or FUNIFIER_BACKUP_ROOT) BEFORE the remote write; " +
|
|
203
|
+
"use list_backups to see them and restore_backup (with backup_path) to roll a change back. " +
|
|
204
|
+
"Snapshots accumulate without automatic retention — prune .funifier/backups/ manually when needed.",
|
|
96
205
|
inputSchema: {
|
|
97
206
|
action: zod_1.z
|
|
98
207
|
.enum([
|
|
@@ -108,6 +217,8 @@ function registerPermissionsTool(server, apiHolder) {
|
|
|
108
217
|
"list_studio_assignments",
|
|
109
218
|
"assign_studio_role",
|
|
110
219
|
"unassign_studio_role",
|
|
220
|
+
"list_backups",
|
|
221
|
+
"restore_backup",
|
|
111
222
|
])
|
|
112
223
|
.describe("Permission operation to execute."),
|
|
113
224
|
data: zod_1.z
|
|
@@ -130,6 +241,7 @@ function registerPermissionsTool(server, apiHolder) {
|
|
|
130
241
|
.optional()
|
|
131
242
|
.describe("Assignment principal type, if 'data' is not provided."),
|
|
132
243
|
principal_item: zod_1.z.string().optional().describe("Assignment principal id, if 'data' is not provided."),
|
|
244
|
+
backup_path: zod_1.z.string().optional().describe("Path of a snapshot file to restore, required by restore_backup."),
|
|
133
245
|
},
|
|
134
246
|
annotations: {
|
|
135
247
|
readOnlyHint: false,
|
|
@@ -137,9 +249,10 @@ function registerPermissionsTool(server, apiHolder) {
|
|
|
137
249
|
idempotentHint: false,
|
|
138
250
|
openWorldHint: true,
|
|
139
251
|
},
|
|
140
|
-
}, async ({ action, data, app_secret, name, role_id, role_type, item, principal_type, principal_item }) => {
|
|
252
|
+
}, async ({ action, data, app_secret, name, role_id, role_type, item, principal_type, principal_item, backup_path }) => {
|
|
141
253
|
try {
|
|
142
254
|
const api = apiHolder.requireClient();
|
|
255
|
+
const serverUrl = apiHolder.getConnectionInfo?.().serverUrl ?? null;
|
|
143
256
|
if (action === "list_api_apps") {
|
|
144
257
|
const security = await loadSecurityDocument(api);
|
|
145
258
|
return formatResult(`API applications (${security.apps?.length ?? 0})`, maskSecurityApplications(security.apps));
|
|
@@ -150,6 +263,7 @@ function registerPermissionsTool(server, apiHolder) {
|
|
|
150
263
|
throw new Error("API app requires 'name', 'app_secret', and 'scope'.");
|
|
151
264
|
}
|
|
152
265
|
const security = await loadSecurityDocument(api);
|
|
266
|
+
backupBeforeMutation("save_api_app", "security", securityPreImage(security), serverUrl);
|
|
153
267
|
security.apps = upsertBy(security.apps, app, (current) => current.app_secret === app.app_secret);
|
|
154
268
|
const saved = await saveSecurityDocument(api, security);
|
|
155
269
|
return formatResult("API app saved in security.apps", maskSecurityApplications(saved.apps));
|
|
@@ -157,6 +271,7 @@ function registerPermissionsTool(server, apiHolder) {
|
|
|
157
271
|
if (action === "delete_api_app") {
|
|
158
272
|
const appSecret = requireAppSecret(app_secret);
|
|
159
273
|
const security = await loadSecurityDocument(api);
|
|
274
|
+
backupBeforeMutation("delete_api_app", "security", securityPreImage(security), serverUrl);
|
|
160
275
|
security.apps = removeBy(security.apps, (current) => current.app_secret === appSecret);
|
|
161
276
|
const saved = await saveSecurityDocument(api, security);
|
|
162
277
|
return formatResult("API app removed from security.apps", maskSecurityApplications(saved.apps));
|
|
@@ -171,6 +286,7 @@ function registerPermissionsTool(server, apiHolder) {
|
|
|
171
286
|
throw new Error("Security role requires 'name', 'timeout', and 'scope'.");
|
|
172
287
|
}
|
|
173
288
|
const security = await loadSecurityDocument(api);
|
|
289
|
+
backupBeforeMutation("save_security_role", "security", securityPreImage(security), serverUrl);
|
|
174
290
|
security.roles = upsertBy(security.roles, role, (current) => current.name === role.name);
|
|
175
291
|
const saved = await saveSecurityDocument(api, security);
|
|
176
292
|
return formatResult("Security role saved in security.roles", saved.roles ?? []);
|
|
@@ -178,6 +294,7 @@ function registerPermissionsTool(server, apiHolder) {
|
|
|
178
294
|
if (action === "delete_security_role") {
|
|
179
295
|
const roleName = requireName(name);
|
|
180
296
|
const security = await loadSecurityDocument(api);
|
|
297
|
+
backupBeforeMutation("delete_security_role", "security", securityPreImage(security), serverUrl);
|
|
181
298
|
security.roles = removeBy(security.roles, (current) => current.name === roleName);
|
|
182
299
|
const saved = await saveSecurityDocument(api, security);
|
|
183
300
|
return formatResult("Security role removed from security.roles", saved.roles ?? []);
|
|
@@ -203,11 +320,13 @@ function registerPermissionsTool(server, apiHolder) {
|
|
|
203
320
|
throw new Error("Each permission requires 'type', 'object', and 'operations'.");
|
|
204
321
|
}
|
|
205
322
|
});
|
|
323
|
+
backupBeforeMutation("save_studio_role", "studio-role", await capturePreImage("save_studio_role", () => rolePreImage(api, role)), serverUrl);
|
|
206
324
|
const saved = await api.saveRole(role);
|
|
207
325
|
return formatResult("Studio role saved", saved);
|
|
208
326
|
}
|
|
209
327
|
if (action === "delete_studio_role") {
|
|
210
328
|
const id = requireRoleId(role_id);
|
|
329
|
+
backupBeforeMutation("delete_studio_role", "studio-role", await capturePreImage("delete_studio_role", () => rolePreImage(api, { _id: id })), serverUrl);
|
|
211
330
|
const result = await api.deleteRole(id);
|
|
212
331
|
return formatResult("Studio role deleted", result);
|
|
213
332
|
}
|
|
@@ -217,14 +336,31 @@ function registerPermissionsTool(server, apiHolder) {
|
|
|
217
336
|
}
|
|
218
337
|
if (action === "assign_studio_role") {
|
|
219
338
|
const assignment = parsePrincipalRole(data, principal_type, principal_item, role_id);
|
|
339
|
+
backupBeforeMutation("assign_studio_role", "studio-assignment", await capturePreImage("assign_studio_role", () => assignmentPreImage(api, assignment)), serverUrl);
|
|
220
340
|
const saved = await api.assignRole(assignment);
|
|
221
341
|
return formatResult("Studio role assigned", saved);
|
|
222
342
|
}
|
|
223
343
|
if (action === "unassign_studio_role") {
|
|
224
344
|
const assignment = parsePrincipalRole(data, principal_type, principal_item, role_id);
|
|
345
|
+
backupBeforeMutation("unassign_studio_role", "studio-assignment", await capturePreImage("unassign_studio_role", () => assignmentPreImage(api, assignment)), serverUrl);
|
|
225
346
|
const result = await api.unassignRole(assignment);
|
|
226
347
|
return formatResult("Studio role unassigned", result);
|
|
227
348
|
}
|
|
349
|
+
if (action === "list_backups") {
|
|
350
|
+
const snapshots = (0, _backup_1.listSnapshots)();
|
|
351
|
+
return formatResult(`Backups (${snapshots.length})`, snapshots);
|
|
352
|
+
}
|
|
353
|
+
if (action === "restore_backup") {
|
|
354
|
+
if (!backup_path)
|
|
355
|
+
throw new Error("'backup_path' is required for restore_backup.");
|
|
356
|
+
// Read + validate first: a missing/corrupt/invalid file throws before any remote write.
|
|
357
|
+
const snapshot = (0, _backup_1.readSnapshot)((0, _backup_1.resolveBackupPath)(backup_path));
|
|
358
|
+
assertSnapshotServerMatches(snapshot, serverUrl);
|
|
359
|
+
// Restore is itself a critical mutation, so it takes its own pre-write backup of current state.
|
|
360
|
+
backupBeforeMutation("restore_backup", snapshot.category, await capturePreImage("restore_backup", () => currentPreImage(api, snapshot)), serverUrl);
|
|
361
|
+
const result = await (0, _backup_1.applySnapshot)(api, snapshot);
|
|
362
|
+
return formatResult(`Backup restored from ${backup_path}`, result);
|
|
363
|
+
}
|
|
228
364
|
return {
|
|
229
365
|
content: [{ type: "text", text: `Unknown action: ${action}` }],
|
|
230
366
|
isError: true,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"permissions.js","sourceRoot":"","sources":["../../../src/mcp/tools/permissions.ts"],"names":[],"mappings":";;AAuHA,0DAwKC;AA/RD,6BAAwB;AA0BxB,SAAS,eAAe,CAAI,KAAyB,EAAE,KAAa;IAClE,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,IAAI,KAAK,iCAAiC,CAAC,CAAC;IAC9D,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACjC,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACnE,MAAM,IAAI,KAAK,CAAC,IAAI,KAAK,0BAA0B,CAAC,CAAC;IACvD,CAAC;IACD,OAAO,MAAW,CAAC;AACrB,CAAC;AAED,SAAS,kBAAkB,CAAC,IAAwB,EAAE,aAAsB,EAAE,aAAsB,EAAE,MAAe;IACnH,IAAI,IAAI;QAAE,OAAO,eAAe,CAAgB,IAAI,EAAE,MAAM,CAAC,CAAC;IAE9D,IAAI,CAAC,aAAa,IAAI,CAAC,aAAa,IAAI,CAAC,MAAM,EAAE,CAAC;QAChD,MAAM,IAAI,KAAK,CAAC,6EAA6E,CAAC,CAAC;IACjG,CAAC;IAED,IAAI,CAAC,CAAC,MAAM,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;QACjE,MAAM,IAAI,KAAK,CAAC,+DAA+D,CAAC,CAAC;IACnF,CAAC;IAED,OAAO;QACL,IAAI,EAAE,aAAsC;QAC5C,IAAI,EAAE,aAAa;QACnB,IAAI,EAAE,MAAM;KACb,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,MAA0B;IAC/C,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;IACvE,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,gBAAgB,CAAC,SAA6B;IACrD,IAAI,CAAC,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;IAC7E,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,WAAW,CAAC,IAAwB;IAC3C,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;IAClE,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,YAAY,CAAC,KAAa,EAAE,KAAc;IACjD,OAAO;QACL,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAe;gBACrB,IAAI,EAAE,GAAG,KAAK,QAAQ,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE;aACvD;SACF;KACF,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CAAC,MAAc;IAChC,IAAI,MAAM,CAAC,MAAM,IAAI,CAAC;QAAE,OAAO,UAAU,CAAC;IAC1C,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACrD,CAAC;AAED,SAAS,wBAAwB,CAAC,IAAuC;IACvE,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QAChC,GAAG,GAAG;QACN,UAAU,EAAE,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC;KACvC,CAAC,CAAC,CAAC;AACN,CAAC;AAED,KAAK,UAAU,oBAAoB,CAAC,GAAQ;IAC1C,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,eAAe,CAAC,UAAU,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;IAC9E,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC3D,IAAI,CAAC,QAAQ,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;IAC3E,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,KAAK,UAAU,oBAAoB,CAAC,GAAQ,EAAE,QAA0B;IACtE,OAAO,GAAG,CAAC,cAAc,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;AAClD,CAAC;AAED,SAAS,QAAQ,CAAI,KAAsB,EAAE,SAAY,EAAE,OAA6B;IACtF,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACpD,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IACtC,IAAI,KAAK,IAAI,CAAC;QAAE,IAAI,CAAC,KAAK,CAAC,GAAG,SAAS,CAAC;;QACnC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC1B,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,QAAQ,CAAI,KAAsB,EAAE,OAA6B;IACxE,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;AAC9E,CAAC;AAED,SAAgB,uBAAuB,CAAC,MAAiB,EAAE,SAAoB;IAC7E,MAAM,CAAC,YAAY,CACjB,sBAAsB,EACtB;QACE,KAAK,EAAE,8BAA8B;QACrC,WAAW,EACT,qDAAqD;YACrD,uGAAuG;YACvG,uGAAuG;YACvG,oIAAoI;QACtI,WAAW,EAAE;YACX,MAAM,EAAE,OAAC;iBACN,IAAI,CAAC;gBACJ,eAAe;gBACf,cAAc;gBACd,gBAAgB;gBAChB,qBAAqB;gBACrB,oBAAoB;gBACpB,sBAAsB;gBACtB,mBAAmB;gBACnB,kBAAkB;gBAClB,oBAAoB;gBACpB,yBAAyB;gBACzB,oBAAoB;gBACpB,sBAAsB;aACvB,CAAC;iBACD,QAAQ,CAAC,kCAAkC,CAAC;YAC/C,IAAI,EAAE,OAAC;iBACJ,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CACP,gFAAgF;gBAC9E,8DAA8D;gBAC9D,8IAA8I;gBAC9I,+GAA+G,CAClH;YACH,UAAU,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,4CAA4C,CAAC;YACxF,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,kDAAkD,CAAC;YACxF,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,mEAAmE,CAAC;YAC5G,SAAS,EAAE,OAAC;iBACT,IAAI,CAAC,CAAC,QAAQ,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC;iBAC3C,QAAQ,EAAE;iBACV,QAAQ,CAAC,wCAAwC,CAAC;YACrD,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,qEAAqE,CAAC;YAC3G,cAAc,EAAE,OAAC;iBACd,IAAI,CAAC,CAAC,MAAM,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC;iBACzC,QAAQ,EAAE;iBACV,QAAQ,CAAC,uDAAuD,CAAC;YACpE,cAAc,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,qDAAqD,CAAC;SACtG;QACD,WAAW,EAAE;YACX,YAAY,EAAE,KAAK;YACnB,eAAe,EAAE,IAAI;YACrB,cAAc,EAAE,KAAK;YACrB,aAAa,EAAE,IAAI;SACpB;KACF,EACD,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,cAAc,EAAE,cAAc,EAAE,EAAE,EAAE;QACrG,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,SAAS,CAAC,aAAa,EAAE,CAAC;YAEtC,IAAI,MAAM,KAAK,eAAe,EAAE,CAAC;gBAC/B,MAAM,QAAQ,GAAG,MAAM,oBAAoB,CAAC,GAAG,CAAC,CAAC;gBACjD,OAAO,YAAY,CAAC,qBAAqB,QAAQ,CAAC,IAAI,EAAE,MAAM,IAAI,CAAC,GAAG,EAAE,wBAAwB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;YACnH,CAAC;YAED,IAAI,MAAM,KAAK,cAAc,EAAE,CAAC;gBAC9B,MAAM,GAAG,GAAG,eAAe,CAAsB,IAAI,EAAE,MAAM,CAAC,CAAC;gBAC/D,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,UAAU,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;oBAC/C,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;gBACzE,CAAC;gBACD,MAAM,QAAQ,GAAG,MAAM,oBAAoB,CAAC,GAAG,CAAC,CAAC;gBACjD,QAAQ,CAAC,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,UAAU,KAAK,GAAG,CAAC,UAAU,CAAC,CAAC;gBACjG,MAAM,KAAK,GAAG,MAAM,oBAAoB,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;gBACxD,OAAO,YAAY,CAAC,gCAAgC,EAAE,wBAAwB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;YAC9F,CAAC;YAED,IAAI,MAAM,KAAK,gBAAgB,EAAE,CAAC;gBAChC,MAAM,SAAS,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAC;gBAC/C,MAAM,QAAQ,GAAG,MAAM,oBAAoB,CAAC,GAAG,CAAC,CAAC;gBACjD,QAAQ,CAAC,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC;gBACvF,MAAM,KAAK,GAAG,MAAM,oBAAoB,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;gBACxD,OAAO,YAAY,CAAC,oCAAoC,EAAE,wBAAwB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;YAClG,CAAC;YAED,IAAI,MAAM,KAAK,qBAAqB,EAAE,CAAC;gBACrC,MAAM,QAAQ,GAAG,MAAM,oBAAoB,CAAC,GAAG,CAAC,CAAC;gBACjD,OAAO,YAAY,CAAC,mBAAmB,QAAQ,CAAC,KAAK,EAAE,MAAM,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;YAC/F,CAAC;YAED,IAAI,MAAM,KAAK,oBAAoB,EAAE,CAAC;gBACpC,MAAM,IAAI,GAAG,eAAe,CAAe,IAAI,EAAE,MAAM,CAAC,CAAC;gBACzD,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;oBAC/C,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC;gBAC5E,CAAC;gBACD,MAAM,QAAQ,GAAG,MAAM,oBAAoB,CAAC,GAAG,CAAC,CAAC;gBACjD,QAAQ,CAAC,KAAK,GAAG,QAAQ,CAAC,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,CAAC,CAAC;gBACzF,MAAM,KAAK,GAAG,MAAM,oBAAoB,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;gBACxD,OAAO,YAAY,CAAC,uCAAuC,EAAE,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;YAClF,CAAC;YAED,IAAI,MAAM,KAAK,sBAAsB,EAAE,CAAC;gBACtC,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;gBACnC,MAAM,QAAQ,GAAG,MAAM,oBAAoB,CAAC,GAAG,CAAC,CAAC;gBACjD,QAAQ,CAAC,KAAK,GAAG,QAAQ,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC;gBAClF,MAAM,KAAK,GAAG,MAAM,oBAAoB,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;gBACxD,OAAO,YAAY,CAAC,2CAA2C,EAAE,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;YACtF,CAAC;YAED,IAAI,MAAM,KAAK,mBAAmB,EAAE,CAAC;gBACnC,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,SAAS,EAAE,CAAC;gBACpC,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,IAAU,EAAE,EAAE;oBAC3C,IAAI,SAAS,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS;wBAAE,OAAO,KAAK,CAAC;oBACvD,IAAI,IAAI,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI;wBAAE,OAAO,KAAK,CAAC;oBAC7C,OAAO,IAAI,CAAC;gBACd,CAAC,CAAC,CAAC;gBACH,OAAO,YAAY,CAAC,iBAAiB,QAAQ,CAAC,MAAM,GAAG,EAAE,QAAQ,CAAC,CAAC;YACrE,CAAC;YAED,IAAI,MAAM,KAAK,kBAAkB,EAAE,CAAC;gBAClC,MAAM,IAAI,GAAG,eAAe,CAAO,IAAI,EAAE,MAAM,CAAC,CAAC;gBACjD,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;oBAC/E,MAAM,IAAI,KAAK,CAAC,uEAAuE,CAAC,CAAC;gBAC3F,CAAC;gBACD,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,UAAsB,EAAE,EAAE;oBAClD,IAAI,CAAC,UAAU,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC;wBACrE,MAAM,IAAI,KAAK,CAAC,8DAA8D,CAAC,CAAC;oBAClF,CAAC;gBACH,CAAC,CAAC,CAAC;gBACH,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;gBACvC,OAAO,YAAY,CAAC,mBAAmB,EAAE,KAAK,CAAC,CAAC;YAClD,CAAC;YAED,IAAI,MAAM,KAAK,oBAAoB,EAAE,CAAC;gBACpC,MAAM,EAAE,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;gBAClC,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;gBACxC,OAAO,YAAY,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;YACrD,CAAC;YAED,IAAI,MAAM,KAAK,yBAAyB,EAAE,CAAC;gBACzC,MAAM,WAAW,GAAG,MAAM,GAAG,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC;gBACxD,OAAO,YAAY,CAAC,4BAA4B,WAAW,CAAC,MAAM,GAAG,EAAE,WAAW,CAAC,CAAC;YACtF,CAAC;YAED,IAAI,MAAM,KAAK,oBAAoB,EAAE,CAAC;gBACpC,MAAM,UAAU,GAAG,kBAAkB,CAAC,IAAI,EAAE,cAAc,EAAE,cAAc,EAAE,OAAO,CAAC,CAAC;gBACrF,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;gBAC/C,OAAO,YAAY,CAAC,sBAAsB,EAAE,KAAK,CAAC,CAAC;YACrD,CAAC;YAED,IAAI,MAAM,KAAK,sBAAsB,EAAE,CAAC;gBACtC,MAAM,UAAU,GAAG,kBAAkB,CAAC,IAAI,EAAE,cAAc,EAAE,cAAc,EAAE,OAAO,CAAC,CAAC;gBACrF,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC;gBAClD,OAAO,YAAY,CAAC,wBAAwB,EAAE,MAAM,CAAC,CAAC;YACxD,CAAC;YAED,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,mBAAmB,MAAM,EAAE,EAAE,CAAC;gBACvE,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,iCAAiC,MAAM,KAAK,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;gBACvG,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
1
|
+
{"version":3,"file":"permissions.js","sourceRoot":"","sources":["../../../src/mcp/tools/permissions.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,31 +1,67 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
const vitest_1 = require("vitest");
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const os_1 = __importDefault(require("os"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
4
10
|
const permissions_1 = require("./permissions");
|
|
11
|
+
const _backup_1 = require("./_backup");
|
|
12
|
+
// Every mutating action now writes a snapshot to backupRoot(); redirect it to a temp dir
|
|
13
|
+
// (via the FUNIFIER_BACKUP_ROOT seam) so tests never touch the real working tree.
|
|
14
|
+
let backupDir;
|
|
15
|
+
(0, vitest_1.beforeEach)(() => {
|
|
16
|
+
backupDir = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), "funifier-perm-test-"));
|
|
17
|
+
process.env.FUNIFIER_BACKUP_ROOT = backupDir;
|
|
18
|
+
});
|
|
19
|
+
(0, vitest_1.afterEach)(() => {
|
|
20
|
+
delete process.env.FUNIFIER_BACKUP_ROOT;
|
|
21
|
+
fs_1.default.rmSync(backupDir, { recursive: true, force: true });
|
|
22
|
+
});
|
|
23
|
+
function readNewestSnapshot() {
|
|
24
|
+
const items = (0, _backup_1.listSnapshots)(backupDir);
|
|
25
|
+
if (items.length === 0)
|
|
26
|
+
throw new Error("no snapshot written");
|
|
27
|
+
return JSON.parse(fs_1.default.readFileSync(items[0].path, "utf8"));
|
|
28
|
+
}
|
|
5
29
|
const SECURITY = {
|
|
6
30
|
_id: "game1",
|
|
7
31
|
apps: [{ name: "Default", app_secret: "old-secret", scope: "read_all" }],
|
|
8
32
|
roles: [{ name: "player", timeout: "1d", scope: "read_all,write_actionlog" }],
|
|
9
33
|
};
|
|
10
34
|
function fakeApi(overrides = {}) {
|
|
35
|
+
const roles = [
|
|
36
|
+
{ _id: "r1", name: "Admin", type: "system", item: "system", permissions: [] },
|
|
37
|
+
{ _id: "r2", name: "Game Editor", type: "gamification", item: "game1", permissions: [] },
|
|
38
|
+
];
|
|
39
|
+
const assignments = [{ type: "user", item: "u1", role: "r1" }];
|
|
11
40
|
return {
|
|
12
41
|
queryCollection: vitest_1.vi.fn().mockResolvedValue([structuredClone(SECURITY)]),
|
|
13
42
|
updateDocument: vitest_1.vi.fn().mockImplementation((_collection, doc) => Promise.resolve(doc)),
|
|
14
|
-
listRoles: vitest_1.vi.fn().mockResolvedValue(
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
]),
|
|
43
|
+
listRoles: vitest_1.vi.fn().mockResolvedValue(roles),
|
|
44
|
+
listRolesStrict: vitest_1.vi.fn().mockResolvedValue(roles),
|
|
45
|
+
getRoleById: vitest_1.vi.fn().mockResolvedValue({ _id: "r1", name: "Admin", type: "system", item: "system", permissions: [] }),
|
|
18
46
|
saveRole: vitest_1.vi.fn().mockImplementation((role) => Promise.resolve({ ...role, _id: role._id ?? "new-role" })),
|
|
19
47
|
deleteRole: vitest_1.vi.fn().mockResolvedValue({ ok: 1 }),
|
|
20
|
-
listRoleAssignments: vitest_1.vi.fn().mockResolvedValue(
|
|
48
|
+
listRoleAssignments: vitest_1.vi.fn().mockResolvedValue(assignments),
|
|
49
|
+
listRoleAssignmentsStrict: vitest_1.vi.fn().mockResolvedValue(assignments),
|
|
21
50
|
assignRole: vitest_1.vi.fn().mockImplementation((payload) => Promise.resolve(payload)),
|
|
22
51
|
unassignRole: vitest_1.vi.fn().mockResolvedValue({ ok: 1 }),
|
|
23
52
|
...overrides,
|
|
24
53
|
};
|
|
25
54
|
}
|
|
26
|
-
function makeInvoke(overrides = {}) {
|
|
55
|
+
function makeInvoke(overrides = {}, connection = { serverUrl: "https://test.funifier.com" }) {
|
|
27
56
|
const api = fakeApi(overrides);
|
|
28
|
-
const holder = {
|
|
57
|
+
const holder = {
|
|
58
|
+
requireClient: () => api,
|
|
59
|
+
getConnectionInfo: () => ({
|
|
60
|
+
connected: true,
|
|
61
|
+
serverUrl: connection.serverUrl ?? null,
|
|
62
|
+
name: null,
|
|
63
|
+
}),
|
|
64
|
+
};
|
|
29
65
|
let handler;
|
|
30
66
|
const server = {
|
|
31
67
|
registerTool: (_name, _config, h) => { handler = h; },
|
|
@@ -96,4 +132,224 @@ function makeInvoke(overrides = {}) {
|
|
|
96
132
|
(0, vitest_1.expect)(result.content[0].text).toContain("Error in funifier_permissions");
|
|
97
133
|
});
|
|
98
134
|
});
|
|
135
|
+
(0, vitest_1.describe)("funifier_permissions native pre-write backup (no LLM in the loop)", () => {
|
|
136
|
+
(0, vitest_1.it)("writes a snapshot of the prior security doc BEFORE the mutation fires", async () => {
|
|
137
|
+
// The mutation mock records how many snapshots exist at the moment it is invoked.
|
|
138
|
+
let snapshotsWhenMutated = -1;
|
|
139
|
+
const { invoke, api } = makeInvoke({
|
|
140
|
+
updateDocument: vitest_1.vi.fn().mockImplementation((_collection, doc) => {
|
|
141
|
+
snapshotsWhenMutated = (0, _backup_1.listSnapshots)(backupDir).length;
|
|
142
|
+
return Promise.resolve(doc);
|
|
143
|
+
}),
|
|
144
|
+
});
|
|
145
|
+
// A genuinely new app, so the mutated doc (2 apps) differs from the prior doc (1 app).
|
|
146
|
+
const result = await invoke({
|
|
147
|
+
action: "save_api_app",
|
|
148
|
+
data: JSON.stringify({ name: "New App", app_secret: "brand-new", scope: "read_all" }),
|
|
149
|
+
});
|
|
150
|
+
(0, vitest_1.expect)(result.isError).toBeUndefined();
|
|
151
|
+
(0, vitest_1.expect)(api.updateDocument).toHaveBeenCalled();
|
|
152
|
+
(0, vitest_1.expect)(snapshotsWhenMutated).toBe(1); // backup existed before updateDocument ran
|
|
153
|
+
const snap = readNewestSnapshot();
|
|
154
|
+
(0, vitest_1.expect)(snap.category).toBe("security");
|
|
155
|
+
(0, vitest_1.expect)(snap.existedBefore).toBe(true);
|
|
156
|
+
(0, vitest_1.expect)(snap.preImage).toEqual(SECURITY); // whole PRIOR doc, not the mutated 2-app version
|
|
157
|
+
});
|
|
158
|
+
(0, vitest_1.it)("aborts the mutation and returns isError when the backup write fails", async () => {
|
|
159
|
+
// Point the backup root at a path blocked by a file → mkdir for the category dir throws.
|
|
160
|
+
const blocker = path_1.default.join(backupDir, "blocker");
|
|
161
|
+
fs_1.default.writeFileSync(blocker, "not-a-directory");
|
|
162
|
+
process.env.FUNIFIER_BACKUP_ROOT = path_1.default.join(blocker, "nested");
|
|
163
|
+
const { invoke, api } = makeInvoke();
|
|
164
|
+
const result = await invoke({
|
|
165
|
+
action: "save_api_app",
|
|
166
|
+
data: JSON.stringify({ name: "Default", app_secret: "old-secret", scope: "read_all" }),
|
|
167
|
+
});
|
|
168
|
+
(0, vitest_1.expect)(result.isError).toBe(true);
|
|
169
|
+
(0, vitest_1.expect)(result.content[0].text).toContain("Backup write failed (mutation aborted)");
|
|
170
|
+
(0, vitest_1.expect)(api.updateDocument).not.toHaveBeenCalled(); // the literal "native, not LLM" guarantee
|
|
171
|
+
});
|
|
172
|
+
(0, vitest_1.it)("records existedBefore=false / preImage=null when creating a brand-new studio role", async () => {
|
|
173
|
+
const { invoke, api } = makeInvoke();
|
|
174
|
+
const role = {
|
|
175
|
+
name: "Brand New",
|
|
176
|
+
type: "gamification",
|
|
177
|
+
item: "game1",
|
|
178
|
+
permissions: [{ type: "page", object: "/x", operations: { read: true } }],
|
|
179
|
+
};
|
|
180
|
+
const result = await invoke({ action: "save_studio_role", data: JSON.stringify(role) });
|
|
181
|
+
(0, vitest_1.expect)(result.isError).toBeUndefined();
|
|
182
|
+
(0, vitest_1.expect)(api.saveRole).toHaveBeenCalledWith(role);
|
|
183
|
+
const snap = readNewestSnapshot(); // built by a real captureBackup, not a hand-faked fixture
|
|
184
|
+
(0, vitest_1.expect)(snap.category).toBe("studio-role");
|
|
185
|
+
(0, vitest_1.expect)(snap.existedBefore).toBe(false);
|
|
186
|
+
(0, vitest_1.expect)(snap.preImage).toBeNull();
|
|
187
|
+
(0, vitest_1.expect)(snap.naturalKey).toEqual({ name: "Brand New", type: "gamification", item: "game1" });
|
|
188
|
+
});
|
|
189
|
+
vitest_1.it.each([
|
|
190
|
+
["save_api_app", { data: JSON.stringify({ name: "X", app_secret: "s", scope: "read_all" }) }],
|
|
191
|
+
["delete_api_app", { app_secret: "old-secret" }],
|
|
192
|
+
["save_security_role", { data: JSON.stringify({ name: "X", timeout: "1d", scope: "read_all" }) }],
|
|
193
|
+
["delete_security_role", { name: "player" }],
|
|
194
|
+
["save_studio_role", { data: JSON.stringify({ name: "X", type: "system", item: "system", permissions: [] }) }],
|
|
195
|
+
["delete_studio_role", { role_id: "r1" }],
|
|
196
|
+
["assign_studio_role", { principal_type: "user", principal_item: "u1", role_id: "r1" }],
|
|
197
|
+
["unassign_studio_role", { principal_type: "user", principal_item: "u1", role_id: "r1" }],
|
|
198
|
+
])("%s writes exactly one pre-write snapshot", async (action, args) => {
|
|
199
|
+
const { invoke } = makeInvoke();
|
|
200
|
+
const result = await invoke({ action, ...args });
|
|
201
|
+
(0, vitest_1.expect)(result.isError).toBeUndefined();
|
|
202
|
+
(0, vitest_1.expect)((0, _backup_1.listSnapshots)(backupDir).length).toBe(1);
|
|
203
|
+
});
|
|
204
|
+
(0, vitest_1.it)("restore_backup reapplies a security snapshot via updateDocument", async () => {
|
|
205
|
+
// 1. A real mutation captures the prior security doc.
|
|
206
|
+
const writer = makeInvoke();
|
|
207
|
+
await writer.invoke({
|
|
208
|
+
action: "save_api_app",
|
|
209
|
+
data: JSON.stringify({ name: "Default", app_secret: "old-secret", scope: "read_all" }),
|
|
210
|
+
});
|
|
211
|
+
(0, vitest_1.expect)((0, _backup_1.listSnapshots)(backupDir).length).toBe(1);
|
|
212
|
+
const backupPath = (0, _backup_1.listSnapshots)(backupDir)[0].path;
|
|
213
|
+
// 2. A fresh handler restores it — restore writes its own pre-write backup (BKP-11).
|
|
214
|
+
const { invoke, api } = makeInvoke();
|
|
215
|
+
const result = await invoke({ action: "restore_backup", backup_path: backupPath });
|
|
216
|
+
(0, vitest_1.expect)(result.isError).toBeUndefined();
|
|
217
|
+
(0, vitest_1.expect)(api.updateDocument).toHaveBeenCalledWith("security", vitest_1.expect.objectContaining({ _id: "game1" }));
|
|
218
|
+
(0, vitest_1.expect)((0, _backup_1.listSnapshots)(backupDir).length).toBe(2);
|
|
219
|
+
});
|
|
220
|
+
(0, vitest_1.it)("restore_backup rejects cross-server snapshots when serverUrl differs", async () => {
|
|
221
|
+
const writer = makeInvoke({}, { serverUrl: "https://tenant-a.funifier.com" });
|
|
222
|
+
await writer.invoke({
|
|
223
|
+
action: "save_api_app",
|
|
224
|
+
data: JSON.stringify({ name: "Default", app_secret: "old-secret", scope: "read_all" }),
|
|
225
|
+
});
|
|
226
|
+
const backupPath = (0, _backup_1.listSnapshots)(backupDir)[0].path;
|
|
227
|
+
const { invoke, api } = makeInvoke({}, { serverUrl: "https://tenant-b.funifier.com" });
|
|
228
|
+
const result = await invoke({ action: "restore_backup", backup_path: backupPath });
|
|
229
|
+
(0, vitest_1.expect)(result.isError).toBe(true);
|
|
230
|
+
(0, vitest_1.expect)(result.content[0].text).toMatch(/serverUrl mismatch/i);
|
|
231
|
+
(0, vitest_1.expect)(api.updateDocument).not.toHaveBeenCalled();
|
|
232
|
+
});
|
|
233
|
+
(0, vitest_1.it)("delete_studio_role aborts when getRoleById fails to read the role", async () => {
|
|
234
|
+
const { invoke, api } = makeInvoke({
|
|
235
|
+
getRoleById: vitest_1.vi.fn().mockResolvedValue(undefined),
|
|
236
|
+
});
|
|
237
|
+
const result = await invoke({ action: "delete_studio_role", role_id: "r1" });
|
|
238
|
+
(0, vitest_1.expect)(result.isError).toBe(true);
|
|
239
|
+
(0, vitest_1.expect)(result.content[0].text).toContain("not found or unreadable");
|
|
240
|
+
(0, vitest_1.expect)(api.deleteRole).not.toHaveBeenCalled();
|
|
241
|
+
(0, vitest_1.expect)((0, _backup_1.listSnapshots)(backupDir).length).toBe(0);
|
|
242
|
+
});
|
|
243
|
+
(0, vitest_1.it)("save_studio_role aborts when listRolesStrict fails (avoids false absent snapshot)", async () => {
|
|
244
|
+
const { invoke, api } = makeInvoke({
|
|
245
|
+
listRolesStrict: vitest_1.vi.fn().mockRejectedValue(new Error("network down")),
|
|
246
|
+
});
|
|
247
|
+
const result = await invoke({
|
|
248
|
+
action: "save_studio_role",
|
|
249
|
+
data: JSON.stringify({
|
|
250
|
+
name: "Editor",
|
|
251
|
+
type: "gamification",
|
|
252
|
+
item: "game1",
|
|
253
|
+
permissions: [{ type: "page", object: "/x", operations: { read: true } }],
|
|
254
|
+
}),
|
|
255
|
+
});
|
|
256
|
+
(0, vitest_1.expect)(result.isError).toBe(true);
|
|
257
|
+
(0, vitest_1.expect)(result.content[0].text).toContain("Failed to capture pre-image");
|
|
258
|
+
(0, vitest_1.expect)(api.saveRole).not.toHaveBeenCalled();
|
|
259
|
+
(0, vitest_1.expect)((0, _backup_1.listSnapshots)(backupDir).length).toBe(0);
|
|
260
|
+
});
|
|
261
|
+
(0, vitest_1.it)("assign_studio_role aborts when listRoleAssignmentsStrict fails (avoids false absent snapshot)", async () => {
|
|
262
|
+
const { invoke, api } = makeInvoke({
|
|
263
|
+
listRoleAssignmentsStrict: vitest_1.vi.fn().mockRejectedValue(new Error("network down")),
|
|
264
|
+
});
|
|
265
|
+
const result = await invoke({
|
|
266
|
+
action: "assign_studio_role",
|
|
267
|
+
principal_type: "user",
|
|
268
|
+
principal_item: "u1",
|
|
269
|
+
role_id: "r1",
|
|
270
|
+
});
|
|
271
|
+
(0, vitest_1.expect)(result.isError).toBe(true);
|
|
272
|
+
(0, vitest_1.expect)(result.content[0].text).toContain("Failed to capture pre-image");
|
|
273
|
+
(0, vitest_1.expect)(api.assignRole).not.toHaveBeenCalled();
|
|
274
|
+
(0, vitest_1.expect)((0, _backup_1.listSnapshots)(backupDir).length).toBe(0);
|
|
275
|
+
});
|
|
276
|
+
(0, vitest_1.it)("restore_backup of an absent studio role resolves the _id via natural key and deletes it", async () => {
|
|
277
|
+
// 1. Create-path snapshot from a real save of a role absent in listRoles → existedBefore=false.
|
|
278
|
+
const writer = makeInvoke();
|
|
279
|
+
await writer.invoke({
|
|
280
|
+
action: "save_studio_role",
|
|
281
|
+
data: JSON.stringify({
|
|
282
|
+
name: "Brand New",
|
|
283
|
+
type: "gamification",
|
|
284
|
+
item: "game1",
|
|
285
|
+
permissions: [{ type: "page", object: "/x", operations: { read: true } }],
|
|
286
|
+
}),
|
|
287
|
+
});
|
|
288
|
+
const backupPath = (0, _backup_1.listSnapshots)(backupDir)[0].path;
|
|
289
|
+
// 2. At restore time the role now exists with a server-assigned _id.
|
|
290
|
+
const { invoke, api } = makeInvoke({
|
|
291
|
+
listRoles: vitest_1.vi.fn().mockResolvedValue([
|
|
292
|
+
{ _id: "created-id", name: "Brand New", type: "gamification", item: "game1", permissions: [] },
|
|
293
|
+
]),
|
|
294
|
+
});
|
|
295
|
+
const result = await invoke({ action: "restore_backup", backup_path: backupPath });
|
|
296
|
+
(0, vitest_1.expect)(result.isError).toBeUndefined();
|
|
297
|
+
(0, vitest_1.expect)(api.deleteRole).toHaveBeenCalledWith("created-id");
|
|
298
|
+
});
|
|
299
|
+
(0, vitest_1.it)("restore_backup with a missing path errors and performs no remote write", async () => {
|
|
300
|
+
const { invoke, api } = makeInvoke();
|
|
301
|
+
const result = await invoke({ action: "restore_backup", backup_path: path_1.default.join(backupDir, "missing.json") });
|
|
302
|
+
(0, vitest_1.expect)(result.isError).toBe(true);
|
|
303
|
+
(0, vitest_1.expect)(api.updateDocument).not.toHaveBeenCalled();
|
|
304
|
+
(0, vitest_1.expect)(api.deleteRole).not.toHaveBeenCalled();
|
|
305
|
+
});
|
|
306
|
+
(0, vitest_1.it)("restore_backup rejects path traversal outside the backup root", async () => {
|
|
307
|
+
const outside = path_1.default.join(backupDir, "..", "outside-backup.json");
|
|
308
|
+
fs_1.default.writeFileSync(outside, JSON.stringify({
|
|
309
|
+
version: 1,
|
|
310
|
+
action: "save_api_app",
|
|
311
|
+
category: "security",
|
|
312
|
+
resourceId: "game1",
|
|
313
|
+
existedBefore: true,
|
|
314
|
+
capturedAt: "2026-05-28T14:31:02.123Z",
|
|
315
|
+
serverUrl: null,
|
|
316
|
+
preImage: SECURITY,
|
|
317
|
+
}));
|
|
318
|
+
const { invoke, api } = makeInvoke();
|
|
319
|
+
const result = await invoke({ action: "restore_backup", backup_path: outside });
|
|
320
|
+
(0, vitest_1.expect)(result.isError).toBe(true);
|
|
321
|
+
(0, vitest_1.expect)(result.content[0].text).toMatch(/must be within/i);
|
|
322
|
+
(0, vitest_1.expect)(api.updateDocument).not.toHaveBeenCalled();
|
|
323
|
+
fs_1.default.rmSync(outside, { force: true });
|
|
324
|
+
});
|
|
325
|
+
(0, vitest_1.it)("restore_backup errors when a studio-role snapshot lacks naturalKey", async () => {
|
|
326
|
+
const badPath = path_1.default.join(backupDir, "studio-role", "missing-key.json");
|
|
327
|
+
fs_1.default.mkdirSync(path_1.default.dirname(badPath), { recursive: true });
|
|
328
|
+
fs_1.default.writeFileSync(badPath, JSON.stringify({
|
|
329
|
+
version: 1,
|
|
330
|
+
action: "save_studio_role",
|
|
331
|
+
category: "studio-role",
|
|
332
|
+
resourceId: "r1",
|
|
333
|
+
existedBefore: false,
|
|
334
|
+
capturedAt: "2026-05-28T14:31:02.123Z",
|
|
335
|
+
serverUrl: null,
|
|
336
|
+
preImage: null,
|
|
337
|
+
}));
|
|
338
|
+
const { invoke, api } = makeInvoke();
|
|
339
|
+
const result = await invoke({ action: "restore_backup", backup_path: badPath });
|
|
340
|
+
(0, vitest_1.expect)(result.isError).toBe(true);
|
|
341
|
+
(0, vitest_1.expect)(result.content[0].text).toContain("Studio-role snapshot missing naturalKey");
|
|
342
|
+
(0, vitest_1.expect)(api.saveRole).not.toHaveBeenCalled();
|
|
343
|
+
(0, vitest_1.expect)(api.deleteRole).not.toHaveBeenCalled();
|
|
344
|
+
});
|
|
345
|
+
(0, vitest_1.it)("list_backups returns captured snapshots newest-first", async () => {
|
|
346
|
+
const writer = makeInvoke();
|
|
347
|
+
await writer.invoke({ action: "delete_security_role", name: "player" });
|
|
348
|
+
const { invoke } = makeInvoke();
|
|
349
|
+
const result = await invoke({ action: "list_backups" });
|
|
350
|
+
(0, vitest_1.expect)(result.isError).toBeUndefined();
|
|
351
|
+
(0, vitest_1.expect)(result.content[0].text).toContain("Backups (1)");
|
|
352
|
+
(0, vitest_1.expect)(result.content[0].text).toContain("security");
|
|
353
|
+
});
|
|
354
|
+
});
|
|
99
355
|
//# sourceMappingURL=permissions.test.js.map
|