mneme-ai 3.1.0 → 3.2.0
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.
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `mneme skillscan` (v3.2.0) — the signed provenance gate for AI agent skills / MCP tools.
|
|
3
|
+
* Scan a skill (a file or a directory) against the 8-point checklist, pin it by content hash,
|
|
4
|
+
* and (optionally) mint a NOTARY (Ed25519) provenance receipt that anyone verifies OFFLINE.
|
|
5
|
+
* skillscan <path> [--sign] [--out receipt.json] [--json]
|
|
6
|
+
* skillscan verify <receipt.json> [--path <skill>] (also re-hashes the skill if --path given)
|
|
7
|
+
*/
|
|
8
|
+
import type { Command } from "commander";
|
|
9
|
+
export declare function registerSkillscanCommands(program: Command): void;
|
|
10
|
+
//# sourceMappingURL=skillscan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skillscan.d.ts","sourceRoot":"","sources":["../../src/commands/skillscan.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA6BzC,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAyChE"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync, statSync, readdirSync } from "node:fs";
|
|
2
|
+
import { join, extname, basename } from "node:path";
|
|
3
|
+
import { skillscan, notary } from "@mneme-ai/core";
|
|
4
|
+
function out(s) { process.stdout.write(s + "\n"); }
|
|
5
|
+
const SKILL_EXT = new Set([".md", ".markdown", ".json", ".mjs", ".cjs", ".js", ".ts", ".txt", ".yaml", ".yml", ".toml", ".sh", ".py"]);
|
|
6
|
+
/** Read a skill's text: a single file, or concatenate the skill-ish files in a directory (≤512KB). */
|
|
7
|
+
function readSkill(path) {
|
|
8
|
+
if (!existsSync(path))
|
|
9
|
+
return { text: "", files: [] };
|
|
10
|
+
const st = statSync(path);
|
|
11
|
+
if (st.isFile())
|
|
12
|
+
return { text: readFileSync(path, "utf8"), files: [path] };
|
|
13
|
+
const parts = [];
|
|
14
|
+
const files = [];
|
|
15
|
+
let total = 0;
|
|
16
|
+
const walk = (dir, depth) => {
|
|
17
|
+
if (depth > 3 || total > 512_000)
|
|
18
|
+
return;
|
|
19
|
+
for (const e of readdirSync(dir, { withFileTypes: true })) {
|
|
20
|
+
if (e.name === "node_modules" || e.name.startsWith(".git"))
|
|
21
|
+
continue;
|
|
22
|
+
const p = join(dir, e.name);
|
|
23
|
+
if (e.isDirectory())
|
|
24
|
+
walk(p, depth + 1);
|
|
25
|
+
else if (SKILL_EXT.has(extname(e.name).toLowerCase()) && total < 512_000) {
|
|
26
|
+
try {
|
|
27
|
+
const c = readFileSync(p, "utf8");
|
|
28
|
+
parts.push(`\n# ── ${e.name} ──\n${c}`);
|
|
29
|
+
files.push(p);
|
|
30
|
+
total += c.length;
|
|
31
|
+
}
|
|
32
|
+
catch { /* */ }
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
walk(path, 0);
|
|
37
|
+
return { text: parts.join("\n"), files };
|
|
38
|
+
}
|
|
39
|
+
export function registerSkillscanCommands(program) {
|
|
40
|
+
const k = program.command("skillscan").description("🛂 SKILLSCAN — the signed provenance gate for AI agent skills / MCP tools: 8-point static scan (prompt-injection · exfiltration · secret · dangerous-command · obfuscation · external-fetch · credential-access · privilege-escalation) + a content-hash + an offline-verifiable NOTARY receipt. The supply-chain frontier, local-first.");
|
|
41
|
+
k.command("scan <path>", { isDefault: true }).description("Scan a skill file/dir; optionally mint a signed provenance receipt.")
|
|
42
|
+
.option("--sign", "mint a NOTARY-signed provenance receipt").option("--out <file>", "write the receipt JSON").option("--json", "emit the full result as JSON")
|
|
43
|
+
.action((path, o) => {
|
|
44
|
+
const { text, files } = readSkill(path);
|
|
45
|
+
if (!text.trim()) {
|
|
46
|
+
out(`✗ nothing to scan at ${path}`);
|
|
47
|
+
process.exitCode = 2;
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const r = skillscan.scanSkill(text);
|
|
51
|
+
const subject = `skill:${basename(path)}`;
|
|
52
|
+
let receipt = null;
|
|
53
|
+
if (o.sign || o.out) {
|
|
54
|
+
try {
|
|
55
|
+
receipt = notary.issueReceipt(process.cwd(), { kind: "skill-provenance", subject, payload: { contentHash: r.contentHash, bytes: r.bytes, verdict: r.verdict, hits: r.hits, files: files.length }, includePayload: true, issuedAt: Date.now() });
|
|
56
|
+
}
|
|
57
|
+
catch { /* */ }
|
|
58
|
+
if (o.out && receipt)
|
|
59
|
+
writeFileSync(o.out, JSON.stringify(receipt, null, 2), "utf8");
|
|
60
|
+
}
|
|
61
|
+
if (o.json) {
|
|
62
|
+
out(JSON.stringify({ result: r, receipt }, null, 2));
|
|
63
|
+
if (r.verdict === "BLOCK")
|
|
64
|
+
process.exitCode = 2;
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const icon = r.verdict === "BLOCK" ? "🔴" : r.verdict === "REVIEW" ? "🟡" : "🟢";
|
|
68
|
+
out(`🛂 SKILLSCAN — ${icon} ${r.verdict} · ${files.length} file(s) · ${r.bytes}B · sha256 ${r.contentHash.slice(0, 16)}…`);
|
|
69
|
+
for (const h of r.hits)
|
|
70
|
+
out(` 🚩 ${h.id} (${h.severity})${h.evidence ? " " + h.evidence : ""}`);
|
|
71
|
+
if (!r.hits.length)
|
|
72
|
+
out(" ✓ no risk-class hits across the 8-point checklist");
|
|
73
|
+
if (receipt)
|
|
74
|
+
out(` 🪪 signed provenance receipt${o.out ? " → " + o.out : ""} (verify offline: mneme skillscan verify)`);
|
|
75
|
+
if (r.verdict === "BLOCK")
|
|
76
|
+
process.exitCode = 2;
|
|
77
|
+
});
|
|
78
|
+
k.command("verify <receipt>").description("Verify a provenance receipt OFFLINE (Ed25519); with --path, re-hash the skill to confirm it's unchanged.")
|
|
79
|
+
.option("--path <skill>", "re-scan this skill and confirm its content-hash matches the receipt")
|
|
80
|
+
.action((receiptFile, o) => {
|
|
81
|
+
if (!existsSync(receiptFile)) {
|
|
82
|
+
out("receipt not found");
|
|
83
|
+
process.exitCode = 2;
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
let receipt;
|
|
87
|
+
try {
|
|
88
|
+
receipt = JSON.parse(readFileSync(receiptFile, "utf8"));
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
out("✗ invalid receipt JSON");
|
|
92
|
+
process.exitCode = 2;
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const v = notary.verifyReceipt(receipt);
|
|
96
|
+
out(v.valid ? "✓ signature VALID (Ed25519, offline)" : `✗ signature INVALID: ${v.reason}`);
|
|
97
|
+
if (v.valid && receipt.payload)
|
|
98
|
+
out(` verdict at signing: ${receipt.payload.verdict} · pinned sha256 ${String(receipt.payload.contentHash).slice(0, 16)}…`);
|
|
99
|
+
if (o.path && receipt.payload?.contentHash) {
|
|
100
|
+
const now = skillscan.scanSkill(readSkill(o.path).text);
|
|
101
|
+
const match = now.contentHash === receipt.payload.contentHash;
|
|
102
|
+
out(match ? " ✓ content UNCHANGED since signing (hash matches)" : " ⚠ content CHANGED since signing — receipt does NOT cover the current skill!");
|
|
103
|
+
if (!match)
|
|
104
|
+
process.exitCode = 2;
|
|
105
|
+
}
|
|
106
|
+
if (!v.valid)
|
|
107
|
+
process.exitCode = 2;
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=skillscan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skillscan.js","sourceRoot":"","sources":["../../src/commands/skillscan.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA6LA,wBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA6lNvD"}
|
package/dist/index.js
CHANGED
|
@@ -106,6 +106,7 @@ import { registerSuccessionCommands } from "./commands/succession.js";
|
|
|
106
106
|
import { registerPagerCommands } from "./commands/pager.js";
|
|
107
107
|
import { registerKeryxCommands } from "./commands/keryx.js";
|
|
108
108
|
import { registerCompileCommands } from "./commands/compile.js";
|
|
109
|
+
import { registerSkillscanCommands } from "./commands/skillscan.js";
|
|
109
110
|
import { registerAdamasCommands } from "./commands/adamas.js";
|
|
110
111
|
import { registerPrismCommands } from "./commands/prism.js";
|
|
111
112
|
import { registerGoldilocksCommands } from "./commands/goldilocks.js";
|
|
@@ -4779,6 +4780,7 @@ export async function run(argv) {
|
|
|
4779
4780
|
registerPagerCommands(program);
|
|
4780
4781
|
registerKeryxCommands(program);
|
|
4781
4782
|
registerCompileCommands(program);
|
|
4783
|
+
registerSkillscanCommands(program);
|
|
4782
4784
|
registerAdamasCommands(program);
|
|
4783
4785
|
registerPrismCommands(program);
|
|
4784
4786
|
registerGoldilocksCommands(program);
|