@quint-security/cli 0.1.2

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.
Files changed (52) hide show
  1. package/dist/commands/auth.d.ts +3 -0
  2. package/dist/commands/auth.d.ts.map +1 -0
  3. package/dist/commands/auth.js +87 -0
  4. package/dist/commands/auth.js.map +1 -0
  5. package/dist/commands/http-proxy.d.ts +3 -0
  6. package/dist/commands/http-proxy.d.ts.map +1 -0
  7. package/dist/commands/http-proxy.js +35 -0
  8. package/dist/commands/http-proxy.js.map +1 -0
  9. package/dist/commands/init.d.ts +3 -0
  10. package/dist/commands/init.d.ts.map +1 -0
  11. package/dist/commands/init.js +343 -0
  12. package/dist/commands/init.js.map +1 -0
  13. package/dist/commands/keys.d.ts +3 -0
  14. package/dist/commands/keys.d.ts.map +1 -0
  15. package/dist/commands/keys.js +58 -0
  16. package/dist/commands/keys.js.map +1 -0
  17. package/dist/commands/logs.d.ts +3 -0
  18. package/dist/commands/logs.d.ts.map +1 -0
  19. package/dist/commands/logs.js +50 -0
  20. package/dist/commands/logs.js.map +1 -0
  21. package/dist/commands/policy.d.ts +3 -0
  22. package/dist/commands/policy.d.ts.map +1 -0
  23. package/dist/commands/policy.js +39 -0
  24. package/dist/commands/policy.js.map +1 -0
  25. package/dist/commands/proxy.d.ts +3 -0
  26. package/dist/commands/proxy.d.ts.map +1 -0
  27. package/dist/commands/proxy.js +24 -0
  28. package/dist/commands/proxy.js.map +1 -0
  29. package/dist/commands/status.d.ts +3 -0
  30. package/dist/commands/status.d.ts.map +1 -0
  31. package/dist/commands/status.js +46 -0
  32. package/dist/commands/status.js.map +1 -0
  33. package/dist/commands/verify.d.ts +3 -0
  34. package/dist/commands/verify.d.ts.map +1 -0
  35. package/dist/commands/verify.js +104 -0
  36. package/dist/commands/verify.js.map +1 -0
  37. package/dist/index.d.ts +3 -0
  38. package/dist/index.d.ts.map +1 -0
  39. package/dist/index.js +28 -0
  40. package/dist/index.js.map +1 -0
  41. package/package.json +27 -0
  42. package/src/commands/auth.ts +103 -0
  43. package/src/commands/http-proxy.ts +34 -0
  44. package/src/commands/init.ts +408 -0
  45. package/src/commands/keys.ts +71 -0
  46. package/src/commands/logs.ts +59 -0
  47. package/src/commands/policy.ts +39 -0
  48. package/src/commands/proxy.ts +22 -0
  49. package/src/commands/status.ts +51 -0
  50. package/src/commands/verify.ts +117 -0
  51. package/src/index.ts +29 -0
  52. package/tsconfig.json +12 -0
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.logsCommand = void 0;
4
+ const commander_1 = require("commander");
5
+ const core_1 = require("@quint-security/core");
6
+ exports.logsCommand = new commander_1.Command("logs")
7
+ .description("Search and display the audit log")
8
+ .option("--server <name>", "Filter by server name")
9
+ .option("--tool <name>", "Filter by tool name")
10
+ .option("--denied", "Show only denied entries")
11
+ .option("--since <iso-date>", "Show entries since ISO-8601 date")
12
+ .option("-n, --limit <count>", "Max entries to show", "50")
13
+ .option("--json", "Output as JSON")
14
+ .action((opts) => {
15
+ const policy = (0, core_1.loadPolicy)();
16
+ const dataDir = (0, core_1.resolveDataDir)(policy.data_dir);
17
+ const db = (0, core_1.openAuditDb)(dataDir);
18
+ try {
19
+ const entries = db.query({
20
+ server: opts.server,
21
+ tool: opts.tool,
22
+ verdict: opts.denied ? "deny" : undefined,
23
+ since: opts.since,
24
+ limit: parseInt(opts.limit, 10),
25
+ });
26
+ if (opts.json) {
27
+ console.log(JSON.stringify(entries, null, 2));
28
+ return;
29
+ }
30
+ if (entries.length === 0) {
31
+ console.log("No audit log entries found.");
32
+ return;
33
+ }
34
+ console.log(`Showing ${entries.length} entries (newest first):\n`);
35
+ for (const entry of entries) {
36
+ printEntry(entry);
37
+ }
38
+ }
39
+ finally {
40
+ db.close();
41
+ }
42
+ });
43
+ function printEntry(e) {
44
+ const icon = e.verdict === "deny" ? "✗" : e.verdict === "allow" ? "✓" : "→";
45
+ const ts = e.timestamp.replace("T", " ").replace(/\.\d+Z$/, "Z");
46
+ const tool = e.tool_name ? ` tool=${e.tool_name}` : "";
47
+ const risk = e.risk_score != null ? ` risk=${e.risk_score}(${e.risk_level})` : "";
48
+ console.log(` ${icon} [${ts}] ${e.direction} ${e.method}${tool} server=${e.server_name} verdict=${e.verdict}${risk} id=${e.id}`);
49
+ }
50
+ //# sourceMappingURL=logs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logs.js","sourceRoot":"","sources":["../../src/commands/logs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ export declare const policyCommand: Command;
3
+ //# sourceMappingURL=policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../src/commands/policy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,eAAO,MAAM,aAAa,SACoB,CAAC"}
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.policyCommand = void 0;
4
+ const commander_1 = require("commander");
5
+ const core_1 = require("@quint-security/core");
6
+ exports.policyCommand = new commander_1.Command("policy")
7
+ .description("Manage access control policy");
8
+ exports.policyCommand
9
+ .command("init")
10
+ .description("Create a default policy.json if none exists")
11
+ .action(() => {
12
+ const path = (0, core_1.initPolicy)();
13
+ console.log(`Policy file: ${path}`);
14
+ });
15
+ exports.policyCommand
16
+ .command("validate")
17
+ .description("Validate the current policy.json")
18
+ .action(() => {
19
+ const policy = (0, core_1.loadPolicy)();
20
+ const errors = (0, core_1.validatePolicy)(policy);
21
+ if (errors.length === 0) {
22
+ console.log("Policy is valid.");
23
+ }
24
+ else {
25
+ console.log("Policy validation errors:");
26
+ for (const err of errors) {
27
+ console.log(` - ${err}`);
28
+ }
29
+ process.exit(1);
30
+ }
31
+ });
32
+ exports.policyCommand
33
+ .command("show")
34
+ .description("Display the current policy")
35
+ .action(() => {
36
+ const policy = (0, core_1.loadPolicy)();
37
+ console.log(JSON.stringify(policy, null, 2));
38
+ });
39
+ //# sourceMappingURL=policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/commands/policy.ts"],"names":[],"mappings":";;;AAAA,yCAAoC;AACpC,+CAA8F;AAEjF,QAAA,aAAa,GAAG,IAAI,mBAAO,CAAC,QAAQ,CAAC;KAC/C,WAAW,CAAC,8BAA8B,CAAC,CAAC;AAE/C,qBAAa;KACV,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,6CAA6C,CAAC;KAC1D,MAAM,CAAC,GAAG,EAAE;IACX,MAAM,IAAI,GAAG,IAAA,iBAAU,GAAE,CAAC;IAC1B,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,EAAE,CAAC,CAAC;AACtC,CAAC,CAAC,CAAC;AAEL,qBAAa;KACV,OAAO,CAAC,UAAU,CAAC;KACnB,WAAW,CAAC,kCAAkC,CAAC;KAC/C,MAAM,CAAC,GAAG,EAAE;IACX,MAAM,MAAM,GAAG,IAAA,iBAAU,GAAE,CAAC;IAC5B,MAAM,MAAM,GAAG,IAAA,qBAAc,EAAC,MAAM,CAAC,CAAC;IAEtC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;IAClC,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;QACzC,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;YACzB,OAAO,CAAC,GAAG,CAAC,OAAO,GAAG,EAAE,CAAC,CAAC;QAC5B,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,qBAAa;KACV,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,4BAA4B,CAAC;KACzC,MAAM,CAAC,GAAG,EAAE;IACX,MAAM,MAAM,GAAG,IAAA,iBAAU,GAAE,CAAC;IAC5B,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAC/C,CAAC,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ export declare const proxyCommand: Command;
3
+ //# sourceMappingURL=proxy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../../src/commands/proxy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,eAAO,MAAM,YAAY,SAiBrB,CAAC"}
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.proxyCommand = void 0;
4
+ const commander_1 = require("commander");
5
+ const core_1 = require("@quint-security/core");
6
+ const proxy_1 = require("@quint-security/proxy");
7
+ exports.proxyCommand = new commander_1.Command("proxy")
8
+ .description("Run as MCP stdio proxy wrapping another MCP server")
9
+ .requiredOption("--name <name>", "Name identifier for the proxied server")
10
+ .option("--policy <path>", "Path to policy.json (default: ~/.quint/policy.json)")
11
+ .argument("<command>", "Command to spawn the real MCP server")
12
+ .argument("[args...]", "Arguments for the real MCP server")
13
+ .allowExcessArguments(true)
14
+ .action((command, args, opts) => {
15
+ const policy = (0, core_1.loadPolicy)(opts.policy ? opts.policy : undefined);
16
+ const dataDir = (0, core_1.resolveDataDir)(policy.data_dir);
17
+ (0, proxy_1.startProxy)({
18
+ serverName: opts.name,
19
+ command,
20
+ args,
21
+ policy,
22
+ });
23
+ });
24
+ //# sourceMappingURL=proxy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy.js","sourceRoot":"","sources":["../../src/commands/proxy.ts"],"names":[],"mappings":";;;AAAA,yCAAoC;AACpC,+CAAkE;AAClE,iDAAmD;AAEtC,QAAA,YAAY,GAAG,IAAI,mBAAO,CAAC,OAAO,CAAC;KAC7C,WAAW,CAAC,oDAAoD,CAAC;KACjE,cAAc,CAAC,eAAe,EAAE,wCAAwC,CAAC;KACzE,MAAM,CAAC,iBAAiB,EAAE,qDAAqD,CAAC;KAChF,QAAQ,CAAC,WAAW,EAAE,sCAAsC,CAAC;KAC7D,QAAQ,CAAC,WAAW,EAAE,mCAAmC,CAAC;KAC1D,oBAAoB,CAAC,IAAI,CAAC;KAC1B,MAAM,CAAC,CAAC,OAAe,EAAE,IAAc,EAAE,IAAuC,EAAE,EAAE;IACnF,MAAM,MAAM,GAAG,IAAA,iBAAU,EAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IACjE,MAAM,OAAO,GAAG,IAAA,qBAAc,EAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAEhD,IAAA,kBAAU,EAAC;QACT,UAAU,EAAE,IAAI,CAAC,IAAI;QACrB,OAAO;QACP,IAAI;QACJ,MAAM;KACP,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ export declare const statusCommand: Command;
3
+ //# sourceMappingURL=status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAWpC,eAAO,MAAM,aAAa,SAuCtB,CAAC"}
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.statusCommand = void 0;
4
+ const commander_1 = require("commander");
5
+ const core_1 = require("@quint-security/core");
6
+ const node_fs_1 = require("node:fs");
7
+ const node_path_1 = require("node:path");
8
+ exports.statusCommand = new commander_1.Command("status")
9
+ .description("Show Quint configuration summary")
10
+ .action(() => {
11
+ const policy = (0, core_1.loadPolicy)();
12
+ const dataDir = (0, core_1.resolveDataDir)(policy.data_dir);
13
+ console.log("Quint Status");
14
+ console.log("============");
15
+ console.log(` Data dir: ${dataDir}`);
16
+ console.log(` Policy: ${(0, node_path_1.join)(dataDir, "policy.json")} ${(0, node_fs_1.existsSync)((0, node_path_1.join)(dataDir, "policy.json")) ? "(found)" : "(not found)"}`);
17
+ console.log(` Log level: ${policy.log_level}`);
18
+ // Keys
19
+ const kp = (0, core_1.loadKeyPair)(dataDir);
20
+ if (kp) {
21
+ console.log(` Keys: ${(0, core_1.publicKeyFingerprint)(kp.publicKey)} (loaded)`);
22
+ }
23
+ else {
24
+ console.log(` Keys: not generated (run \`quint keys generate\`)`);
25
+ }
26
+ // Database
27
+ const dbPath = (0, node_path_1.join)(dataDir, "quint.db");
28
+ if ((0, node_fs_1.existsSync)(dbPath)) {
29
+ const db = (0, core_1.openAuditDb)(dataDir);
30
+ const count = db.count();
31
+ db.close();
32
+ console.log(` Database: ${dbPath} (${count} entries)`);
33
+ }
34
+ else {
35
+ console.log(` Database: not created yet`);
36
+ }
37
+ // Servers
38
+ console.log(`\n Servers (${policy.servers.length}):`);
39
+ for (const srv of policy.servers) {
40
+ const toolRules = srv.tools.length > 0
41
+ ? srv.tools.map(t => `${t.tool}:${t.action}`).join(", ")
42
+ : "no tool-specific rules";
43
+ console.log(` ${srv.server} → default:${srv.default_action} [${toolRules}]`);
44
+ }
45
+ });
46
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":";;;AAAA,yCAAoC;AACpC,+CAM8B;AAC9B,qCAAqC;AACrC,yCAAiC;AAEpB,QAAA,aAAa,GAAG,IAAI,mBAAO,CAAC,QAAQ,CAAC;KAC/C,WAAW,CAAC,kCAAkC,CAAC;KAC/C,MAAM,CAAC,GAAG,EAAE;IACX,MAAM,MAAM,GAAG,IAAA,iBAAU,GAAE,CAAC;IAC5B,MAAM,OAAO,GAAG,IAAA,qBAAc,EAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAEhD,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAC5B,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAC5B,OAAO,CAAC,GAAG,CAAC,kBAAkB,OAAO,EAAE,CAAC,CAAC;IACzC,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAA,gBAAI,EAAC,OAAO,EAAE,aAAa,CAAC,IAAI,IAAA,oBAAU,EAAC,IAAA,gBAAI,EAAC,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC,CAAC;IACtI,OAAO,CAAC,GAAG,CAAC,kBAAkB,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;IAElD,OAAO;IACP,MAAM,EAAE,GAAG,IAAA,kBAAW,EAAC,OAAO,CAAC,CAAC;IAChC,IAAI,EAAE,EAAE,CAAC;QACP,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAA,2BAAoB,EAAC,EAAE,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IAC/E,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,4DAA4D,CAAC,CAAC;IAC5E,CAAC;IAED,WAAW;IACX,MAAM,MAAM,GAAG,IAAA,gBAAI,EAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IACzC,IAAI,IAAA,oBAAU,EAAC,MAAM,CAAC,EAAE,CAAC;QACvB,MAAM,EAAE,GAAG,IAAA,kBAAW,EAAC,OAAO,CAAC,CAAC;QAChC,MAAM,KAAK,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC;QACzB,EAAE,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,GAAG,CAAC,kBAAkB,MAAM,KAAK,KAAK,WAAW,CAAC,CAAC;IAC7D,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;IAChD,CAAC;IAED,UAAU;IACV,OAAO,CAAC,GAAG,CAAC,gBAAgB,MAAM,CAAC,OAAO,CAAC,MAAM,IAAI,CAAC,CAAC;IACvD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACjC,MAAM,SAAS,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC;YACpC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;YACxD,CAAC,CAAC,wBAAwB,CAAC;QAC7B,OAAO,CAAC,GAAG,CAAC,OAAO,GAAG,CAAC,MAAM,cAAc,GAAG,CAAC,cAAc,KAAK,SAAS,GAAG,CAAC,CAAC;IAClF,CAAC;AACH,CAAC,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ export declare const verifyCommand: Command;
3
+ //# sourceMappingURL=verify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../src/commands/verify.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAWpC,eAAO,MAAM,aAAa,SAkFtB,CAAC"}
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.verifyCommand = void 0;
4
+ const commander_1 = require("commander");
5
+ const core_1 = require("@quint-security/core");
6
+ exports.verifyCommand = new commander_1.Command("verify")
7
+ .description("Verify Ed25519 signatures and hash chain on audit log entries")
8
+ .option("--id <n>", "Verify a specific entry by ID")
9
+ .option("--last <n>", "Verify the last N entries", "20")
10
+ .option("--all", "Verify all entries")
11
+ .option("--chain", "Also verify hash chain integrity (requires --all or --last)")
12
+ .action((opts) => {
13
+ const policy = (0, core_1.loadPolicy)();
14
+ const dataDir = (0, core_1.resolveDataDir)(policy.data_dir);
15
+ const db = (0, core_1.openAuditDb)(dataDir);
16
+ try {
17
+ let entries;
18
+ if (opts.id) {
19
+ const entry = db.getById(parseInt(opts.id, 10));
20
+ entries = entry ? [entry] : [];
21
+ }
22
+ else if (opts.all) {
23
+ entries = db.getAll(); // ascending order for chain verification
24
+ }
25
+ else {
26
+ entries = db.getLast(parseInt(opts.last, 10));
27
+ // Reverse to ascending for chain verification
28
+ entries.reverse();
29
+ }
30
+ if (entries.length === 0) {
31
+ console.log("No entries to verify.");
32
+ return;
33
+ }
34
+ // Signature verification
35
+ let sigValid = 0;
36
+ let sigInvalid = 0;
37
+ for (const entry of entries) {
38
+ const ok = verifyEntry(entry);
39
+ if (ok) {
40
+ sigValid++;
41
+ }
42
+ else {
43
+ sigInvalid++;
44
+ console.log(` ✗ INVALID signature on entry #${entry.id} (${entry.timestamp})`);
45
+ }
46
+ }
47
+ console.log(`\nSignatures: ${entries.length} checked, ${sigValid} valid, ${sigInvalid} invalid`);
48
+ // Hash chain verification
49
+ if (opts.chain || opts.all) {
50
+ let chainValid = 0;
51
+ let chainBroken = 0;
52
+ for (let i = 1; i < entries.length; i++) {
53
+ const prev = entries[i - 1];
54
+ const curr = entries[i];
55
+ if (curr.prev_hash === "" && prev.prev_hash === "") {
56
+ // Legacy entries without hash chain — skip
57
+ continue;
58
+ }
59
+ const expectedHash = (0, core_1.sha256)(prev.signature);
60
+ if (curr.prev_hash === expectedHash) {
61
+ chainValid++;
62
+ }
63
+ else {
64
+ chainBroken++;
65
+ console.log(` ⛓ BROKEN chain at entry #${curr.id} — prev_hash doesn't match entry #${prev.id}`);
66
+ }
67
+ }
68
+ if (chainValid + chainBroken > 0) {
69
+ console.log(`Chain: ${chainValid + chainBroken} links checked, ${chainValid} valid, ${chainBroken} broken`);
70
+ }
71
+ else {
72
+ console.log(`Chain: no chain data (legacy entries)`);
73
+ }
74
+ }
75
+ if (sigInvalid > 0) {
76
+ process.exit(1);
77
+ }
78
+ }
79
+ finally {
80
+ db.close();
81
+ }
82
+ });
83
+ function verifyEntry(entry) {
84
+ const signable = {
85
+ timestamp: entry.timestamp,
86
+ server_name: entry.server_name,
87
+ direction: entry.direction,
88
+ method: entry.method,
89
+ message_id: entry.message_id,
90
+ tool_name: entry.tool_name,
91
+ arguments_json: entry.arguments_json,
92
+ response_json: entry.response_json,
93
+ verdict: entry.verdict,
94
+ risk_score: entry.risk_score ?? null,
95
+ risk_level: entry.risk_level ?? null,
96
+ policy_hash: entry.policy_hash ?? "",
97
+ prev_hash: entry.prev_hash ?? "",
98
+ nonce: entry.nonce ?? "",
99
+ public_key: entry.public_key,
100
+ };
101
+ const canonical = (0, core_1.canonicalize)(signable);
102
+ return (0, core_1.verifySignature)(canonical, entry.signature, entry.public_key);
103
+ }
104
+ //# sourceMappingURL=verify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/commands/verify.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const commander_1 = require("commander");
5
+ const proxy_js_1 = require("./commands/proxy.js");
6
+ const http_proxy_js_1 = require("./commands/http-proxy.js");
7
+ const logs_js_1 = require("./commands/logs.js");
8
+ const keys_js_1 = require("./commands/keys.js");
9
+ const verify_js_1 = require("./commands/verify.js");
10
+ const policy_js_1 = require("./commands/policy.js");
11
+ const status_js_1 = require("./commands/status.js");
12
+ const auth_js_1 = require("./commands/auth.js");
13
+ const init_js_1 = require("./commands/init.js");
14
+ const program = new commander_1.Command()
15
+ .name("quint")
16
+ .version("0.1.0")
17
+ .description("Local security proxy for MCP tool calls");
18
+ program.addCommand(init_js_1.initCommand);
19
+ program.addCommand(proxy_js_1.proxyCommand);
20
+ program.addCommand(http_proxy_js_1.httpProxyCommand);
21
+ program.addCommand(logs_js_1.logsCommand);
22
+ program.addCommand(keys_js_1.keysCommand);
23
+ program.addCommand(verify_js_1.verifyCommand);
24
+ program.addCommand(policy_js_1.policyCommand);
25
+ program.addCommand(status_js_1.statusCommand);
26
+ program.addCommand(auth_js_1.authCommand);
27
+ program.parse();
28
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAEA,yCAAoC;AACpC,kDAAmD;AACnD,4DAA4D;AAC5D,gDAAiD;AACjD,gDAAiD;AACjD,oDAAqD;AACrD,oDAAqD;AACrD,oDAAqD;AACrD,gDAAiD;AACjD,gDAAiD;AAEjD,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE;KAC1B,IAAI,CAAC,OAAO,CAAC;KACb,OAAO,CAAC,OAAO,CAAC;KAChB,WAAW,CAAC,yCAAyC,CAAC,CAAC;AAE1D,OAAO,CAAC,UAAU,CAAC,qBAAW,CAAC,CAAC;AAChC,OAAO,CAAC,UAAU,CAAC,uBAAY,CAAC,CAAC;AACjC,OAAO,CAAC,UAAU,CAAC,gCAAgB,CAAC,CAAC;AACrC,OAAO,CAAC,UAAU,CAAC,qBAAW,CAAC,CAAC;AAChC,OAAO,CAAC,UAAU,CAAC,qBAAW,CAAC,CAAC;AAChC,OAAO,CAAC,UAAU,CAAC,yBAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,yBAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,yBAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,qBAAW,CAAC,CAAC;AAEhC,OAAO,CAAC,KAAK,EAAE,CAAC"}
package/package.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "@quint-security/cli",
3
+ "version": "0.1.2",
4
+ "bin": {
5
+ "quint": "dist/index.js"
6
+ },
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/Quint-Security/cli.git",
10
+ "directory": "packages/cli"
11
+ },
12
+ "publishConfig": {
13
+ "access": "public"
14
+ },
15
+ "scripts": {
16
+ "build": "tsc"
17
+ },
18
+ "dependencies": {
19
+ "@quint-security/core": "*",
20
+ "@quint-security/proxy": "*",
21
+ "commander": "^12.0.0"
22
+ },
23
+ "devDependencies": {
24
+ "@types/node": "^20.0.0",
25
+ "typescript": "^5.4.0"
26
+ }
27
+ }
@@ -0,0 +1,103 @@
1
+ import { Command } from "commander";
2
+ import {
3
+ loadPolicy,
4
+ resolveDataDir,
5
+ openAuthDb,
6
+ generateApiKey,
7
+ } from "@quint-security/core";
8
+
9
+ export const authCommand = new Command("auth")
10
+ .description("Manage authentication (API keys and sessions)");
11
+
12
+ authCommand
13
+ .command("create-key")
14
+ .description("Create a new API key")
15
+ .requiredOption("--label <name>", "Human-readable label for the key")
16
+ .option("--scopes <scopes>", "Comma-separated scopes (e.g. proxy:read,audit:write)")
17
+ .option("--ttl <seconds>", "Time-to-live in seconds (0 = no expiry)", "0")
18
+ .action((opts: { label: string; scopes?: string; ttl: string }) => {
19
+ const policy = loadPolicy();
20
+ const dataDir = resolveDataDir(policy.data_dir);
21
+ const db = openAuthDb(dataDir);
22
+
23
+ const scopes = opts.scopes ? opts.scopes.split(",").map((s) => s.trim()) : [];
24
+ const ttl = parseInt(opts.ttl, 10);
25
+
26
+ const { rawKey, apiKey } = generateApiKey(db, {
27
+ label: opts.label,
28
+ scopes,
29
+ ttlSeconds: ttl > 0 ? ttl : undefined,
30
+ });
31
+
32
+ console.log(`API key created.\n`);
33
+ console.log(` ID: ${apiKey.id}`);
34
+ console.log(` Label: ${apiKey.label}`);
35
+ console.log(` Scopes: ${apiKey.scopes || "(all)"}`);
36
+ console.log(` Expires: ${apiKey.expires_at ?? "never"}`);
37
+ console.log(`\n Raw key (SAVE THIS — shown only once):\n`);
38
+ console.log(` ${rawKey}\n`);
39
+
40
+ db.close();
41
+ });
42
+
43
+ authCommand
44
+ .command("list-keys")
45
+ .description("List all API keys")
46
+ .action(() => {
47
+ const policy = loadPolicy();
48
+ const dataDir = resolveDataDir(policy.data_dir);
49
+ const db = openAuthDb(dataDir);
50
+
51
+ const keys = db.listApiKeys();
52
+ if (keys.length === 0) {
53
+ console.log("No API keys found. Create one with `quint auth create-key`.");
54
+ db.close();
55
+ return;
56
+ }
57
+
58
+ console.log(`${keys.length} API key(s):\n`);
59
+ for (const key of keys) {
60
+ const status = key.revoked
61
+ ? "REVOKED"
62
+ : key.expires_at && new Date(key.expires_at) < new Date()
63
+ ? "EXPIRED"
64
+ : "active";
65
+ const icon = status === "active" ? "●" : "○";
66
+ console.log(` ${icon} ${key.id} ${key.label} [${status}] scopes=${key.scopes || "*"} created=${key.created_at}`);
67
+ }
68
+
69
+ db.close();
70
+ });
71
+
72
+ authCommand
73
+ .command("revoke-key")
74
+ .description("Revoke an API key")
75
+ .requiredOption("--id <id>", "API key ID to revoke")
76
+ .action((opts: { id: string }) => {
77
+ const policy = loadPolicy();
78
+ const dataDir = resolveDataDir(policy.data_dir);
79
+ const db = openAuthDb(dataDir);
80
+
81
+ const key = db.getApiKeyById(opts.id);
82
+ if (!key) {
83
+ console.error(`API key not found: ${opts.id}`);
84
+ db.close();
85
+ process.exit(1);
86
+ }
87
+
88
+ if (key.revoked) {
89
+ console.log(`Key ${opts.id} is already revoked.`);
90
+ db.close();
91
+ return;
92
+ }
93
+
94
+ db.revokeApiKey(opts.id);
95
+ // Also revoke any sessions issued to this key
96
+ const revoked = db.revokeSessionsBySubject(opts.id);
97
+ console.log(`Revoked key ${opts.id} (${key.label}).`);
98
+ if (revoked > 0) {
99
+ console.log(` Also revoked ${revoked} active session(s).`);
100
+ }
101
+
102
+ db.close();
103
+ });
@@ -0,0 +1,34 @@
1
+ import { Command } from "commander";
2
+ import { loadPolicy } from "@quint-security/core";
3
+ import { startHttpProxy } from "@quint-security/proxy";
4
+
5
+ export const httpProxyCommand = new Command("http-proxy")
6
+ .description("Run as HTTP proxy in front of a remote MCP server")
7
+ .requiredOption("--name <name>", "Name identifier for the proxied server")
8
+ .requiredOption("--port <port>", "Local port to listen on", parseInt)
9
+ .requiredOption("--target <url>", "Remote MCP server URL to proxy to")
10
+ .option("--policy <path>", "Path to policy.json (default: ~/.quint/policy.json)")
11
+ .option("--require-auth", "Require API key authentication on all requests")
12
+ .action(async (opts: { name: string; port: number; target: string; policy?: string; requireAuth?: boolean }) => {
13
+ if (isNaN(opts.port) || opts.port < 1 || opts.port > 65535) {
14
+ process.stderr.write("quint: --port must be a valid port number (1-65535)\n");
15
+ process.exit(1);
16
+ }
17
+
18
+ try {
19
+ new URL(opts.target);
20
+ } catch {
21
+ process.stderr.write(`quint: --target must be a valid URL\n`);
22
+ process.exit(1);
23
+ }
24
+
25
+ const policy = loadPolicy(opts.policy ? opts.policy : undefined);
26
+
27
+ await startHttpProxy({
28
+ serverName: opts.name,
29
+ port: opts.port,
30
+ targetUrl: opts.target,
31
+ policy,
32
+ requireAuth: opts.requireAuth,
33
+ });
34
+ });