create-guardio 0.0.7 → 0.0.9
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/index.mjs +117 -45
- package/package.json +5 -2
package/index.mjs
CHANGED
|
@@ -1,11 +1,22 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createInterface } from "node:readline";
|
|
3
|
-
import { mkdir, writeFile } from "node:fs/promises";
|
|
4
|
-
import {
|
|
3
|
+
import { mkdir, writeFile, mkdtemp } from "node:fs/promises";
|
|
4
|
+
import { createWriteStream } from "node:fs";
|
|
5
|
+
import { readdirSync, cpSync, existsSync } from "node:fs";
|
|
6
|
+
import { resolve, dirname, join } from "node:path";
|
|
5
7
|
import { fileURLToPath } from "node:url";
|
|
8
|
+
import { pipeline } from "node:stream/promises";
|
|
9
|
+
import { tmpdir } from "node:os";
|
|
10
|
+
import { spawnSync } from "node:child_process";
|
|
11
|
+
import decompress from "decompress";
|
|
6
12
|
|
|
7
13
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
14
|
|
|
15
|
+
const DASHBOARD_REPO =
|
|
16
|
+
process.env.GUARDIO_DASHBOARD_REPO || "radoslaw-sz/guardio";
|
|
17
|
+
const DASHBOARD_BRANCH = process.env.GUARDIO_DASHBOARD_BRANCH || "main";
|
|
18
|
+
const DASHBOARD_TARBALL_URL = `https://github.com/${DASHBOARD_REPO}/archive/refs/heads/${DASHBOARD_BRANCH}.tar.gz`;
|
|
19
|
+
|
|
9
20
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
10
21
|
|
|
11
22
|
function ask(question, defaultAnswer = "") {
|
|
@@ -27,46 +38,83 @@ function askYesNo(question, defaultAnswer = "n") {
|
|
|
27
38
|
);
|
|
28
39
|
}
|
|
29
40
|
|
|
41
|
+
async function setupDashboardFromTarball(guardioPath) {
|
|
42
|
+
const dashboardPath = join(guardioPath, "dashboard");
|
|
43
|
+
console.log("Downloading dashboard from GitHub...");
|
|
44
|
+
let res;
|
|
45
|
+
try {
|
|
46
|
+
res = await fetch(DASHBOARD_TARBALL_URL, { redirect: "follow" });
|
|
47
|
+
} catch (err) {
|
|
48
|
+
console.error(
|
|
49
|
+
"Could not download dashboard template. Check network and GUARDIO_DASHBOARD_REPO.",
|
|
50
|
+
);
|
|
51
|
+
throw err;
|
|
52
|
+
}
|
|
53
|
+
if (!res.ok) {
|
|
54
|
+
throw new Error(
|
|
55
|
+
`Dashboard download failed: ${res.status} ${res.statusText}. Check repo (${DASHBOARD_REPO}) and branch (${DASHBOARD_BRANCH}).`,
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
const tmpDir = await mkdtemp(join(tmpdir(), "guardio-dashboard-"));
|
|
59
|
+
const tarPath = join(tmpDir, "archive.tar.gz");
|
|
60
|
+
const w = createWriteStream(tarPath);
|
|
61
|
+
await pipeline(res.body, w);
|
|
62
|
+
console.log("Extracting...");
|
|
63
|
+
const extractDir = join(tmpDir, "extract");
|
|
64
|
+
await mkdir(extractDir, { recursive: true });
|
|
65
|
+
await decompress(tarPath, extractDir);
|
|
66
|
+
const topLevel = readdirSync(extractDir)[0];
|
|
67
|
+
if (!topLevel) {
|
|
68
|
+
throw new Error("Dashboard tarball had no top-level directory.");
|
|
69
|
+
}
|
|
70
|
+
const srcDashboard = join(extractDir, topLevel, "packages", "dashboard");
|
|
71
|
+
if (!existsSync(srcDashboard)) {
|
|
72
|
+
throw new Error(
|
|
73
|
+
"Dashboard tarball missing packages/dashboard. Wrong repo or branch?",
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
await mkdir(dashboardPath, { recursive: true });
|
|
77
|
+
cpSync(srcDashboard, dashboardPath, { recursive: true });
|
|
78
|
+
console.log("Installing dashboard dependencies...");
|
|
79
|
+
const installResult = spawnSync(
|
|
80
|
+
"pnpm",
|
|
81
|
+
["install"],
|
|
82
|
+
{ cwd: dashboardPath, stdio: "inherit", shell: true },
|
|
83
|
+
);
|
|
84
|
+
if (installResult.status !== 0) {
|
|
85
|
+
const npmResult = spawnSync(
|
|
86
|
+
"npm",
|
|
87
|
+
["install"],
|
|
88
|
+
{ cwd: dashboardPath, stdio: "inherit", shell: true },
|
|
89
|
+
);
|
|
90
|
+
if (npmResult.status !== 0) {
|
|
91
|
+
throw new Error("Failed to install dashboard dependencies (tried pnpm and npm).");
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
30
96
|
async function main() {
|
|
31
97
|
console.log("\nCreate Guardio\n");
|
|
32
98
|
|
|
33
|
-
const guardioDir = await ask("Guardio directory", "
|
|
99
|
+
const guardioDir = await ask("Guardio directory", "guardio-project");
|
|
34
100
|
const guardioPath = resolve(process.cwd(), guardioDir);
|
|
35
101
|
|
|
36
|
-
// Servers: at least one, with name + URL
|
|
37
|
-
const servers = [];
|
|
38
|
-
let serverName = await ask("First MCP server name", "default");
|
|
39
|
-
let serverUrl = await ask("MCP server URL", "https://example.com/mcp");
|
|
40
|
-
servers.push({ name: serverName, type: "url", url: serverUrl });
|
|
41
|
-
|
|
42
|
-
while (await askYesNo("Add another MCP server?", "n")) {
|
|
43
|
-
serverName = await ask("MCP server name", "server-" + (servers.length + 1));
|
|
44
|
-
serverUrl = await ask("MCP server URL", "https://example.com/mcp");
|
|
45
|
-
servers.push({ name: serverName, type: "url", url: serverUrl });
|
|
46
|
-
}
|
|
47
|
-
|
|
48
102
|
const portStr = await ask("Guardio HTTP server port", "3939");
|
|
49
103
|
const port = parseInt(portStr, 10) || 3939;
|
|
50
104
|
|
|
51
|
-
const
|
|
105
|
+
const useStorage = await askYesNo(
|
|
106
|
+
"Use storage and events (for dashboard / policy state)?",
|
|
107
|
+
"n",
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
// All built-in policy plugins by default
|
|
111
|
+
const plugins = [
|
|
112
|
+
{ type: "policy", name: "deny-tool-access" },
|
|
113
|
+
{ type: "policy", name: "deny-regex-parameter" },
|
|
114
|
+
];
|
|
52
115
|
|
|
53
|
-
// Built-in plugins: by category
|
|
54
|
-
console.log("\nPolicy plugins:");
|
|
55
|
-
console.log(" 1) none");
|
|
56
|
-
console.log(" 2) deny-tool-access");
|
|
57
|
-
console.log(" 3) regex");
|
|
58
|
-
console.log(" 4) both");
|
|
59
|
-
const policyChoice = await ask("Policy plugins (1-4)", "1");
|
|
60
|
-
const policyNum = parseInt(policyChoice, 10) || 1;
|
|
61
|
-
const policyPlugins = [];
|
|
62
|
-
if (policyNum === 2 || policyNum === 4) policyPlugins.push({ type: "policy", name: "deny-tool-access" });
|
|
63
|
-
if (policyNum === 3 || policyNum === 4) policyPlugins.push({ type: "policy", name: "regex" });
|
|
64
|
-
|
|
65
|
-
const useStorage = await askYesNo("Use storage and events (for dashboard / policy state)?", installDashboard ? "y" : "n");
|
|
66
|
-
|
|
67
|
-
const plugins = [...policyPlugins];
|
|
68
116
|
if (useStorage) {
|
|
69
|
-
console.log(" 1) sqlite (
|
|
117
|
+
console.log(" 1) sqlite (in-memory or file)");
|
|
70
118
|
console.log(" 2) postgres");
|
|
71
119
|
const storageBackend = await ask("Storage backend (1-2)", "1");
|
|
72
120
|
if (storageBackend === "2") {
|
|
@@ -79,20 +127,35 @@ async function main() {
|
|
|
79
127
|
plugins.push({ type: "eventSink", name: "postgres" });
|
|
80
128
|
plugins.push({ type: "eventSinkStore", name: "postgres" });
|
|
81
129
|
} else {
|
|
82
|
-
const
|
|
130
|
+
const sqliteInMemory = await askYesNo(
|
|
131
|
+
"Use in-memory SQLite? (y = in-memory, n = file guardio.sqlite)",
|
|
132
|
+
"y",
|
|
133
|
+
);
|
|
134
|
+
const sqliteConfig = sqliteInMemory
|
|
135
|
+
? { inMemory: true }
|
|
136
|
+
: { database: "guardio.sqlite" };
|
|
83
137
|
plugins.push({ type: "storage", name: "sqlite", config: sqliteConfig });
|
|
84
138
|
plugins.push({ type: "eventSink", name: "sqlite", config: sqliteConfig });
|
|
85
|
-
plugins.push({
|
|
139
|
+
plugins.push({
|
|
140
|
+
type: "eventSinkStore",
|
|
141
|
+
name: "sqlite",
|
|
142
|
+
config: sqliteConfig,
|
|
143
|
+
});
|
|
86
144
|
}
|
|
87
145
|
}
|
|
88
146
|
|
|
89
|
-
const addExamplePlugin = await askYesNo(
|
|
147
|
+
const addExamplePlugin = await askYesNo(
|
|
148
|
+
"Add example custom policy plugin?",
|
|
149
|
+
"n",
|
|
150
|
+
);
|
|
90
151
|
if (addExamplePlugin) {
|
|
91
152
|
plugins.push({ type: "policy", name: "example", path: "./plugins/example" });
|
|
92
153
|
}
|
|
93
154
|
|
|
155
|
+
const installDashboard = await askYesNo("Install dashboard?", "n");
|
|
156
|
+
|
|
94
157
|
const config = {
|
|
95
|
-
servers,
|
|
158
|
+
servers: [],
|
|
96
159
|
client: { port, host: "127.0.0.1" },
|
|
97
160
|
plugins,
|
|
98
161
|
};
|
|
@@ -117,8 +180,7 @@ async function main() {
|
|
|
117
180
|
},
|
|
118
181
|
};
|
|
119
182
|
if (installDashboard) {
|
|
120
|
-
packageJson.
|
|
121
|
-
packageJson.scripts.dashboard = "guardio-dashboard";
|
|
183
|
+
packageJson.scripts.dashboard = "cd dashboard && npm run dev";
|
|
122
184
|
}
|
|
123
185
|
await writeFile(
|
|
124
186
|
resolve(guardioPath, "package.json"),
|
|
@@ -126,6 +188,10 @@ async function main() {
|
|
|
126
188
|
"utf-8",
|
|
127
189
|
);
|
|
128
190
|
|
|
191
|
+
if (installDashboard) {
|
|
192
|
+
await setupDashboardFromTarball(guardioPath);
|
|
193
|
+
}
|
|
194
|
+
|
|
129
195
|
const tsconfig = {
|
|
130
196
|
compilerOptions: {
|
|
131
197
|
target: "ES2022",
|
|
@@ -145,6 +211,9 @@ async function main() {
|
|
|
145
211
|
|
|
146
212
|
const configTsContent = `import type { GuardioConfig } from "@guardiojs/guardio";
|
|
147
213
|
|
|
214
|
+
// Example server (uncomment and add to servers array to proxy an MCP server):
|
|
215
|
+
// { name: "nuvei-docs", type: "url", url: "https://mcp.nuvei.com/sse" }
|
|
216
|
+
|
|
148
217
|
const config: GuardioConfig = ${JSON.stringify(config, null, 2).replace(/^/gm, " ")};
|
|
149
218
|
|
|
150
219
|
export default config;
|
|
@@ -171,9 +240,9 @@ export default config;
|
|
|
171
240
|
class ExamplePolicyPlugin implements PolicyPluginInterface {
|
|
172
241
|
readonly name = "example";
|
|
173
242
|
|
|
174
|
-
evaluate(context: PolicyRequestContext): PolicyResult {
|
|
243
|
+
async evaluate(context: PolicyRequestContext): Promise<PolicyResult> {
|
|
175
244
|
// Example: allow all calls. Replace with your policy logic.
|
|
176
|
-
return { verdict: "allow" };
|
|
245
|
+
return Promise.resolve({ verdict: "allow" });
|
|
177
246
|
}
|
|
178
247
|
}
|
|
179
248
|
|
|
@@ -192,7 +261,7 @@ export default new ExamplePolicyPlugin();
|
|
|
192
261
|
Add a plugin by setting \`path\` in \`guardio.config.ts\` to a directory that contains \`index.js\` or \`index.mjs\` (compile from \`index.ts\` with \`npm run build\`).
|
|
193
262
|
|
|
194
263
|
- The directory must have \`index.js\` or \`index.mjs\` whose **default export is the plugin instance** (no descriptor).
|
|
195
|
-
- Policy: implement \`PolicyPluginInterface\` (name, evaluate). Config: \`{ "type": "policy", "name": "my-policy", "path": "./plugins/my-policy" }\`.
|
|
264
|
+
- Policy: implement \`PolicyPluginInterface\` (name, evaluate returning Promise<PolicyResult>). Config: \`{ "type": "policy", "name": "my-policy", "path": "./plugins/my-policy" }\`.
|
|
196
265
|
|
|
197
266
|
Import types from "@guardiojs/guardio".${addExamplePlugin ? " See example/ for a policy plugin." : ""}
|
|
198
267
|
`;
|
|
@@ -204,7 +273,10 @@ Import types from "@guardiojs/guardio".${addExamplePlugin ? " See example/ for a
|
|
|
204
273
|
|
|
205
274
|
console.log("\n---\n");
|
|
206
275
|
console.log("Next steps");
|
|
207
|
-
console.log(" cd " + guardioDir
|
|
276
|
+
console.log(" cd " + guardioDir);
|
|
277
|
+
console.log(
|
|
278
|
+
" npm install # or: pnpm install, yarn, bun install, etc.",
|
|
279
|
+
);
|
|
208
280
|
if (addExamplePlugin) {
|
|
209
281
|
console.log(" npm run build # compile plugins (index.ts → index.js)");
|
|
210
282
|
}
|
|
@@ -213,9 +285,9 @@ Import types from "@guardiojs/guardio".${addExamplePlugin ? " See example/ for a
|
|
|
213
285
|
console.log(" npm run guardio");
|
|
214
286
|
console.log("");
|
|
215
287
|
if (installDashboard) {
|
|
216
|
-
console.log("Run dashboard (point
|
|
217
|
-
console.log(" npm run dashboard");
|
|
218
|
-
console.log(" #
|
|
288
|
+
console.log("Run dashboard (standalone copy from GitHub; point at Guardio URL):");
|
|
289
|
+
console.log(" pnpm run dashboard # or: npm run dashboard");
|
|
290
|
+
console.log(" # Guardio base URL: http://127.0.0.1:" + port);
|
|
219
291
|
console.log("");
|
|
220
292
|
}
|
|
221
293
|
console.log("Add to MCP client (use URL):");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-guardio",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.9",
|
|
4
4
|
"description": "Scaffold a Guardio project",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -18,5 +18,8 @@
|
|
|
18
18
|
"agents"
|
|
19
19
|
],
|
|
20
20
|
"author": "Radoslaw Szymkiewicz",
|
|
21
|
-
"license": "Apache-2.0"
|
|
21
|
+
"license": "Apache-2.0",
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"decompress": "^4.2.1"
|
|
24
|
+
}
|
|
22
25
|
}
|