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
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal backup chokepoint for `funifier_permissions`.
|
|
3
|
+
*
|
|
4
|
+
* Every mutating permission branch hands a complete pre-image {@link BackupSnapshot}
|
|
5
|
+
* to {@link captureBackup} BEFORE issuing its remote write. If the write to disk
|
|
6
|
+
* throws, the caller's try/catch aborts the mutation — that is the deterministic,
|
|
7
|
+
* LLM-independent "back up first" guarantee. Restore is the inverse: read a snapshot,
|
|
8
|
+
* then {@link applySnapshot} reapplies the captured state (or removes a resource that
|
|
9
|
+
* did not exist before).
|
|
10
|
+
*/
|
|
11
|
+
export type BackupCategory = "security" | "studio-role" | "studio-assignment";
|
|
12
|
+
export interface RoleNaturalKey {
|
|
13
|
+
name: string;
|
|
14
|
+
type: string;
|
|
15
|
+
item: string;
|
|
16
|
+
}
|
|
17
|
+
export interface AssignmentKey {
|
|
18
|
+
type: string;
|
|
19
|
+
item: string;
|
|
20
|
+
role: string;
|
|
21
|
+
}
|
|
22
|
+
export interface BackupSnapshot {
|
|
23
|
+
version: 1;
|
|
24
|
+
/** Originating action, e.g. "delete_studio_role". */
|
|
25
|
+
action: string;
|
|
26
|
+
category: BackupCategory;
|
|
27
|
+
/** security._id | role _id/name | "type:item:role". */
|
|
28
|
+
resourceId: string;
|
|
29
|
+
/** Recorded so restore-to-absent can resolve the server `_id` (studio-role) or rebuild the unassign payload. */
|
|
30
|
+
naturalKey?: RoleNaturalKey | AssignmentKey;
|
|
31
|
+
/** false => the original op created the resource (restore = remove it). */
|
|
32
|
+
existedBefore: boolean;
|
|
33
|
+
capturedAt: string;
|
|
34
|
+
/** Best-effort, from ApiHolder. */
|
|
35
|
+
serverUrl: string | null;
|
|
36
|
+
/** Full prior state; null when existedBefore=false. */
|
|
37
|
+
preImage: unknown | null;
|
|
38
|
+
}
|
|
39
|
+
export interface BackupListItem {
|
|
40
|
+
path: string;
|
|
41
|
+
category: BackupCategory;
|
|
42
|
+
resourceId: string;
|
|
43
|
+
action: string;
|
|
44
|
+
capturedAt: string;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Root directory for snapshots. Honors `FUNIFIER_BACKUP_ROOT` so tests (and operators
|
|
48
|
+
* with a preferred location) can redirect writes without touching the working tree.
|
|
49
|
+
* Falls back to `<FUNIFIER_PROJECT_ROOT or cwd>/.funifier/backups`.
|
|
50
|
+
*/
|
|
51
|
+
export declare function backupRoot(): string;
|
|
52
|
+
/** Resolve and validate that `raw` points inside `root` (blocks path traversal). */
|
|
53
|
+
export declare function resolveBackupPath(raw: string, root?: string): string;
|
|
54
|
+
/**
|
|
55
|
+
* Writes `<dir>/.gitignore` with `*` when missing so snapshots (which may contain
|
|
56
|
+
* app_secret) stay out of git even when the project root .gitignore was never updated.
|
|
57
|
+
*/
|
|
58
|
+
export declare function ensureSelfIgnore(dir: string): void;
|
|
59
|
+
/**
|
|
60
|
+
* Serialize a snapshot to `<root>/<category>/<safeId>-<timestamp>.json` and return the
|
|
61
|
+
* absolute path. Synchronous so call sites need not await. **Throws** on any mkdir/write/
|
|
62
|
+
* serialization failure — this throw is the abort signal that prevents the remote mutation.
|
|
63
|
+
*/
|
|
64
|
+
export declare function captureBackup(snapshot: BackupSnapshot, root?: string): string;
|
|
65
|
+
/** Recursively read every `*.json` snapshot under `root`, newest-first. Skips unreadable files. */
|
|
66
|
+
export declare function listSnapshots(root?: string): BackupListItem[];
|
|
67
|
+
/** Read and zod-validate a snapshot. Throws on missing, corrupt, or schema-invalid files. */
|
|
68
|
+
export declare function readSnapshot(filePath: string): BackupSnapshot;
|
|
69
|
+
/**
|
|
70
|
+
* Reapply a snapshot's prior state ("make reality match preImage"): when `existedBefore`
|
|
71
|
+
* reapply the captured payload; otherwise remove the resource the original op created.
|
|
72
|
+
*/
|
|
73
|
+
export declare function applySnapshot(api: any, snapshot: BackupSnapshot): Promise<unknown>;
|
|
74
|
+
//# sourceMappingURL=_backup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_backup.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/_backup.ts"],"names":[],"mappings":"AAIA;;;;;;;;;GASG;AAEH,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,aAAa,GAAG,mBAAmB,CAAC;AAE9E,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,CAAC,CAAC;IACX,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,cAAc,CAAC;IACzB,uDAAuD;IACvD,UAAU,EAAE,MAAM,CAAC;IACnB,gHAAgH;IAChH,UAAU,CAAC,EAAE,cAAc,GAAG,aAAa,CAAC;IAC5C,2EAA2E;IAC3E,aAAa,EAAE,OAAO,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,mCAAmC;IACnC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,uDAAuD;IACvD,QAAQ,EAAE,OAAO,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,cAAc,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAGnC;AAED,oFAAoF;AACpF,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE,MAAqB,GAAG,MAAM,CAOlF;AAcD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAKlD;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,cAAc,EAAE,IAAI,GAAE,MAAqB,GAAG,MAAM,CAgB3F;AA4CD,mGAAmG;AACnG,wBAAgB,aAAa,CAAC,IAAI,GAAE,MAAqB,GAAG,cAAc,EAAE,CAqB3E;AAED,6FAA6F;AAC7F,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,cAAc,CAI7D;AA+DD;;;GAGG;AACH,wBAAsB,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,CAWxF"}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.backupRoot = backupRoot;
|
|
7
|
+
exports.resolveBackupPath = resolveBackupPath;
|
|
8
|
+
exports.ensureSelfIgnore = ensureSelfIgnore;
|
|
9
|
+
exports.captureBackup = captureBackup;
|
|
10
|
+
exports.listSnapshots = listSnapshots;
|
|
11
|
+
exports.readSnapshot = readSnapshot;
|
|
12
|
+
exports.applySnapshot = applySnapshot;
|
|
13
|
+
const fs_1 = __importDefault(require("fs"));
|
|
14
|
+
const path_1 = __importDefault(require("path"));
|
|
15
|
+
const zod_1 = require("zod");
|
|
16
|
+
/**
|
|
17
|
+
* Root directory for snapshots. Honors `FUNIFIER_BACKUP_ROOT` so tests (and operators
|
|
18
|
+
* with a preferred location) can redirect writes without touching the working tree.
|
|
19
|
+
* Falls back to `<FUNIFIER_PROJECT_ROOT or cwd>/.funifier/backups`.
|
|
20
|
+
*/
|
|
21
|
+
function backupRoot() {
|
|
22
|
+
const projectRoot = process.env.FUNIFIER_PROJECT_ROOT ?? process.cwd();
|
|
23
|
+
return process.env.FUNIFIER_BACKUP_ROOT ?? path_1.default.join(projectRoot, ".funifier", "backups");
|
|
24
|
+
}
|
|
25
|
+
/** Resolve and validate that `raw` points inside `root` (blocks path traversal). */
|
|
26
|
+
function resolveBackupPath(raw, root = backupRoot()) {
|
|
27
|
+
const resolved = path_1.default.resolve(raw);
|
|
28
|
+
const resolvedRoot = path_1.default.resolve(root);
|
|
29
|
+
if (!resolved.startsWith(resolvedRoot + path_1.default.sep) && resolved !== resolvedRoot) {
|
|
30
|
+
throw new Error(`backup_path must be within ${resolvedRoot}; got ${raw}`);
|
|
31
|
+
}
|
|
32
|
+
return resolved;
|
|
33
|
+
}
|
|
34
|
+
/** `resourceId` with filesystem-unsafe characters collapsed to `_`. */
|
|
35
|
+
function sanitizeId(resourceId) {
|
|
36
|
+
return resourceId.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
37
|
+
}
|
|
38
|
+
/** ISO-8601 → compact `YYYYMMDDTHHmmssSSS` (sub-second precision avoids same-second collisions). */
|
|
39
|
+
function compactTimestamp(capturedAt) {
|
|
40
|
+
return capturedAt.replace(/[-:]/g, "").replace(/\.(\d{3})Z$/, "$1");
|
|
41
|
+
}
|
|
42
|
+
const SELF_IGNORE_CONTENT = "*\n";
|
|
43
|
+
/**
|
|
44
|
+
* Writes `<dir>/.gitignore` with `*` when missing so snapshots (which may contain
|
|
45
|
+
* app_secret) stay out of git even when the project root .gitignore was never updated.
|
|
46
|
+
*/
|
|
47
|
+
function ensureSelfIgnore(dir) {
|
|
48
|
+
const ignorePath = path_1.default.join(dir, ".gitignore");
|
|
49
|
+
if (!fs_1.default.existsSync(ignorePath)) {
|
|
50
|
+
fs_1.default.writeFileSync(ignorePath, SELF_IGNORE_CONTENT, "utf8");
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Serialize a snapshot to `<root>/<category>/<safeId>-<timestamp>.json` and return the
|
|
55
|
+
* absolute path. Synchronous so call sites need not await. **Throws** on any mkdir/write/
|
|
56
|
+
* serialization failure — this throw is the abort signal that prevents the remote mutation.
|
|
57
|
+
*/
|
|
58
|
+
function captureBackup(snapshot, root = backupRoot()) {
|
|
59
|
+
fs_1.default.mkdirSync(root, { recursive: true });
|
|
60
|
+
ensureSelfIgnore(root);
|
|
61
|
+
const dir = path_1.default.join(root, snapshot.category);
|
|
62
|
+
fs_1.default.mkdirSync(dir, { recursive: true });
|
|
63
|
+
const safeId = sanitizeId(snapshot.resourceId);
|
|
64
|
+
const timestamp = compactTimestamp(snapshot.capturedAt);
|
|
65
|
+
let filePath = path_1.default.join(dir, `${safeId}-${timestamp}.json`);
|
|
66
|
+
if (fs_1.default.existsSync(filePath)) {
|
|
67
|
+
filePath = path_1.default.join(dir, `${safeId}-${timestamp}-${Date.now()}.json`);
|
|
68
|
+
}
|
|
69
|
+
fs_1.default.writeFileSync(filePath, JSON.stringify(snapshot, null, 2), "utf8");
|
|
70
|
+
return filePath;
|
|
71
|
+
}
|
|
72
|
+
const roleNaturalKeySchema = zod_1.z.object({
|
|
73
|
+
name: zod_1.z.string(),
|
|
74
|
+
type: zod_1.z.string(),
|
|
75
|
+
item: zod_1.z.string(),
|
|
76
|
+
});
|
|
77
|
+
const assignmentKeySchema = zod_1.z.object({
|
|
78
|
+
type: zod_1.z.string(),
|
|
79
|
+
item: zod_1.z.string(),
|
|
80
|
+
role: zod_1.z.string(),
|
|
81
|
+
});
|
|
82
|
+
const snapshotSchema = zod_1.z.object({
|
|
83
|
+
version: zod_1.z.literal(1),
|
|
84
|
+
action: zod_1.z.string(),
|
|
85
|
+
category: zod_1.z.enum(["security", "studio-role", "studio-assignment"]),
|
|
86
|
+
resourceId: zod_1.z.string(),
|
|
87
|
+
naturalKey: zod_1.z.union([roleNaturalKeySchema, assignmentKeySchema]).optional(),
|
|
88
|
+
existedBefore: zod_1.z.boolean(),
|
|
89
|
+
capturedAt: zod_1.z.string(),
|
|
90
|
+
serverUrl: zod_1.z.string().nullable(),
|
|
91
|
+
preImage: zod_1.z.unknown().nullable(),
|
|
92
|
+
});
|
|
93
|
+
/** Lenient header used for listing — tolerates files missing the full body. */
|
|
94
|
+
const snapshotHeaderSchema = zod_1.z.object({
|
|
95
|
+
category: zod_1.z.enum(["security", "studio-role", "studio-assignment"]),
|
|
96
|
+
resourceId: zod_1.z.string(),
|
|
97
|
+
action: zod_1.z.string(),
|
|
98
|
+
capturedAt: zod_1.z.string(),
|
|
99
|
+
});
|
|
100
|
+
function walkJsonFiles(dir) {
|
|
101
|
+
const out = [];
|
|
102
|
+
for (const entry of fs_1.default.readdirSync(dir, { withFileTypes: true })) {
|
|
103
|
+
const full = path_1.default.join(dir, entry.name);
|
|
104
|
+
if (entry.isDirectory())
|
|
105
|
+
out.push(...walkJsonFiles(full));
|
|
106
|
+
else if (entry.isFile() && entry.name.endsWith(".json"))
|
|
107
|
+
out.push(full);
|
|
108
|
+
}
|
|
109
|
+
return out;
|
|
110
|
+
}
|
|
111
|
+
/** Recursively read every `*.json` snapshot under `root`, newest-first. Skips unreadable files. */
|
|
112
|
+
function listSnapshots(root = backupRoot()) {
|
|
113
|
+
if (!fs_1.default.existsSync(root))
|
|
114
|
+
return [];
|
|
115
|
+
const items = [];
|
|
116
|
+
for (const filePath of walkJsonFiles(root)) {
|
|
117
|
+
try {
|
|
118
|
+
const parsed = JSON.parse(fs_1.default.readFileSync(filePath, "utf8"));
|
|
119
|
+
const header = snapshotHeaderSchema.parse(parsed);
|
|
120
|
+
items.push({
|
|
121
|
+
path: filePath,
|
|
122
|
+
category: header.category,
|
|
123
|
+
resourceId: header.resourceId,
|
|
124
|
+
action: header.action,
|
|
125
|
+
capturedAt: header.capturedAt,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
console.warn(`Skipping corrupt/invalid snapshot: ${filePath}`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return items.sort((a, b) => b.capturedAt.localeCompare(a.capturedAt));
|
|
133
|
+
}
|
|
134
|
+
/** Read and zod-validate a snapshot. Throws on missing, corrupt, or schema-invalid files. */
|
|
135
|
+
function readSnapshot(filePath) {
|
|
136
|
+
const raw = fs_1.default.readFileSync(filePath, "utf8");
|
|
137
|
+
const parsed = JSON.parse(raw);
|
|
138
|
+
return snapshotSchema.parse(parsed);
|
|
139
|
+
}
|
|
140
|
+
async function applySecuritySnapshot(api, snapshot) {
|
|
141
|
+
const preImage = snapshot.preImage;
|
|
142
|
+
if (!preImage || !preImage._id) {
|
|
143
|
+
throw new Error("Security snapshot has no restorable pre-image.");
|
|
144
|
+
}
|
|
145
|
+
const docs = await api.queryCollection("security", {}, { limit: 1, skip: 0 });
|
|
146
|
+
const live = Array.isArray(docs) ? docs[0] : undefined;
|
|
147
|
+
if (!live || !live._id) {
|
|
148
|
+
throw new Error("Security document not found in collection 'security'.");
|
|
149
|
+
}
|
|
150
|
+
if (live._id !== preImage._id) {
|
|
151
|
+
throw new Error(`Security document _id mismatch (snapshot '${preImage._id}' vs live '${live._id}'). Refusing to restore a divergent document.`);
|
|
152
|
+
}
|
|
153
|
+
return api.updateDocument("security", preImage);
|
|
154
|
+
}
|
|
155
|
+
async function applyStudioRoleSnapshot(api, snapshot) {
|
|
156
|
+
if (snapshot.existedBefore) {
|
|
157
|
+
if (!snapshot.preImage)
|
|
158
|
+
throw new Error("Studio-role snapshot marked existedBefore but has no pre-image.");
|
|
159
|
+
return api.saveRole(snapshot.preImage);
|
|
160
|
+
}
|
|
161
|
+
// The original op created the role, so there is no captured `_id`. Resolve it now,
|
|
162
|
+
// while the role still exists, by matching the natural key — then delete.
|
|
163
|
+
const naturalKey = snapshot.naturalKey;
|
|
164
|
+
if (!naturalKey || !naturalKey.name) {
|
|
165
|
+
throw new Error("Cannot restore studio role to absent without a natural key.");
|
|
166
|
+
}
|
|
167
|
+
const roles = await api.listRoles();
|
|
168
|
+
const matches = roles.filter((role) => role.name === naturalKey.name && role.type === naturalKey.type && role.item === naturalKey.item);
|
|
169
|
+
if (matches.length > 1) {
|
|
170
|
+
throw new Error(`Ambiguous studio role natural key (${naturalKey.name}/${naturalKey.type}/${naturalKey.item}): ${matches.length} matches. Refusing to delete.`);
|
|
171
|
+
}
|
|
172
|
+
const match = matches[0];
|
|
173
|
+
if (!match || !match._id) {
|
|
174
|
+
return { ok: 1, note: "Role already absent; nothing to delete." };
|
|
175
|
+
}
|
|
176
|
+
return api.deleteRole(match._id);
|
|
177
|
+
}
|
|
178
|
+
async function applyStudioAssignmentSnapshot(api, snapshot) {
|
|
179
|
+
if (snapshot.existedBefore) {
|
|
180
|
+
if (!snapshot.preImage)
|
|
181
|
+
throw new Error("Assignment snapshot marked existedBefore but has no pre-image.");
|
|
182
|
+
return api.assignRole(snapshot.preImage);
|
|
183
|
+
}
|
|
184
|
+
const naturalKey = snapshot.naturalKey;
|
|
185
|
+
if (!naturalKey)
|
|
186
|
+
throw new Error("Cannot restore assignment to absent without a natural key.");
|
|
187
|
+
return api.unassignRole(naturalKey);
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Reapply a snapshot's prior state ("make reality match preImage"): when `existedBefore`
|
|
191
|
+
* reapply the captured payload; otherwise remove the resource the original op created.
|
|
192
|
+
*/
|
|
193
|
+
async function applySnapshot(api, snapshot) {
|
|
194
|
+
switch (snapshot.category) {
|
|
195
|
+
case "security":
|
|
196
|
+
return applySecuritySnapshot(api, snapshot);
|
|
197
|
+
case "studio-role":
|
|
198
|
+
return applyStudioRoleSnapshot(api, snapshot);
|
|
199
|
+
case "studio-assignment":
|
|
200
|
+
return applyStudioAssignmentSnapshot(api, snapshot);
|
|
201
|
+
default:
|
|
202
|
+
throw new Error(`Unknown backup category: ${snapshot.category}`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
//# sourceMappingURL=_backup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_backup.js","sourceRoot":"","sources":["../../../src/mcp/tools/_backup.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_backup.test.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/_backup.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
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"));
|
|
10
|
+
const _backup_1 = require("./_backup");
|
|
11
|
+
let root;
|
|
12
|
+
(0, vitest_1.beforeEach)(() => {
|
|
13
|
+
root = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), "funifier-backup-test-"));
|
|
14
|
+
});
|
|
15
|
+
(0, vitest_1.afterEach)(() => {
|
|
16
|
+
fs_1.default.rmSync(root, { recursive: true, force: true });
|
|
17
|
+
});
|
|
18
|
+
function snapshot(overrides = {}) {
|
|
19
|
+
return {
|
|
20
|
+
version: 1,
|
|
21
|
+
action: "delete_studio_role",
|
|
22
|
+
category: "studio-role",
|
|
23
|
+
resourceId: "r1",
|
|
24
|
+
existedBefore: true,
|
|
25
|
+
capturedAt: "2026-05-28T14:31:02.123Z",
|
|
26
|
+
serverUrl: null,
|
|
27
|
+
preImage: { _id: "r1", name: "Admin", type: "system", item: "system", permissions: [] },
|
|
28
|
+
...overrides,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
(0, vitest_1.describe)("captureBackup", () => {
|
|
32
|
+
(0, vitest_1.it)("writes the serialized snapshot to <root>/<category>/<safeId>-<timestamp>.json", () => {
|
|
33
|
+
const snap = snapshot();
|
|
34
|
+
const filePath = (0, _backup_1.captureBackup)(snap, root);
|
|
35
|
+
(0, vitest_1.expect)(path_1.default.isAbsolute(filePath)).toBe(true);
|
|
36
|
+
(0, vitest_1.expect)(filePath).toBe(path_1.default.join(root, "studio-role", "r1-20260528T143102123.json"));
|
|
37
|
+
(0, vitest_1.expect)(fs_1.default.existsSync(filePath)).toBe(true);
|
|
38
|
+
(0, vitest_1.expect)(JSON.parse(fs_1.default.readFileSync(filePath, "utf8"))).toEqual(snap);
|
|
39
|
+
});
|
|
40
|
+
(0, vitest_1.it)("sanitizes filesystem-unsafe characters in the resourceId", () => {
|
|
41
|
+
const filePath = (0, _backup_1.captureBackup)(snapshot({ category: "studio-assignment", resourceId: "user:u/1:r1" }), root);
|
|
42
|
+
(0, vitest_1.expect)(path_1.default.basename(filePath)).toBe("user_u_1_r1-20260528T143102123.json");
|
|
43
|
+
});
|
|
44
|
+
(0, vitest_1.it)("throws when the snapshot cannot be serialized (abort signal for the mutation)", () => {
|
|
45
|
+
const circular = {};
|
|
46
|
+
circular.self = circular;
|
|
47
|
+
(0, vitest_1.expect)(() => (0, _backup_1.captureBackup)(snapshot({ preImage: circular }), root)).toThrow();
|
|
48
|
+
});
|
|
49
|
+
(0, vitest_1.it)("throws when the root cannot be written (a file blocks the category directory)", () => {
|
|
50
|
+
const blocker = path_1.default.join(root, "security");
|
|
51
|
+
fs_1.default.writeFileSync(blocker, "not-a-directory");
|
|
52
|
+
(0, vitest_1.expect)(() => (0, _backup_1.captureBackup)(snapshot({ category: "security" }), root)).toThrow();
|
|
53
|
+
});
|
|
54
|
+
(0, vitest_1.it)("appends a millisecond suffix when the filename collides", () => {
|
|
55
|
+
const snap = snapshot();
|
|
56
|
+
const first = (0, _backup_1.captureBackup)(snap, root);
|
|
57
|
+
const second = (0, _backup_1.captureBackup)(snap, root);
|
|
58
|
+
(0, vitest_1.expect)(first).not.toBe(second);
|
|
59
|
+
(0, vitest_1.expect)(fs_1.default.existsSync(first)).toBe(true);
|
|
60
|
+
(0, vitest_1.expect)(fs_1.default.existsSync(second)).toBe(true);
|
|
61
|
+
});
|
|
62
|
+
(0, vitest_1.it)("creates a self-contained .gitignore with * in the backup root (idempotent)", () => {
|
|
63
|
+
const ignorePath = path_1.default.join(root, ".gitignore");
|
|
64
|
+
(0, vitest_1.expect)(fs_1.default.existsSync(ignorePath)).toBe(false);
|
|
65
|
+
(0, _backup_1.captureBackup)(snapshot(), root);
|
|
66
|
+
(0, vitest_1.expect)(fs_1.default.readFileSync(ignorePath, "utf8")).toBe("*\n");
|
|
67
|
+
const mtime = fs_1.default.statSync(ignorePath).mtimeMs;
|
|
68
|
+
(0, _backup_1.captureBackup)(snapshot({ resourceId: "second" }), root);
|
|
69
|
+
(0, vitest_1.expect)(fs_1.default.statSync(ignorePath).mtimeMs).toBe(mtime);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
(0, vitest_1.describe)("ensureSelfIgnore", () => {
|
|
73
|
+
(0, vitest_1.it)("writes * to <dir>/.gitignore only when missing", () => {
|
|
74
|
+
const dir = path_1.default.join(root, "nested");
|
|
75
|
+
fs_1.default.mkdirSync(dir, { recursive: true });
|
|
76
|
+
(0, _backup_1.ensureSelfIgnore)(dir);
|
|
77
|
+
(0, _backup_1.ensureSelfIgnore)(dir);
|
|
78
|
+
(0, vitest_1.expect)(fs_1.default.readFileSync(path_1.default.join(dir, ".gitignore"), "utf8")).toBe("*\n");
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
(0, vitest_1.describe)("resolveBackupPath", () => {
|
|
82
|
+
(0, vitest_1.it)("accepts paths inside the backup root", () => {
|
|
83
|
+
const filePath = (0, _backup_1.captureBackup)(snapshot(), root);
|
|
84
|
+
(0, vitest_1.expect)((0, _backup_1.resolveBackupPath)(filePath, root)).toBe(path_1.default.resolve(filePath));
|
|
85
|
+
});
|
|
86
|
+
(0, vitest_1.it)("rejects path traversal outside the backup root", () => {
|
|
87
|
+
const outside = path_1.default.join(root, "..", "outside.json");
|
|
88
|
+
(0, vitest_1.expect)(() => (0, _backup_1.resolveBackupPath)(outside, root)).toThrow(/must be within/i);
|
|
89
|
+
});
|
|
90
|
+
(0, vitest_1.it)("rejects absolute paths outside the backup root", () => {
|
|
91
|
+
(0, vitest_1.expect)(() => (0, _backup_1.resolveBackupPath)("/etc/passwd", root)).toThrow(/must be within/i);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
(0, vitest_1.describe)("readSnapshot", () => {
|
|
95
|
+
(0, vitest_1.it)("round-trips a captured snapshot", () => {
|
|
96
|
+
const snap = snapshot();
|
|
97
|
+
const filePath = (0, _backup_1.captureBackup)(snap, root);
|
|
98
|
+
(0, vitest_1.expect)((0, _backup_1.readSnapshot)(filePath)).toEqual(snap);
|
|
99
|
+
});
|
|
100
|
+
(0, vitest_1.it)("throws on a non-existent path", () => {
|
|
101
|
+
(0, vitest_1.expect)(() => (0, _backup_1.readSnapshot)(path_1.default.join(root, "missing.json"))).toThrow();
|
|
102
|
+
});
|
|
103
|
+
(0, vitest_1.it)("throws on a JSON file that fails the schema", () => {
|
|
104
|
+
const filePath = path_1.default.join(root, "bad.json");
|
|
105
|
+
fs_1.default.writeFileSync(filePath, JSON.stringify({ version: 99, hello: "world" }));
|
|
106
|
+
(0, vitest_1.expect)(() => (0, _backup_1.readSnapshot)(filePath)).toThrow();
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
(0, vitest_1.describe)("listSnapshots", () => {
|
|
110
|
+
(0, vitest_1.it)("returns an empty list when the root does not exist", () => {
|
|
111
|
+
(0, vitest_1.expect)((0, _backup_1.listSnapshots)(path_1.default.join(root, "nope"))).toEqual([]);
|
|
112
|
+
});
|
|
113
|
+
(0, vitest_1.it)("returns items newest-first by capturedAt", () => {
|
|
114
|
+
(0, _backup_1.captureBackup)(snapshot({ resourceId: "older", capturedAt: "2026-05-28T10:00:00.000Z" }), root);
|
|
115
|
+
(0, _backup_1.captureBackup)(snapshot({ resourceId: "newer", capturedAt: "2026-05-28T12:00:00.000Z" }), root);
|
|
116
|
+
const items = (0, _backup_1.listSnapshots)(root);
|
|
117
|
+
(0, vitest_1.expect)(items.map((i) => i.resourceId)).toEqual(["newer", "older"]);
|
|
118
|
+
(0, vitest_1.expect)(items[0].category).toBe("studio-role");
|
|
119
|
+
});
|
|
120
|
+
(0, vitest_1.it)("skips corrupt and non-JSON files with a warning", () => {
|
|
121
|
+
const warn = vitest_1.vi.spyOn(console, "warn").mockImplementation(() => { });
|
|
122
|
+
(0, _backup_1.captureBackup)(snapshot(), root);
|
|
123
|
+
fs_1.default.writeFileSync(path_1.default.join(root, "studio-role", "not-json.txt"), "hello");
|
|
124
|
+
fs_1.default.writeFileSync(path_1.default.join(root, "studio-role", "corrupt.json"), "{ invalid");
|
|
125
|
+
const items = (0, _backup_1.listSnapshots)(root);
|
|
126
|
+
(0, vitest_1.expect)(items).toHaveLength(1);
|
|
127
|
+
(0, vitest_1.expect)(warn).toHaveBeenCalledWith(vitest_1.expect.stringContaining("corrupt.json"));
|
|
128
|
+
warn.mockRestore();
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
(0, vitest_1.describe)("applySnapshot", () => {
|
|
132
|
+
(0, vitest_1.it)("security: updates the document when the live _id matches", async () => {
|
|
133
|
+
const preImage = { _id: "game1", apps: [], roles: [] };
|
|
134
|
+
const api = {
|
|
135
|
+
queryCollection: vitest_1.vi.fn().mockResolvedValue([{ _id: "game1" }]),
|
|
136
|
+
updateDocument: vitest_1.vi.fn().mockResolvedValue({ ok: 1 }),
|
|
137
|
+
};
|
|
138
|
+
await (0, _backup_1.applySnapshot)(api, snapshot({ category: "security", resourceId: "game1", preImage }));
|
|
139
|
+
(0, vitest_1.expect)(api.updateDocument).toHaveBeenCalledWith("security", preImage);
|
|
140
|
+
});
|
|
141
|
+
(0, vitest_1.it)("security: throws on _id mismatch instead of writing a divergent document", async () => {
|
|
142
|
+
const api = {
|
|
143
|
+
queryCollection: vitest_1.vi.fn().mockResolvedValue([{ _id: "other" }]),
|
|
144
|
+
updateDocument: vitest_1.vi.fn(),
|
|
145
|
+
};
|
|
146
|
+
await (0, vitest_1.expect)((0, _backup_1.applySnapshot)(api, snapshot({ category: "security", resourceId: "game1", preImage: { _id: "game1" } }))).rejects.toThrow(/mismatch/i);
|
|
147
|
+
(0, vitest_1.expect)(api.updateDocument).not.toHaveBeenCalled();
|
|
148
|
+
});
|
|
149
|
+
(0, vitest_1.it)("studio-role existedBefore: reapplies the captured role via saveRole", async () => {
|
|
150
|
+
const preImage = { _id: "r1", name: "Admin", type: "system", item: "system", permissions: [] };
|
|
151
|
+
const api = { saveRole: vitest_1.vi.fn().mockResolvedValue(preImage) };
|
|
152
|
+
await (0, _backup_1.applySnapshot)(api, snapshot({ category: "studio-role", preImage, existedBefore: true }));
|
|
153
|
+
(0, vitest_1.expect)(api.saveRole).toHaveBeenCalledWith(preImage);
|
|
154
|
+
});
|
|
155
|
+
(0, vitest_1.it)("studio-role absent: resolves _id via listRoles natural-key match, then deleteRole", async () => {
|
|
156
|
+
const api = {
|
|
157
|
+
listRoles: vitest_1.vi.fn().mockResolvedValue([
|
|
158
|
+
{ _id: "wrong", name: "Admin", type: "gamification", item: "game1", permissions: [] },
|
|
159
|
+
{ _id: "right", name: "Admin", type: "system", item: "system", permissions: [] },
|
|
160
|
+
]),
|
|
161
|
+
deleteRole: vitest_1.vi.fn().mockResolvedValue({ ok: 1 }),
|
|
162
|
+
};
|
|
163
|
+
await (0, _backup_1.applySnapshot)(api, snapshot({
|
|
164
|
+
category: "studio-role",
|
|
165
|
+
existedBefore: false,
|
|
166
|
+
preImage: null,
|
|
167
|
+
naturalKey: { name: "Admin", type: "system", item: "system" },
|
|
168
|
+
}));
|
|
169
|
+
(0, vitest_1.expect)(api.deleteRole).toHaveBeenCalledWith("right");
|
|
170
|
+
});
|
|
171
|
+
(0, vitest_1.it)("studio-role absent: throws when natural key matches multiple roles", async () => {
|
|
172
|
+
const api = {
|
|
173
|
+
listRoles: vitest_1.vi.fn().mockResolvedValue([
|
|
174
|
+
{ _id: "dup-a", name: "Admin", type: "system", item: "system", permissions: [] },
|
|
175
|
+
{ _id: "dup-b", name: "Admin", type: "system", item: "system", permissions: [] },
|
|
176
|
+
]),
|
|
177
|
+
deleteRole: vitest_1.vi.fn(),
|
|
178
|
+
};
|
|
179
|
+
await (0, vitest_1.expect)((0, _backup_1.applySnapshot)(api, snapshot({
|
|
180
|
+
category: "studio-role",
|
|
181
|
+
existedBefore: false,
|
|
182
|
+
preImage: null,
|
|
183
|
+
naturalKey: { name: "Admin", type: "system", item: "system" },
|
|
184
|
+
}))).rejects.toThrow(/Ambiguous studio role natural key/i);
|
|
185
|
+
(0, vitest_1.expect)(api.deleteRole).not.toHaveBeenCalled();
|
|
186
|
+
});
|
|
187
|
+
(0, vitest_1.it)("studio-assignment existedBefore: reapplies via assignRole", async () => {
|
|
188
|
+
const preImage = { type: "user", item: "u1", role: "r1" };
|
|
189
|
+
const api = { assignRole: vitest_1.vi.fn().mockResolvedValue(preImage) };
|
|
190
|
+
await (0, _backup_1.applySnapshot)(api, snapshot({ category: "studio-assignment", preImage, existedBefore: true }));
|
|
191
|
+
(0, vitest_1.expect)(api.assignRole).toHaveBeenCalledWith(preImage);
|
|
192
|
+
});
|
|
193
|
+
(0, vitest_1.it)("studio-assignment absent: removes via unassignRole(naturalKey)", async () => {
|
|
194
|
+
const naturalKey = { type: "user", item: "u1", role: "r1" };
|
|
195
|
+
const api = { unassignRole: vitest_1.vi.fn().mockResolvedValue({ ok: 1 }) };
|
|
196
|
+
await (0, _backup_1.applySnapshot)(api, snapshot({ category: "studio-assignment", existedBefore: false, preImage: null, naturalKey }));
|
|
197
|
+
(0, vitest_1.expect)(api.unassignRole).toHaveBeenCalledWith(naturalKey);
|
|
198
|
+
});
|
|
199
|
+
(0, vitest_1.it)("throws on an unknown backup category", async () => {
|
|
200
|
+
const api = {};
|
|
201
|
+
await (0, vitest_1.expect)((0, _backup_1.applySnapshot)(api, { ...snapshot(), category: "unknown" })).rejects.toThrow(/Unknown backup category/i);
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
//# sourceMappingURL=_backup.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_backup.test.js","sourceRoot":"","sources":["../../../src/mcp/tools/_backup.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list-tools.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/list-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"list-tools.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/list-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAyIpE,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,QAqBtD"}
|
|
@@ -67,8 +67,9 @@ const TOOL_CATALOG = {
|
|
|
67
67
|
{
|
|
68
68
|
name: "funifier_permissions",
|
|
69
69
|
requiresApi: true,
|
|
70
|
-
description: "Manage API scopes/security roles and Studio roles/assignments without mixing the two permission models."
|
|
71
|
-
|
|
70
|
+
description: "Manage API scopes/security roles and Studio roles/assignments without mixing the two permission models. " +
|
|
71
|
+
"Every mutating action auto-backups prior state; use list_backups/restore_backup to roll back.",
|
|
72
|
+
keyParams: "action, data?, app_secret?, name?, role_id?, item?, backup_path?",
|
|
72
73
|
},
|
|
73
74
|
{
|
|
74
75
|
name: "funifier_folder",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list-tools.js","sourceRoot":"","sources":["../../../src/mcp/tools/list-tools.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"list-tools.js","sourceRoot":"","sources":["../../../src/mcp/tools/list-tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"permissions.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/permissions.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"permissions.d.ts","sourceRoot":"","sources":["../../../src/mcp/tools/permissions.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AA8P1C,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,QAgO9E"}
|