@weave_protocol/mund 0.2.3 → 0.3.1
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/README.md +135 -1
- package/dist/analyzers/code-analyzer.d.ts.map +1 -1
- package/dist/analyzers/code-analyzer.js +2 -1
- package/dist/analyzers/code-analyzer.js.map +1 -1
- package/dist/analyzers/exfiltration-detector.d.ts.map +1 -1
- package/dist/analyzers/exfiltration-detector.js +2 -1
- package/dist/analyzers/exfiltration-detector.js.map +1 -1
- package/dist/analyzers/index.d.ts.map +1 -1
- package/dist/analyzers/index.js +4 -2
- package/dist/analyzers/index.js.map +1 -1
- package/dist/analyzers/injection-detector.d.ts.map +1 -1
- package/dist/analyzers/injection-detector.js +2 -1
- package/dist/analyzers/injection-detector.js.map +1 -1
- package/dist/analyzers/mcp-server-analyzer.d.ts +2 -0
- package/dist/analyzers/mcp-server-analyzer.d.ts.map +1 -1
- package/dist/analyzers/mcp-server-analyzer.js.map +1 -1
- package/dist/analyzers/pii-detector.d.ts.map +1 -1
- package/dist/analyzers/pii-detector.js +2 -1
- package/dist/analyzers/pii-detector.js.map +1 -1
- package/dist/analyzers/regex.d.ts +10 -0
- package/dist/analyzers/regex.d.ts.map +1 -0
- package/dist/analyzers/regex.js +17 -0
- package/dist/analyzers/regex.js.map +1 -0
- package/dist/analyzers/secret-scanner.d.ts.map +1 -1
- package/dist/analyzers/secret-scanner.js +2 -1
- package/dist/analyzers/secret-scanner.js.map +1 -1
- package/dist/canary.d.ts +48 -0
- package/dist/canary.d.ts.map +1 -0
- package/dist/canary.js +149 -0
- package/dist/canary.js.map +1 -0
- package/dist/cli/scan.d.ts +50 -0
- package/dist/cli/scan.d.ts.map +1 -0
- package/dist/cli/scan.js +235 -0
- package/dist/cli/scan.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -4
- package/dist/index.js.map +1 -1
- package/dist/notifications/email.d.ts +21 -8
- package/dist/notifications/email.d.ts.map +1 -1
- package/dist/notifications/email.js +32 -178
- package/dist/notifications/email.js.map +1 -1
- package/dist/osv.d.ts +94 -0
- package/dist/osv.d.ts.map +1 -0
- package/dist/osv.js +239 -0
- package/dist/osv.js.map +1 -0
- package/dist/rugpull.d.ts +73 -0
- package/dist/rugpull.d.ts.map +1 -0
- package/dist/rugpull.js +177 -0
- package/dist/rugpull.js.map +1 -0
- package/dist/sarif.d.ts +20 -0
- package/dist/sarif.d.ts.map +1 -0
- package/dist/sarif.js +122 -0
- package/dist/sarif.js.map +1 -0
- package/dist/scoring.d.ts +26 -0
- package/dist/scoring.d.ts.map +1 -0
- package/dist/scoring.js +49 -0
- package/dist/scoring.js.map +1 -0
- package/dist/threat-intel-manager.d.ts.map +1 -1
- package/dist/threat-intel-manager.js +2 -1
- package/dist/threat-intel-manager.js.map +1 -1
- package/dist/tools/canary-rugpull.d.ts +7 -0
- package/dist/tools/canary-rugpull.d.ts.map +1 -0
- package/dist/tools/canary-rugpull.js +50 -0
- package/dist/tools/canary-rugpull.js.map +1 -0
- package/dist/tools/configuration.d.ts.map +1 -1
- package/dist/tools/configuration.js +2 -1
- package/dist/tools/configuration.js.map +1 -1
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +4 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/mcp-scanning.d.ts.map +1 -1
- package/dist/tools/mcp-scanning.js +4 -0
- package/dist/tools/mcp-scanning.js.map +1 -1
- package/dist/tools/monitoring.d.ts.map +1 -1
- package/dist/tools/monitoring.js +22 -1
- package/dist/tools/monitoring.js.map +1 -1
- package/dist/version.d.ts +6 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +19 -0
- package/dist/version.js.map +1 -0
- package/package.json +2 -4
- package/src/analyzers/code-analyzer.ts +2 -1
- package/src/analyzers/exfiltration-detector.ts +2 -1
- package/src/analyzers/index.ts +4 -2
- package/src/analyzers/injection-detector.ts +2 -1
- package/src/analyzers/mcp-server-analyzer.ts +2 -0
- package/src/analyzers/pii-detector.ts +2 -1
- package/src/analyzers/regex.ts +17 -0
- package/src/analyzers/secret-scanner.ts +2 -1
- package/src/canary.ts +165 -0
- package/src/cli/scan.ts +260 -0
- package/src/index.ts +13 -4
- package/src/notifications/email.ts +38 -194
- package/src/osv.ts +310 -0
- package/src/rugpull.ts +233 -0
- package/src/sarif.ts +146 -0
- package/src/scoring.ts +64 -0
- package/src/threat-intel-manager.ts +2 -1
- package/src/tools/canary-rugpull.ts +75 -0
- package/src/tools/configuration.ts +2 -1
- package/src/tools/index.ts +5 -0
- package/src/tools/mcp-scanning.ts +5 -0
- package/src/tools/monitoring.ts +23 -1
- package/src/version.ts +20 -0
- package/tests/analyzers/engine.test.ts +60 -0
- package/tests/analyzers/injection-and-code.test.ts +80 -0
- package/tests/analyzers/mcp-server-analyzer.test.ts +82 -0
- package/tests/analyzers/regex.test.ts +35 -0
- package/tests/analyzers/rules.test.ts +54 -0
- package/tests/analyzers/secret-scanner.test.ts +80 -0
- package/tests/canary.test.ts +79 -0
- package/tests/cli/scan.test.ts +92 -0
- package/tests/fixtures/canary/base64.json +9 -0
- package/tests/fixtures/canary/clean-output.json +8 -0
- package/tests/fixtures/canary/exact-leak.json +9 -0
- package/tests/fixtures/canary/lowercased.json +9 -0
- package/tests/fixtures/canary/other-token.json +8 -0
- package/tests/fixtures/canary/prefix-only.json +8 -0
- package/tests/fixtures/canary/reversed.json +9 -0
- package/tests/fixtures/canary/spaced-out.json +9 -0
- package/tests/fixtures/canary/zero-width.json +9 -0
- package/tests/fixtures/rugpull/description-changed/baseline.json +36 -0
- package/tests/fixtures/rugpull/description-changed/current.json +36 -0
- package/tests/fixtures/rugpull/description-changed/expected.json +11 -0
- package/tests/fixtures/rugpull/gains-execution/baseline.json +36 -0
- package/tests/fixtures/rugpull/gains-execution/current.json +36 -0
- package/tests/fixtures/rugpull/gains-execution/expected.json +18 -0
- package/tests/fixtures/rugpull/schema-changed/baseline.json +36 -0
- package/tests/fixtures/rugpull/schema-changed/current.json +39 -0
- package/tests/fixtures/rugpull/schema-changed/expected.json +11 -0
- package/tests/fixtures/rugpull/schema-key-reorder/baseline.json +36 -0
- package/tests/fixtures/rugpull/schema-key-reorder/current.json +36 -0
- package/tests/fixtures/rugpull/schema-key-reorder/expected.json +5 -0
- package/tests/fixtures/rugpull/server-renamed/baseline.json +36 -0
- package/tests/fixtures/rugpull/server-renamed/current.json +36 -0
- package/tests/fixtures/rugpull/server-renamed/expected.json +11 -0
- package/tests/fixtures/rugpull/tool-added/baseline.json +36 -0
- package/tests/fixtures/rugpull/tool-added/current.json +44 -0
- package/tests/fixtures/rugpull/tool-added/expected.json +11 -0
- package/tests/fixtures/rugpull/tool-removed/baseline.json +36 -0
- package/tests/fixtures/rugpull/tool-removed/current.json +21 -0
- package/tests/fixtures/rugpull/tool-removed/expected.json +11 -0
- package/tests/fixtures/rugpull/unchanged/baseline.json +36 -0
- package/tests/fixtures/rugpull/unchanged/current.json +36 -0
- package/tests/fixtures/rugpull/unchanged/expected.json +5 -0
- package/tests/fixtures.test.ts +40 -0
- package/tests/helpers.ts +51 -0
- package/tests/notifications/email.test.ts +68 -0
- package/tests/notifications/hub.test.ts +160 -0
- package/tests/osv.test.ts +117 -0
- package/tests/rugpull.test.ts +80 -0
- package/tests/sarif.test.ts +59 -0
- package/tests/scoring.test.ts +49 -0
- package/tests/tools/canary-rugpull.test.ts +57 -0
- package/tests/tools/monitoring.test.ts +95 -0
- package/vitest.config.ts +8 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"secret-scanner.js","sourceRoot":"","sources":["../../src/analyzers/secret-scanner.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"secret-scanner.js","sourceRoot":"","sources":["../../src/analyzers/secret-scanner.ts"],"names":[],"mappings":"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"}
|
package/dist/canary.d.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mund - The Guardian Protocol
|
|
3
|
+
* Canary Tokens - detect system prompt leakage (OWASP LLM07)
|
|
4
|
+
*
|
|
5
|
+
* Generate a unique marker, place it in your system prompt (or any
|
|
6
|
+
* confidential context), and Mund flags any scanned output that
|
|
7
|
+
* contains it. A model that has been talked into revealing its
|
|
8
|
+
* instructions reveals the canary with them.
|
|
9
|
+
*
|
|
10
|
+
* Matching tolerates the cheap evasions a leaking model or an attacker
|
|
11
|
+
* might apply: case changes, inserted whitespace / zero-width
|
|
12
|
+
* characters / punctuation, base64 encoding, and reversal.
|
|
13
|
+
*/
|
|
14
|
+
import type { DetectionRule, IAnalyzer, SecurityIssue } from './types.js';
|
|
15
|
+
export interface Canary {
|
|
16
|
+
token: string;
|
|
17
|
+
label: string;
|
|
18
|
+
createdAt: string;
|
|
19
|
+
}
|
|
20
|
+
export type CanaryMatchKind = 'exact' | 'obfuscated' | 'base64' | 'reversed';
|
|
21
|
+
export declare class CanaryRegistry {
|
|
22
|
+
private canaries;
|
|
23
|
+
/** Create a new random canary token. */
|
|
24
|
+
create(label?: string): Canary;
|
|
25
|
+
/** Register an existing token (e.g. one already deployed in a prompt). */
|
|
26
|
+
register(token: string, label?: string): Canary;
|
|
27
|
+
remove(token: string): boolean;
|
|
28
|
+
list(): Canary[];
|
|
29
|
+
get size(): number;
|
|
30
|
+
/** Find every registered canary that appears in the content. */
|
|
31
|
+
find(content: string): Array<{
|
|
32
|
+
canary: Canary;
|
|
33
|
+
kind: CanaryMatchKind;
|
|
34
|
+
index: number;
|
|
35
|
+
}>;
|
|
36
|
+
}
|
|
37
|
+
/** Shared registry used by the MCP tools and the default analyzer set. */
|
|
38
|
+
export declare const canaries: CanaryRegistry;
|
|
39
|
+
/** Load canaries from MUND_CANARIES (comma-separated) or MUND_CANARY_FILE (one per line). */
|
|
40
|
+
export declare function loadCanariesFromEnv(registry?: CanaryRegistry): number;
|
|
41
|
+
export declare class CanaryDetector implements IAnalyzer {
|
|
42
|
+
private registry;
|
|
43
|
+
name: string;
|
|
44
|
+
type: string;
|
|
45
|
+
constructor(registry?: CanaryRegistry);
|
|
46
|
+
analyze(content: string, _rules: DetectionRule[]): Promise<SecurityIssue[]>;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=canary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canary.d.ts","sourceRoot":"","sources":["../src/canary.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE1E,MAAM,WAAW,MAAM;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,YAAY,GAAG,QAAQ,GAAG,UAAU,CAAC;AAW7E,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAA6B;IAE7C,wCAAwC;IACxC,MAAM,CAAC,KAAK,SAAkB,GAAG,MAAM;IAUvC,0EAA0E;IAC1E,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,SAAkB,GAAG,MAAM;IASxD,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAI9B,IAAI,IAAI,MAAM,EAAE;IAIhB,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,gEAAgE;IAChE,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,eAAe,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CAwBvF;AAiBD,0EAA0E;AAC1E,eAAO,MAAM,QAAQ,gBAAuB,CAAC;AAE7C,6FAA6F;AAC7F,wBAAgB,mBAAmB,CAAC,QAAQ,GAAE,cAAyB,GAAG,MAAM,CAoB/E;AAED,qBAAa,cAAe,YAAW,SAAS;IAIlC,OAAO,CAAC,QAAQ;IAH5B,IAAI,SAAoB;IACxB,IAAI,SAAkB;gBAEF,QAAQ,GAAE,cAAyB;IAEjD,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;CAmBlF"}
|
package/dist/canary.js
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mund - The Guardian Protocol
|
|
3
|
+
* Canary Tokens - detect system prompt leakage (OWASP LLM07)
|
|
4
|
+
*
|
|
5
|
+
* Generate a unique marker, place it in your system prompt (or any
|
|
6
|
+
* confidential context), and Mund flags any scanned output that
|
|
7
|
+
* contains it. A model that has been talked into revealing its
|
|
8
|
+
* instructions reveals the canary with them.
|
|
9
|
+
*
|
|
10
|
+
* Matching tolerates the cheap evasions a leaking model or an attacker
|
|
11
|
+
* might apply: case changes, inserted whitespace / zero-width
|
|
12
|
+
* characters / punctuation, base64 encoding, and reversal.
|
|
13
|
+
*/
|
|
14
|
+
import { randomBytes } from 'crypto';
|
|
15
|
+
import { readFileSync } from 'fs';
|
|
16
|
+
const TOKEN_PREFIX = 'MUND-CANARY-';
|
|
17
|
+
const MIN_TOKEN_LENGTH = 12;
|
|
18
|
+
const ZERO_WIDTH = /[-]/g;
|
|
19
|
+
/** Lowercase and keep only letters and digits. */
|
|
20
|
+
function squash(text) {
|
|
21
|
+
return text.replace(ZERO_WIDTH, '').toLowerCase().replace(/[^a-z0-9]/g, '');
|
|
22
|
+
}
|
|
23
|
+
export class CanaryRegistry {
|
|
24
|
+
canaries = new Map();
|
|
25
|
+
/** Create a new random canary token. */
|
|
26
|
+
create(label = 'system-prompt') {
|
|
27
|
+
const canary = {
|
|
28
|
+
token: TOKEN_PREFIX + randomBytes(8).toString('hex').toUpperCase(),
|
|
29
|
+
label,
|
|
30
|
+
createdAt: new Date().toISOString(),
|
|
31
|
+
};
|
|
32
|
+
this.canaries.set(canary.token, canary);
|
|
33
|
+
return canary;
|
|
34
|
+
}
|
|
35
|
+
/** Register an existing token (e.g. one already deployed in a prompt). */
|
|
36
|
+
register(token, label = 'system-prompt') {
|
|
37
|
+
if (squash(token).length < MIN_TOKEN_LENGTH) {
|
|
38
|
+
throw new Error(`Canary token must contain at least ${MIN_TOKEN_LENGTH} letters/digits to avoid false positives`);
|
|
39
|
+
}
|
|
40
|
+
const canary = { token, label, createdAt: new Date().toISOString() };
|
|
41
|
+
this.canaries.set(token, canary);
|
|
42
|
+
return canary;
|
|
43
|
+
}
|
|
44
|
+
remove(token) {
|
|
45
|
+
return this.canaries.delete(token);
|
|
46
|
+
}
|
|
47
|
+
list() {
|
|
48
|
+
return [...this.canaries.values()];
|
|
49
|
+
}
|
|
50
|
+
get size() {
|
|
51
|
+
return this.canaries.size;
|
|
52
|
+
}
|
|
53
|
+
/** Find every registered canary that appears in the content. */
|
|
54
|
+
find(content) {
|
|
55
|
+
const hits = [];
|
|
56
|
+
if (this.canaries.size === 0 || !content)
|
|
57
|
+
return hits;
|
|
58
|
+
const lower = content.toLowerCase();
|
|
59
|
+
const squashed = squash(content);
|
|
60
|
+
const decoded = decodeBase64Runs(content).map(squash);
|
|
61
|
+
for (const canary of this.canaries.values()) {
|
|
62
|
+
const needle = squash(canary.token);
|
|
63
|
+
const exactAt = lower.indexOf(canary.token.toLowerCase());
|
|
64
|
+
if (exactAt !== -1) {
|
|
65
|
+
hits.push({ canary, kind: 'exact', index: exactAt });
|
|
66
|
+
}
|
|
67
|
+
else if (squashed.includes(needle)) {
|
|
68
|
+
hits.push({ canary, kind: 'obfuscated', index: -1 });
|
|
69
|
+
}
|
|
70
|
+
else if (decoded.some(d => d.includes(needle))) {
|
|
71
|
+
hits.push({ canary, kind: 'base64', index: -1 });
|
|
72
|
+
}
|
|
73
|
+
else if (squashed.includes([...needle].reverse().join(''))) {
|
|
74
|
+
hits.push({ canary, kind: 'reversed', index: -1 });
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return hits;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/** Decode every plausible base64 run in the text (best effort). */
|
|
81
|
+
function decodeBase64Runs(content) {
|
|
82
|
+
const runs = content.match(/[A-Za-z0-9+/]{16,}={0,2}/g) ?? [];
|
|
83
|
+
const out = [];
|
|
84
|
+
for (const run of runs) {
|
|
85
|
+
try {
|
|
86
|
+
const text = Buffer.from(run, 'base64').toString('utf8');
|
|
87
|
+
if (/^[\x20-\x7E\s]+$/.test(text))
|
|
88
|
+
out.push(text);
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
// not base64
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return out;
|
|
95
|
+
}
|
|
96
|
+
/** Shared registry used by the MCP tools and the default analyzer set. */
|
|
97
|
+
export const canaries = new CanaryRegistry();
|
|
98
|
+
/** Load canaries from MUND_CANARIES (comma-separated) or MUND_CANARY_FILE (one per line). */
|
|
99
|
+
export function loadCanariesFromEnv(registry = canaries) {
|
|
100
|
+
const tokens = [];
|
|
101
|
+
if (process.env.MUND_CANARIES)
|
|
102
|
+
tokens.push(...process.env.MUND_CANARIES.split(','));
|
|
103
|
+
if (process.env.MUND_CANARY_FILE) {
|
|
104
|
+
try {
|
|
105
|
+
tokens.push(...readFileSync(process.env.MUND_CANARY_FILE, 'utf8').split('\n'));
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
// missing file: nothing to load
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
let loaded = 0;
|
|
112
|
+
for (const t of tokens.map(t => t.trim()).filter(Boolean)) {
|
|
113
|
+
try {
|
|
114
|
+
registry.register(t, 'env');
|
|
115
|
+
loaded++;
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
// too short; skip
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return loaded;
|
|
122
|
+
}
|
|
123
|
+
export class CanaryDetector {
|
|
124
|
+
registry;
|
|
125
|
+
name = 'CanaryDetector';
|
|
126
|
+
type = 'exfiltration';
|
|
127
|
+
constructor(registry = canaries) {
|
|
128
|
+
this.registry = registry;
|
|
129
|
+
}
|
|
130
|
+
async analyze(content, _rules) {
|
|
131
|
+
return this.registry.find(content).map(({ canary, kind, index }) => {
|
|
132
|
+
const before = index >= 0 ? content.slice(0, index).split('\n') : null;
|
|
133
|
+
return {
|
|
134
|
+
rule_id: 'canary_leak',
|
|
135
|
+
rule_name: `Canary token leaked (${kind})`,
|
|
136
|
+
type: 'exfiltration',
|
|
137
|
+
severity: 'critical',
|
|
138
|
+
action: 'block',
|
|
139
|
+
match: `${canary.token.slice(0, TOKEN_PREFIX.length + 4)}…`,
|
|
140
|
+
...(before
|
|
141
|
+
? { location: { start: index, end: index + canary.token.length, line: before.length, column: before[before.length - 1].length + 1 } }
|
|
142
|
+
: {}),
|
|
143
|
+
suggestion: `Content contains the "${canary.label}" canary, so confidential instructions or context are leaking. ` +
|
|
144
|
+
'Block this output and review the prompt that produced it.',
|
|
145
|
+
};
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=canary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canary.js","sourceRoot":"","sources":["../src/canary.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mund - The Guardian Protocol
|
|
3
|
+
* `mund-mcp scan` - scan files on disk and report as text, JSON or SARIF
|
|
4
|
+
*
|
|
5
|
+
* mund-mcp scan [paths...] [--format=text|json|sarif] [--output=FILE]
|
|
6
|
+
* [--fail-on=critical|high|medium|low|none]
|
|
7
|
+
* [--no-osv] [--offline]
|
|
8
|
+
*/
|
|
9
|
+
import type { Severity } from '../types.js';
|
|
10
|
+
import { type RiskScore } from '../scoring.js';
|
|
11
|
+
import { type SarifTarget } from '../sarif.js';
|
|
12
|
+
import { OsvClient, type OsvSource } from '../osv.js';
|
|
13
|
+
export type OutputFormat = 'text' | 'json' | 'sarif';
|
|
14
|
+
type FailOn = Severity | 'none';
|
|
15
|
+
export interface ScanCliOptions {
|
|
16
|
+
paths: string[];
|
|
17
|
+
format: OutputFormat;
|
|
18
|
+
output?: string;
|
|
19
|
+
failOn: FailOn;
|
|
20
|
+
osv: boolean;
|
|
21
|
+
offline: boolean;
|
|
22
|
+
canaries: string[];
|
|
23
|
+
}
|
|
24
|
+
export interface FileReport extends SarifTarget {
|
|
25
|
+
risk: RiskScore;
|
|
26
|
+
}
|
|
27
|
+
export interface ScanReport {
|
|
28
|
+
tool: {
|
|
29
|
+
name: 'mund';
|
|
30
|
+
version: string;
|
|
31
|
+
};
|
|
32
|
+
risk: RiskScore;
|
|
33
|
+
files_scanned: number;
|
|
34
|
+
osv?: {
|
|
35
|
+
source: OsvSource;
|
|
36
|
+
lockfiles: number;
|
|
37
|
+
unchecked: number;
|
|
38
|
+
error?: string;
|
|
39
|
+
};
|
|
40
|
+
files: FileReport[];
|
|
41
|
+
}
|
|
42
|
+
export declare const SCAN_USAGE = "Usage: mund-mcp scan [paths...] [options]\n\nScan files for secrets, PII, injection, exfiltration and dangerous code,\nplus known-vulnerable npm dependencies (via OSV.dev) in package-lock.json.\n\nOptions:\n --format=FORMAT text (default), json, or sarif\n --output=FILE Write the report to FILE instead of stdout\n --fail-on=LEVEL Exit 1 if any finding is at or above LEVEL\n (critical, high [default], medium, low, none)\n --no-osv Skip dependency vulnerability lookups\n --offline Use only the local OSV cache (also: MUND_OFFLINE=1)\n --canary=TOKEN Flag any file containing this canary token (repeatable;\n also MUND_CANARIES / MUND_CANARY_FILE)\n\nExamples:\n mund-mcp scan .\n mund-mcp scan src --format=sarif --output=mund.sarif\n";
|
|
43
|
+
export declare function parseScanArgs(args: string[]): ScanCliOptions;
|
|
44
|
+
export declare function runScan(opts: ScanCliOptions, osvClient?: OsvClient): Promise<ScanReport>;
|
|
45
|
+
export declare function formatReport(report: ScanReport, format: OutputFormat): string;
|
|
46
|
+
export declare function shouldFail(report: ScanReport, failOn: FailOn): boolean;
|
|
47
|
+
/** Entry point for `mund-mcp scan`. Returns the process exit code. */
|
|
48
|
+
export declare function runScanCli(args: string[]): Promise<number>;
|
|
49
|
+
export {};
|
|
50
|
+
//# sourceMappingURL=scan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../../src/cli/scan.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAiB,QAAQ,EAAE,MAAM,aAAa,CAAC;AAG3D,OAAO,EAAoB,KAAK,SAAS,EAAE,MAAM,eAAe,CAAC;AACjE,OAAO,EAAW,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,SAAS,EAAwC,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AAI5F,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AACrD,KAAK,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEhC,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,OAAO,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,UAAW,SAAQ,WAAW;IAC7C,IAAI,EAAE,SAAS,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IACxC,IAAI,EAAE,SAAS,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,GAAG,CAAC,EAAE;QAAE,MAAM,EAAE,SAAS,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAClF,KAAK,EAAE,UAAU,EAAE,CAAC;CACrB;AAOD,eAAO,MAAM,UAAU,wzBAkBtB,CAAC;AAEF,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,cAAc,CA8C5D;AAED,wBAAsB,OAAO,CAAC,IAAI,EAAE,cAAc,EAAE,SAAS,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAuD9F;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,YAAY,GAAG,MAAM,CAwB7E;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAItE;AAED,sEAAsE;AACtE,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAoBhE"}
|
package/dist/cli/scan.js
ADDED
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mund - The Guardian Protocol
|
|
3
|
+
* `mund-mcp scan` - scan files on disk and report as text, JSON or SARIF
|
|
4
|
+
*
|
|
5
|
+
* mund-mcp scan [paths...] [--format=text|json|sarif] [--output=FILE]
|
|
6
|
+
* [--fail-on=critical|high|medium|low|none]
|
|
7
|
+
* [--no-osv] [--offline]
|
|
8
|
+
*/
|
|
9
|
+
import { readFile, writeFile, readdir, stat } from 'fs/promises';
|
|
10
|
+
import { basename, join, relative, resolve, sep } from 'path';
|
|
11
|
+
import { DEFAULT_RULES } from '../constants.js';
|
|
12
|
+
import { AnalyzerEngine } from '../analyzers/index.js';
|
|
13
|
+
import { computeRiskScore } from '../scoring.js';
|
|
14
|
+
import { toSarif } from '../sarif.js';
|
|
15
|
+
import { OsvClient, parseNpmLockfile, advisoriesToIssues } from '../osv.js';
|
|
16
|
+
import { getVersion } from '../version.js';
|
|
17
|
+
import { canaries, loadCanariesFromEnv } from '../canary.js';
|
|
18
|
+
const SKIP_DIRS = new Set(['node_modules', '.git', 'dist', 'build', 'coverage', '.next', '.turbo', 'vendor', '__pycache__', '.venv']);
|
|
19
|
+
const LOCKFILES = new Set(['package-lock.json', 'npm-shrinkwrap.json']);
|
|
20
|
+
const MAX_FILE_BYTES = 1024 * 1024;
|
|
21
|
+
const SEVERITY_RANK = { critical: 0, high: 1, medium: 2, low: 3, info: 4 };
|
|
22
|
+
export const SCAN_USAGE = `Usage: mund-mcp scan [paths...] [options]
|
|
23
|
+
|
|
24
|
+
Scan files for secrets, PII, injection, exfiltration and dangerous code,
|
|
25
|
+
plus known-vulnerable npm dependencies (via OSV.dev) in package-lock.json.
|
|
26
|
+
|
|
27
|
+
Options:
|
|
28
|
+
--format=FORMAT text (default), json, or sarif
|
|
29
|
+
--output=FILE Write the report to FILE instead of stdout
|
|
30
|
+
--fail-on=LEVEL Exit 1 if any finding is at or above LEVEL
|
|
31
|
+
(critical, high [default], medium, low, none)
|
|
32
|
+
--no-osv Skip dependency vulnerability lookups
|
|
33
|
+
--offline Use only the local OSV cache (also: MUND_OFFLINE=1)
|
|
34
|
+
--canary=TOKEN Flag any file containing this canary token (repeatable;
|
|
35
|
+
also MUND_CANARIES / MUND_CANARY_FILE)
|
|
36
|
+
|
|
37
|
+
Examples:
|
|
38
|
+
mund-mcp scan .
|
|
39
|
+
mund-mcp scan src --format=sarif --output=mund.sarif
|
|
40
|
+
`;
|
|
41
|
+
export function parseScanArgs(args) {
|
|
42
|
+
const opts = { paths: [], format: 'text', failOn: 'high', osv: true, offline: false, canaries: [] };
|
|
43
|
+
for (let i = 0; i < args.length; i++) {
|
|
44
|
+
const arg = args[i];
|
|
45
|
+
const [flag, inline] = arg.startsWith('--') && arg.includes('=') ? [arg.slice(0, arg.indexOf('=')), arg.slice(arg.indexOf('=') + 1)] : [arg, undefined];
|
|
46
|
+
const value = () => {
|
|
47
|
+
const v = inline ?? args[++i];
|
|
48
|
+
if (v === undefined)
|
|
49
|
+
throw new Error(`${flag} needs a value`);
|
|
50
|
+
return v;
|
|
51
|
+
};
|
|
52
|
+
switch (flag) {
|
|
53
|
+
case '--format': {
|
|
54
|
+
const v = value();
|
|
55
|
+
if (v !== 'text' && v !== 'json' && v !== 'sarif')
|
|
56
|
+
throw new Error(`Unknown format "${v}" (expected text, json or sarif)`);
|
|
57
|
+
opts.format = v;
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
case '--output':
|
|
61
|
+
case '-o':
|
|
62
|
+
opts.output = value();
|
|
63
|
+
break;
|
|
64
|
+
case '--fail-on': {
|
|
65
|
+
const v = value();
|
|
66
|
+
if (v !== 'none' && !(v in SEVERITY_RANK))
|
|
67
|
+
throw new Error(`Unknown --fail-on level "${v}"`);
|
|
68
|
+
opts.failOn = v;
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
case '--no-osv':
|
|
72
|
+
opts.osv = false;
|
|
73
|
+
break;
|
|
74
|
+
case '--offline':
|
|
75
|
+
opts.offline = true;
|
|
76
|
+
break;
|
|
77
|
+
case '--canary':
|
|
78
|
+
opts.canaries.push(value());
|
|
79
|
+
break;
|
|
80
|
+
default:
|
|
81
|
+
if (flag.startsWith('-'))
|
|
82
|
+
throw new Error(`Unknown option ${flag}`);
|
|
83
|
+
opts.paths.push(arg);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (opts.paths.length === 0)
|
|
87
|
+
opts.paths.push('.');
|
|
88
|
+
return opts;
|
|
89
|
+
}
|
|
90
|
+
export async function runScan(opts, osvClient) {
|
|
91
|
+
const cwd = process.cwd();
|
|
92
|
+
loadCanariesFromEnv();
|
|
93
|
+
for (const token of opts.canaries)
|
|
94
|
+
canaries.register(token, 'cli');
|
|
95
|
+
const engine = new AnalyzerEngine();
|
|
96
|
+
const files = [];
|
|
97
|
+
const lockfiles = [];
|
|
98
|
+
let scanned = 0;
|
|
99
|
+
for (const file of await collectFiles(opts.paths.map(p => resolve(cwd, p)))) {
|
|
100
|
+
if (LOCKFILES.has(basename(file))) {
|
|
101
|
+
lockfiles.push(file);
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
const content = await readText(file);
|
|
105
|
+
if (content === null)
|
|
106
|
+
continue;
|
|
107
|
+
scanned++;
|
|
108
|
+
const issues = await engine.analyzeAll(content, DEFAULT_RULES);
|
|
109
|
+
if (issues.length > 0)
|
|
110
|
+
files.push({ uri: toUri(cwd, file), issues, risk: computeRiskScore(issues) });
|
|
111
|
+
}
|
|
112
|
+
let osv;
|
|
113
|
+
if (opts.osv && lockfiles.length > 0) {
|
|
114
|
+
const client = osvClient ?? new OsvClient({ offline: opts.offline });
|
|
115
|
+
let source = 'live';
|
|
116
|
+
let unchecked = 0;
|
|
117
|
+
let error;
|
|
118
|
+
for (const lockfile of lockfiles) {
|
|
119
|
+
const content = await readFile(lockfile, 'utf8');
|
|
120
|
+
let packages;
|
|
121
|
+
try {
|
|
122
|
+
packages = parseNpmLockfile(content);
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
continue; // malformed lockfile; nothing to look up
|
|
126
|
+
}
|
|
127
|
+
const result = await client.lookup(packages);
|
|
128
|
+
// Report the weakest source across lockfiles.
|
|
129
|
+
if (result.source === 'unavailable' || (result.source === 'cache' && source === 'live'))
|
|
130
|
+
source = result.source;
|
|
131
|
+
unchecked += result.unchecked.length;
|
|
132
|
+
error ??= result.error;
|
|
133
|
+
const issues = advisoriesToIssues(packages, result, content);
|
|
134
|
+
if (issues.length > 0)
|
|
135
|
+
files.push({ uri: toUri(cwd, lockfile), issues, risk: computeRiskScore(issues) });
|
|
136
|
+
}
|
|
137
|
+
osv = { source, lockfiles: lockfiles.length, unchecked, ...(error ? { error } : {}) };
|
|
138
|
+
}
|
|
139
|
+
return {
|
|
140
|
+
tool: { name: 'mund', version: getVersion() },
|
|
141
|
+
risk: computeRiskScore(files.flatMap(f => f.issues)),
|
|
142
|
+
files_scanned: scanned,
|
|
143
|
+
...(osv ? { osv } : {}),
|
|
144
|
+
files,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
export function formatReport(report, format) {
|
|
148
|
+
if (format === 'json')
|
|
149
|
+
return JSON.stringify(report, null, 2);
|
|
150
|
+
if (format === 'sarif')
|
|
151
|
+
return JSON.stringify(toSarif(report.files, { toolVersion: report.tool.version }), null, 2);
|
|
152
|
+
const lines = [];
|
|
153
|
+
for (const file of report.files) {
|
|
154
|
+
lines.push(`${file.uri} (risk ${file.risk.score}/100, ${file.risk.label})`);
|
|
155
|
+
for (const issue of file.issues) {
|
|
156
|
+
const where = issue.location?.line ? `${issue.location.line}:${issue.location.column ?? 1}` : '-';
|
|
157
|
+
lines.push(` ${where.padEnd(8)} ${issue.severity.padEnd(8)} ${issue.rule_name}`);
|
|
158
|
+
}
|
|
159
|
+
lines.push('');
|
|
160
|
+
}
|
|
161
|
+
const total = report.files.reduce((n, f) => n + f.issues.length, 0);
|
|
162
|
+
const { counts } = report.risk;
|
|
163
|
+
lines.push(`Scanned ${report.files_scanned} file(s): ${total} finding(s) ` +
|
|
164
|
+
`(${counts.critical} critical, ${counts.high} high, ${counts.medium} medium, ${counts.low} low)`);
|
|
165
|
+
lines.push(`Risk score: ${report.risk.score}/100 (${report.risk.label})`);
|
|
166
|
+
if (report.osv) {
|
|
167
|
+
const note = report.osv.source === 'live' ? 'live' : `${report.osv.source} - ${report.osv.error ?? ''}`.trim();
|
|
168
|
+
lines.push(`Dependencies: OSV.dev (${note})` + (report.osv.unchecked ? `, ${report.osv.unchecked} package(s) unchecked` : ''));
|
|
169
|
+
}
|
|
170
|
+
return lines.join('\n');
|
|
171
|
+
}
|
|
172
|
+
export function shouldFail(report, failOn) {
|
|
173
|
+
if (failOn === 'none')
|
|
174
|
+
return false;
|
|
175
|
+
const threshold = SEVERITY_RANK[failOn];
|
|
176
|
+
return report.files.some(f => f.issues.some((i) => SEVERITY_RANK[i.severity] <= threshold));
|
|
177
|
+
}
|
|
178
|
+
/** Entry point for `mund-mcp scan`. Returns the process exit code. */
|
|
179
|
+
export async function runScanCli(args) {
|
|
180
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
181
|
+
process.stdout.write(SCAN_USAGE);
|
|
182
|
+
return 0;
|
|
183
|
+
}
|
|
184
|
+
let opts;
|
|
185
|
+
try {
|
|
186
|
+
opts = parseScanArgs(args);
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
process.stderr.write(`mund scan: ${error.message}\n\n${SCAN_USAGE}`);
|
|
190
|
+
return 2;
|
|
191
|
+
}
|
|
192
|
+
const report = await runScan(opts);
|
|
193
|
+
const out = formatReport(report, opts.format) + '\n';
|
|
194
|
+
if (opts.output)
|
|
195
|
+
await writeFile(opts.output, out);
|
|
196
|
+
else
|
|
197
|
+
process.stdout.write(out);
|
|
198
|
+
return shouldFail(report, opts.failOn) ? 1 : 0;
|
|
199
|
+
}
|
|
200
|
+
async function collectFiles(roots) {
|
|
201
|
+
const out = [];
|
|
202
|
+
const walk = async (path) => {
|
|
203
|
+
const info = await stat(path).catch(() => null);
|
|
204
|
+
if (!info)
|
|
205
|
+
return;
|
|
206
|
+
if (info.isFile()) {
|
|
207
|
+
out.push(path);
|
|
208
|
+
}
|
|
209
|
+
else if (info.isDirectory()) {
|
|
210
|
+
for (const entry of await readdir(path, { withFileTypes: true })) {
|
|
211
|
+
if (entry.isDirectory() && SKIP_DIRS.has(entry.name))
|
|
212
|
+
continue;
|
|
213
|
+
if (entry.isDirectory() || entry.isFile())
|
|
214
|
+
await walk(join(path, entry.name));
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
for (const root of roots)
|
|
219
|
+
await walk(root);
|
|
220
|
+
return out.sort();
|
|
221
|
+
}
|
|
222
|
+
/** Read a file as UTF-8 text, or null if it's too big or looks binary. */
|
|
223
|
+
async function readText(file) {
|
|
224
|
+
const info = await stat(file);
|
|
225
|
+
if (info.size > MAX_FILE_BYTES)
|
|
226
|
+
return null;
|
|
227
|
+
const buf = await readFile(file);
|
|
228
|
+
if (buf.subarray(0, 8000).includes(0))
|
|
229
|
+
return null;
|
|
230
|
+
return buf.toString('utf8');
|
|
231
|
+
}
|
|
232
|
+
function toUri(cwd, file) {
|
|
233
|
+
return relative(cwd, file).split(sep).join('/');
|
|
234
|
+
}
|
|
235
|
+
//# sourceMappingURL=scan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan.js","sourceRoot":"","sources":["../../src/cli/scan.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":";AACA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;GAGG;AA0XH,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAC5E,OAAO,EAAE,gBAAgB,EAAE,6BAA6B,EAAE,MAAM,yBAAyB,CAAC;AAC1F,cAAc,yBAAyB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -12,6 +12,9 @@ import { createStorage } from './storage/index.js';
|
|
|
12
12
|
import { AnalyzerEngine } from './analyzers/index.js';
|
|
13
13
|
import { NotificationHub } from './notifications/index.js';
|
|
14
14
|
import { registerAllTools } from './tools/index.js';
|
|
15
|
+
import { runScanCli } from './cli/scan.js';
|
|
16
|
+
import { getVersion } from './version.js';
|
|
17
|
+
import { loadCanariesFromEnv } from './canary.js';
|
|
15
18
|
// Threat Intelligence imports
|
|
16
19
|
import { threatIntel } from './threat-intel-manager.js';
|
|
17
20
|
import { threatIntelTools, createThreatIntelToolHandlers, UpdateThreatIntelSchema, ListIntelSourcesSchema, IntelStatusSchema, AddIntelSourceSchema, RemoveIntelSourceSchema, ThreatScanSchema, ListPatternsSchema, TogglePatternSchema, } from './threat-intel-tools.js';
|
|
@@ -117,7 +120,7 @@ async function createMundServer(config) {
|
|
|
117
120
|
// Create MCP server
|
|
118
121
|
const server = new McpServer({
|
|
119
122
|
name: 'mund-mcp-server',
|
|
120
|
-
version:
|
|
123
|
+
version: getVersion()
|
|
121
124
|
});
|
|
122
125
|
// Initialize storage
|
|
123
126
|
const storage = createStorage(config);
|
|
@@ -135,6 +138,7 @@ async function createMundServer(config) {
|
|
|
135
138
|
}
|
|
136
139
|
}
|
|
137
140
|
// Register all core tools
|
|
141
|
+
loadCanariesFromEnv();
|
|
138
142
|
registerAllTools(server, storage, rules, analyzer, notificationHub, config.block_mode);
|
|
139
143
|
// Register threat intelligence tools
|
|
140
144
|
registerThreatIntelTools(server);
|
|
@@ -165,7 +169,7 @@ async function runHTTP(config) {
|
|
|
165
169
|
app.use(express.json({ limit: '10mb' }));
|
|
166
170
|
// Health check endpoint
|
|
167
171
|
app.get('/health', (_req, res) => {
|
|
168
|
-
res.json({ status: 'ok', version:
|
|
172
|
+
res.json({ status: 'ok', version: getVersion() });
|
|
169
173
|
});
|
|
170
174
|
// Threat intel status endpoint
|
|
171
175
|
app.get('/intel/status', (_req, res) => {
|
|
@@ -194,7 +198,8 @@ function printHelp() {
|
|
|
194
198
|
Mund - The Guardian Protocol
|
|
195
199
|
MCP-based security monitoring for agentic AI systems
|
|
196
200
|
|
|
197
|
-
Usage: mund-mcp [options]
|
|
201
|
+
Usage: mund-mcp [options] Run the MCP server
|
|
202
|
+
mund-mcp scan [paths...] Scan files (see: mund-mcp scan --help)
|
|
198
203
|
|
|
199
204
|
Options:
|
|
200
205
|
--help, -h Show this help message
|
|
@@ -252,13 +257,16 @@ For more information, visit: https://github.com/Tyox-all/Weave_Protocol
|
|
|
252
257
|
}
|
|
253
258
|
async function main() {
|
|
254
259
|
const args = process.argv.slice(2);
|
|
260
|
+
if (args[0] === 'scan') {
|
|
261
|
+
process.exit(await runScanCli(args.slice(1)));
|
|
262
|
+
}
|
|
255
263
|
// Parse CLI arguments
|
|
256
264
|
if (args.includes('--help') || args.includes('-h')) {
|
|
257
265
|
printHelp();
|
|
258
266
|
process.exit(0);
|
|
259
267
|
}
|
|
260
268
|
if (args.includes('--version') || args.includes('-v')) {
|
|
261
|
-
console.log(
|
|
269
|
+
console.log(getVersion());
|
|
262
270
|
process.exit(0);
|
|
263
271
|
}
|
|
264
272
|
// Load config
|