@mcp-guardian/server 1.0.0 → 1.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.
- package/README.md +63 -7
- package/dist/auth/dashboard-auth.d.ts +97 -0
- package/dist/auth/dashboard-auth.d.ts.map +1 -0
- package/dist/auth/dashboard-auth.js +319 -0
- package/dist/auth/dashboard-auth.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/policy/policy-engine.d.ts +10 -0
- package/dist/policy/policy-engine.d.ts.map +1 -1
- package/dist/policy/policy-engine.js +57 -6
- package/dist/policy/policy-engine.js.map +1 -1
- package/dist/policy/shell-tokenizer.d.ts +92 -0
- package/dist/policy/shell-tokenizer.d.ts.map +1 -0
- package/dist/policy/shell-tokenizer.js +300 -0
- package/dist/policy/shell-tokenizer.js.map +1 -0
- package/dist/utils/dashboard-server.d.ts +14 -5
- package/dist/utils/dashboard-server.d.ts.map +1 -1
- package/dist/utils/dashboard-server.js +213 -41
- package/dist/utils/dashboard-server.js.map +1 -1
- package/dist/utils/payload-normalizer.d.ts +62 -0
- package/dist/utils/payload-normalizer.d.ts.map +1 -0
- package/dist/utils/payload-normalizer.js +240 -0
- package/dist/utils/payload-normalizer.js.map +1 -0
- package/dist/utils/policy-auditor.d.ts +24 -0
- package/dist/utils/policy-auditor.d.ts.map +1 -0
- package/dist/utils/policy-auditor.js +58 -0
- package/dist/utils/policy-auditor.js.map +1 -0
- package/dist/utils/tracing.d.ts +2 -2
- package/dist/utils/tracing.d.ts.map +1 -1
- package/dist/utils/tracing.js +8 -6
- package/dist/utils/tracing.js.map +1 -1
- package/package.json +3 -3
|
@@ -1,19 +1,29 @@
|
|
|
1
1
|
import { PolicyConfig, PolicyDecision, CallContext, PolicyMode } from './policy-types.js';
|
|
2
|
+
import { ShellTokenizer } from './shell-tokenizer.js';
|
|
2
3
|
/**
|
|
3
4
|
* Policy Engine — evaluates every intercepted tools/call against configured rules.
|
|
4
5
|
* Supports three modes: audit (passive), warn (flag only), block (active enforcement).
|
|
6
|
+
*
|
|
7
|
+
* v1.2: Integrated payload normalization and semantic shell analysis layers
|
|
8
|
+
* to move beyond regex-only detection toward semantic execution security.
|
|
5
9
|
*/
|
|
6
10
|
export declare class PolicyEngine {
|
|
7
11
|
private rules;
|
|
8
12
|
private mode;
|
|
9
13
|
private callCounters;
|
|
14
|
+
private normalizer;
|
|
15
|
+
private shellTokenizer;
|
|
10
16
|
constructor(config: PolicyConfig);
|
|
11
17
|
/**
|
|
12
18
|
* Evaluate a tools/call request and return a decision.
|
|
19
|
+
*
|
|
20
|
+
* Pipeline: Normalize payload → Semantic shell analysis → Rule evaluation
|
|
13
21
|
*/
|
|
14
22
|
evaluate(context: CallContext): PolicyDecision;
|
|
15
23
|
private evaluateRule;
|
|
16
24
|
private resolveAction;
|
|
17
25
|
getMode(): PolicyMode;
|
|
26
|
+
/** Expose the shell tokenizer for testing */
|
|
27
|
+
getShellTokenizer(): ShellTokenizer;
|
|
18
28
|
}
|
|
19
29
|
//# sourceMappingURL=policy-engine.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"policy-engine.d.ts","sourceRoot":"","sources":["../../src/policy/policy-engine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,WAAW,EAAgB,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAGxG
|
|
1
|
+
{"version":3,"file":"policy-engine.d.ts","sourceRoot":"","sources":["../../src/policy/policy-engine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,WAAW,EAAgB,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAGxG,OAAO,EAAE,cAAc,EAAe,MAAM,sBAAsB,CAAC;AAEnE;;;;;;GAMG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,KAAK,CAAkC;IAC/C,OAAO,CAAC,IAAI,CAAa;IACzB,OAAO,CAAC,YAAY,CAA8D;IAClF,OAAO,CAAC,UAAU,CAAmB;IACrC,OAAO,CAAC,cAAc,CAAwB;gBAElC,MAAM,EAAE,YAAY;IAKhC;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,WAAW,GAAG,cAAc;IAiC9C,OAAO,CAAC,YAAY;IAoGpB,OAAO,CAAC,aAAa;IAMrB,OAAO,IAAI,UAAU;IAIrB,6CAA6C;IAC7C,iBAAiB,IAAI,cAAc;CAGpC"}
|
|
@@ -1,29 +1,58 @@
|
|
|
1
1
|
import { Logger } from '../utils/logger.js';
|
|
2
|
+
import { getNormalizer } from '../utils/payload-normalizer.js';
|
|
3
|
+
import { ShellTokenizer } from './shell-tokenizer.js';
|
|
2
4
|
/**
|
|
3
5
|
* Policy Engine — evaluates every intercepted tools/call against configured rules.
|
|
4
6
|
* Supports three modes: audit (passive), warn (flag only), block (active enforcement).
|
|
7
|
+
*
|
|
8
|
+
* v1.2: Integrated payload normalization and semantic shell analysis layers
|
|
9
|
+
* to move beyond regex-only detection toward semantic execution security.
|
|
5
10
|
*/
|
|
6
11
|
export class PolicyEngine {
|
|
7
12
|
rules;
|
|
8
13
|
mode;
|
|
9
14
|
callCounters = new Map();
|
|
15
|
+
normalizer = getNormalizer();
|
|
16
|
+
shellTokenizer = new ShellTokenizer();
|
|
10
17
|
constructor(config) {
|
|
11
18
|
this.rules = config.policy.rules;
|
|
12
19
|
this.mode = config.policy.mode;
|
|
13
20
|
}
|
|
14
21
|
/**
|
|
15
22
|
* Evaluate a tools/call request and return a decision.
|
|
23
|
+
*
|
|
24
|
+
* Pipeline: Normalize payload → Semantic shell analysis → Rule evaluation
|
|
16
25
|
*/
|
|
17
26
|
evaluate(context) {
|
|
27
|
+
// ── v1.2: Payload normalization (before regex evaluation) ──
|
|
28
|
+
const normalizedArgs = context.arguments
|
|
29
|
+
? this.normalizer.normalizeJsonValue(context.arguments)
|
|
30
|
+
: {};
|
|
31
|
+
const normalizedContext = {
|
|
32
|
+
...context,
|
|
33
|
+
arguments: normalizedArgs,
|
|
34
|
+
};
|
|
35
|
+
// ── v1.2: Semantic shell analysis on argument strings ──
|
|
36
|
+
const argsStr = JSON.stringify(normalizedArgs);
|
|
37
|
+
const shellRisk = argsStr.length > 0
|
|
38
|
+
? this.shellTokenizer.analyzeRisk(this.shellTokenizer.tokenize(argsStr).commands)
|
|
39
|
+
: { hasCommandSubstitution: false, hasPipes: false, hasRedirects: false, hasLogicalChains: false, dangerousCommands: [], shellMetacharacters: [] };
|
|
40
|
+
// Check for high-risk semantic patterns regardless of rule match
|
|
41
|
+
if (shellRisk.hasCommandSubstitution) {
|
|
42
|
+
Logger.info(`[policy] Semantic: command substitution detected in '${context.toolName}' arguments`);
|
|
43
|
+
}
|
|
44
|
+
if (shellRisk.dangerousCommands.length > 0) {
|
|
45
|
+
Logger.info(`[policy] Semantic: dangerous commands [${shellRisk.dangerousCommands.join(', ')}] in '${context.toolName}' arguments`);
|
|
46
|
+
}
|
|
18
47
|
for (const rule of this.rules) {
|
|
19
|
-
const decision = this.evaluateRule(rule,
|
|
48
|
+
const decision = this.evaluateRule(rule, normalizedContext, { argsStr, shellRisk });
|
|
20
49
|
if (decision)
|
|
21
50
|
return decision;
|
|
22
51
|
}
|
|
23
52
|
// Default: pass
|
|
24
53
|
return { action: 'pass', rule: 'default', reason: 'No policy rules matched' };
|
|
25
54
|
}
|
|
26
|
-
evaluateRule(rule, ctx) {
|
|
55
|
+
evaluateRule(rule, ctx, analysis) {
|
|
27
56
|
// Tool allowlist/denylist
|
|
28
57
|
if (rule.tools) {
|
|
29
58
|
if (rule.tools.allow && rule.tools.allow.length > 0) {
|
|
@@ -37,13 +66,12 @@ export class PolicyEngine {
|
|
|
37
66
|
}
|
|
38
67
|
}
|
|
39
68
|
}
|
|
40
|
-
// Malicious pattern detection
|
|
69
|
+
// v1.2: Malicious pattern detection — runs against NORMALIZED payload
|
|
41
70
|
if (rule.patterns) {
|
|
42
|
-
const argsStr = ctx.arguments ? JSON.stringify(ctx.arguments) : '';
|
|
43
71
|
for (const pattern of rule.patterns) {
|
|
44
72
|
try {
|
|
45
|
-
if (new RegExp(pattern).test(argsStr)) {
|
|
46
|
-
return { action: this.resolveAction(rule.action), rule: rule.name, reason: `Argument pattern '${pattern}' matched in tool call` };
|
|
73
|
+
if (new RegExp(pattern).test(analysis.argsStr)) {
|
|
74
|
+
return { action: this.resolveAction(rule.action), rule: rule.name, reason: `Argument pattern '${pattern}' matched in tool call (normalized)` };
|
|
47
75
|
}
|
|
48
76
|
}
|
|
49
77
|
catch {
|
|
@@ -51,6 +79,25 @@ export class PolicyEngine {
|
|
|
51
79
|
}
|
|
52
80
|
}
|
|
53
81
|
}
|
|
82
|
+
// v1.2: Semantic shell detection rule — automatic high-risk pattern block
|
|
83
|
+
if (rule.name === 'block-shell-injection' || rule.name.includes('shell')) {
|
|
84
|
+
// Command substitution is always high-risk
|
|
85
|
+
if (analysis.shellRisk.hasCommandSubstitution) {
|
|
86
|
+
return { action: this.resolveAction('block'), rule: rule.name, reason: 'Semantic: shell command substitution detected in arguments' };
|
|
87
|
+
}
|
|
88
|
+
// Dangerous commands in any context
|
|
89
|
+
if (analysis.shellRisk.dangerousCommands.length > 0) {
|
|
90
|
+
return {
|
|
91
|
+
action: this.resolveAction('block'),
|
|
92
|
+
rule: rule.name,
|
|
93
|
+
reason: `Semantic: dangerous shell commands detected: [${analysis.shellRisk.dangerousCommands.join(', ')}]`,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
// Pipe chains with dangerous patterns
|
|
97
|
+
if (analysis.shellRisk.hasPipes && analysis.shellRisk.hasCommandSubstitution) {
|
|
98
|
+
return { action: this.resolveAction('block'), rule: rule.name, reason: 'Semantic: pipe chain with command substitution' };
|
|
99
|
+
}
|
|
100
|
+
}
|
|
54
101
|
// Max tokens per call
|
|
55
102
|
if (rule.maxTokens && ctx.requestTokens > rule.maxTokens) {
|
|
56
103
|
return { action: this.resolveAction(rule.action), rule: rule.name, reason: `Token count ${ctx.requestTokens} exceeds max ${rule.maxTokens}` };
|
|
@@ -104,5 +151,9 @@ export class PolicyEngine {
|
|
|
104
151
|
getMode() {
|
|
105
152
|
return this.mode;
|
|
106
153
|
}
|
|
154
|
+
/** Expose the shell tokenizer for testing */
|
|
155
|
+
getShellTokenizer() {
|
|
156
|
+
return this.shellTokenizer;
|
|
157
|
+
}
|
|
107
158
|
}
|
|
108
159
|
//# sourceMappingURL=policy-engine.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"policy-engine.js","sourceRoot":"","sources":["../../src/policy/policy-engine.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"policy-engine.js","sourceRoot":"","sources":["../../src/policy/policy-engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shell Command Tokenizer & Semantic Analyzer
|
|
3
|
+
*
|
|
4
|
+
* Parses tool argument strings into tokenized AST nodes for semantic
|
|
5
|
+
* security analysis. Goes beyond regex pattern matching by understanding
|
|
6
|
+
* shell grammar: pipelines, redirects, command substitutions, logical chains.
|
|
7
|
+
*
|
|
8
|
+
* This is the semantic detection layer that addresses the architectural
|
|
9
|
+
* limitation of regex-only detection. Instead of pattern-matching "$(rm -rf /)"
|
|
10
|
+
* we parse it as a CommandSubstitution AST node and then analyze the inner
|
|
11
|
+
* command semantically.
|
|
12
|
+
*/
|
|
13
|
+
export declare enum TokenType {
|
|
14
|
+
WORD = "WORD",
|
|
15
|
+
STRING = "STRING",
|
|
16
|
+
VARIABLE = "VARIABLE",
|
|
17
|
+
COMMAND_SUBSTITUTION = "COMMAND_SUBSTITUTION",
|
|
18
|
+
BACKTICK_SUBSTITUTION = "BACKTICK_SUBSTITUTION",
|
|
19
|
+
PIPE = "PIPE",
|
|
20
|
+
REDIRECT = "REDIRECT",
|
|
21
|
+
SEMICOLON = "SEMICOLON",
|
|
22
|
+
AND_IF = "AND_IF",// &&
|
|
23
|
+
OR_IF = "OR_IF",// ||
|
|
24
|
+
BACKGROUND = "BACKGROUND",
|
|
25
|
+
SUBSHELL = "SUBSHELL"
|
|
26
|
+
}
|
|
27
|
+
export interface Token {
|
|
28
|
+
type: TokenType;
|
|
29
|
+
value: string;
|
|
30
|
+
/** Start position in original string */
|
|
31
|
+
start: number;
|
|
32
|
+
/** End position in original string */
|
|
33
|
+
end: number;
|
|
34
|
+
/** For compound tokens (substitution, subshell), nested tokens */
|
|
35
|
+
children?: Token[];
|
|
36
|
+
}
|
|
37
|
+
export interface ShellAST {
|
|
38
|
+
/** Top-level commands (separated by ;, &&, ||, &) */
|
|
39
|
+
commands: Token[];
|
|
40
|
+
/** Whether the input contained potentially dangerous constructs */
|
|
41
|
+
warnings: string[];
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Dangerous command categories for semantic analysis.
|
|
45
|
+
*/
|
|
46
|
+
export interface CommandRisk {
|
|
47
|
+
/** High risk: command substitution present */
|
|
48
|
+
hasCommandSubstitution: boolean;
|
|
49
|
+
/** High risk: pipe chains present */
|
|
50
|
+
hasPipes: boolean;
|
|
51
|
+
/** Medium risk: redirect operators present */
|
|
52
|
+
hasRedirects: boolean;
|
|
53
|
+
/** Medium risk: logical chain operators */
|
|
54
|
+
hasLogicalChains: boolean;
|
|
55
|
+
/** Dangerous commands detected in tokenized words */
|
|
56
|
+
dangerousCommands: string[];
|
|
57
|
+
/** Shell metacharacters found */
|
|
58
|
+
shellMetacharacters: string[];
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* ShellTokenizer parses shell-like input into an AST without executing anything.
|
|
62
|
+
* It's a security analyzer, not a full POSIX shell parser — focus is on detecting
|
|
63
|
+
* execution patterns that signal malicious intent.
|
|
64
|
+
*/
|
|
65
|
+
export declare class ShellTokenizer {
|
|
66
|
+
private readonly DANGEROUS_COMMANDS;
|
|
67
|
+
/**
|
|
68
|
+
* Tokenize a string that may contain shell syntax.
|
|
69
|
+
*/
|
|
70
|
+
tokenize(input: string): ShellAST;
|
|
71
|
+
/**
|
|
72
|
+
* Parse the next token starting at position pos.
|
|
73
|
+
*/
|
|
74
|
+
private nextToken;
|
|
75
|
+
/**
|
|
76
|
+
* Parse a delimited token like $(...), ${...}, `...`, (...).
|
|
77
|
+
* Recursively tokenizes inner content.
|
|
78
|
+
*/
|
|
79
|
+
private parseDelimited;
|
|
80
|
+
/**
|
|
81
|
+
* Analyze a token for risk.
|
|
82
|
+
*/
|
|
83
|
+
analyzeRisk(tokens: Token[]): CommandRisk;
|
|
84
|
+
/**
|
|
85
|
+
* Full semantic analysis: tokenize + assess risk.
|
|
86
|
+
*/
|
|
87
|
+
analyze(input: string): {
|
|
88
|
+
ast: ShellAST;
|
|
89
|
+
risk: CommandRisk;
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=shell-tokenizer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shell-tokenizer.d.ts","sourceRoot":"","sources":["../../src/policy/shell-tokenizer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,oBAAY,SAAS;IACnB,IAAI,SAAS;IACb,MAAM,WAAW;IACjB,QAAQ,aAAa;IACrB,oBAAoB,yBAAyB;IAC7C,qBAAqB,0BAA0B;IAC/C,IAAI,SAAS;IACb,QAAQ,aAAa;IACrB,SAAS,cAAc;IACvB,MAAM,WAAW,CAAM,KAAK;IAC5B,KAAK,UAAU,CAAQ,KAAK;IAC5B,UAAU,eAAe;IACzB,QAAQ,aAAa;CACtB;AAED,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,wCAAwC;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,sCAAsC;IACtC,GAAG,EAAE,MAAM,CAAC;IACZ,kEAAkE;IAClE,QAAQ,CAAC,EAAE,KAAK,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,QAAQ;IACvB,qDAAqD;IACrD,QAAQ,EAAE,KAAK,EAAE,CAAC;IAClB,mEAAmE;IACnE,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,8CAA8C;IAC9C,sBAAsB,EAAE,OAAO,CAAC;IAChC,qCAAqC;IACrC,QAAQ,EAAE,OAAO,CAAC;IAClB,8CAA8C;IAC9C,YAAY,EAAE,OAAO,CAAC;IACtB,2CAA2C;IAC3C,gBAAgB,EAAE,OAAO,CAAC;IAC1B,qDAAqD;IACrD,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,iCAAiC;IACjC,mBAAmB,EAAE,MAAM,EAAE,CAAC;CAC/B;AAED;;;;GAIG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAShC;IAEH;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ;IA6BjC;;OAEG;IACH,OAAO,CAAC,SAAS;IA2IjB;;;OAGG;IACH,OAAO,CAAC,cAAc;IA0CtB;;OAEG;IACH,WAAW,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,WAAW;IAoDzC;;OAEG;IACH,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG;QAAE,GAAG,EAAE,QAAQ,CAAC;QAAC,IAAI,EAAE,WAAW,CAAA;KAAE;CAK7D"}
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shell Command Tokenizer & Semantic Analyzer
|
|
3
|
+
*
|
|
4
|
+
* Parses tool argument strings into tokenized AST nodes for semantic
|
|
5
|
+
* security analysis. Goes beyond regex pattern matching by understanding
|
|
6
|
+
* shell grammar: pipelines, redirects, command substitutions, logical chains.
|
|
7
|
+
*
|
|
8
|
+
* This is the semantic detection layer that addresses the architectural
|
|
9
|
+
* limitation of regex-only detection. Instead of pattern-matching "$(rm -rf /)"
|
|
10
|
+
* we parse it as a CommandSubstitution AST node and then analyze the inner
|
|
11
|
+
* command semantically.
|
|
12
|
+
*/
|
|
13
|
+
export var TokenType;
|
|
14
|
+
(function (TokenType) {
|
|
15
|
+
TokenType["WORD"] = "WORD";
|
|
16
|
+
TokenType["STRING"] = "STRING";
|
|
17
|
+
TokenType["VARIABLE"] = "VARIABLE";
|
|
18
|
+
TokenType["COMMAND_SUBSTITUTION"] = "COMMAND_SUBSTITUTION";
|
|
19
|
+
TokenType["BACKTICK_SUBSTITUTION"] = "BACKTICK_SUBSTITUTION";
|
|
20
|
+
TokenType["PIPE"] = "PIPE";
|
|
21
|
+
TokenType["REDIRECT"] = "REDIRECT";
|
|
22
|
+
TokenType["SEMICOLON"] = "SEMICOLON";
|
|
23
|
+
TokenType["AND_IF"] = "AND_IF";
|
|
24
|
+
TokenType["OR_IF"] = "OR_IF";
|
|
25
|
+
TokenType["BACKGROUND"] = "BACKGROUND";
|
|
26
|
+
TokenType["SUBSHELL"] = "SUBSHELL";
|
|
27
|
+
})(TokenType || (TokenType = {}));
|
|
28
|
+
/**
|
|
29
|
+
* ShellTokenizer parses shell-like input into an AST without executing anything.
|
|
30
|
+
* It's a security analyzer, not a full POSIX shell parser — focus is on detecting
|
|
31
|
+
* execution patterns that signal malicious intent.
|
|
32
|
+
*/
|
|
33
|
+
export class ShellTokenizer {
|
|
34
|
+
DANGEROUS_COMMANDS = new Set([
|
|
35
|
+
'rm', 'dd', 'mkfs', 'fdisk', 'shred',
|
|
36
|
+
'chmod', 'chown', 'passwd', 'mount', 'umount',
|
|
37
|
+
'iptables', 'nc', 'curl', 'wget', 'telnet',
|
|
38
|
+
'eval', 'exec', 'source', 'bash', 'sh', 'zsh',
|
|
39
|
+
'python', 'perl', 'ruby', 'node', 'php',
|
|
40
|
+
'ssh', 'scp', 'rsync',
|
|
41
|
+
'kill', 'pkill', 'reboot', 'shutdown', 'halt',
|
|
42
|
+
'tcpdump', 'nmap', 'traceroute',
|
|
43
|
+
]);
|
|
44
|
+
/**
|
|
45
|
+
* Tokenize a string that may contain shell syntax.
|
|
46
|
+
*/
|
|
47
|
+
tokenize(input) {
|
|
48
|
+
const warnings = [];
|
|
49
|
+
const tokens = [];
|
|
50
|
+
let pos = 0;
|
|
51
|
+
while (pos < input.length) {
|
|
52
|
+
// Skip whitespace
|
|
53
|
+
if (/\s/.test(input[pos])) {
|
|
54
|
+
pos++;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
const result = this.nextToken(input, pos);
|
|
58
|
+
if (!result)
|
|
59
|
+
break;
|
|
60
|
+
tokens.push(result.token);
|
|
61
|
+
pos = result.nextPos;
|
|
62
|
+
if (result.token.type === TokenType.WORD) {
|
|
63
|
+
const word = result.token.value.toLowerCase();
|
|
64
|
+
if (this.DANGEROUS_COMMANDS.has(word)) {
|
|
65
|
+
warnings.push(`Dangerous command detected: '${result.token.value}'`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return { commands: tokens, warnings };
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Parse the next token starting at position pos.
|
|
73
|
+
*/
|
|
74
|
+
nextToken(input, pos) {
|
|
75
|
+
const ch = input[pos];
|
|
76
|
+
if (ch === undefined)
|
|
77
|
+
return null;
|
|
78
|
+
// ── Pipe ──────────────────────────────────────────
|
|
79
|
+
if (ch === '|' && input[pos + 1] !== '|') {
|
|
80
|
+
return {
|
|
81
|
+
token: { type: TokenType.PIPE, value: '|', start: pos, end: pos + 1 },
|
|
82
|
+
nextPos: pos + 1,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
// ── Logical operators && || ────────────────────────
|
|
86
|
+
if (ch === '&' && input[pos + 1] === '&') {
|
|
87
|
+
return {
|
|
88
|
+
token: { type: TokenType.AND_IF, value: '&&', start: pos, end: pos + 2 },
|
|
89
|
+
nextPos: pos + 2,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
if (ch === '|' && input[pos + 1] === '|') {
|
|
93
|
+
return {
|
|
94
|
+
token: { type: TokenType.OR_IF, value: '||', start: pos, end: pos + 2 },
|
|
95
|
+
nextPos: pos + 2,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
// ── Semicolon ─────────────────────────────────────
|
|
99
|
+
if (ch === ';') {
|
|
100
|
+
return {
|
|
101
|
+
token: { type: TokenType.SEMICOLON, value: ';', start: pos, end: pos + 1 },
|
|
102
|
+
nextPos: pos + 1,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
// ── Background & ──────────────────────────────────
|
|
106
|
+
if (ch === '&') {
|
|
107
|
+
return {
|
|
108
|
+
token: { type: TokenType.BACKGROUND, value: '&', start: pos, end: pos + 1 },
|
|
109
|
+
nextPos: pos + 1,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
// ── Redirect > >> < << <<< >& ─────────────────────
|
|
113
|
+
if (ch === '>' || ch === '<') {
|
|
114
|
+
let end = pos + 1;
|
|
115
|
+
if (input[end] === '>' || input[end] === ch)
|
|
116
|
+
end++;
|
|
117
|
+
if (input[end] === '&' && ch === '>')
|
|
118
|
+
end++;
|
|
119
|
+
return {
|
|
120
|
+
token: { type: TokenType.REDIRECT, value: input.slice(pos, end), start: pos, end },
|
|
121
|
+
nextPos: end,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
// ── Command substitution $(...) ────────────────────
|
|
125
|
+
if (ch === '$' && input[pos + 1] === '(') {
|
|
126
|
+
return this.parseDelimited(input, pos, '$(', ')', TokenType.COMMAND_SUBSTITUTION);
|
|
127
|
+
}
|
|
128
|
+
// ── Backtick substitution `...` ────────────────────
|
|
129
|
+
if (ch === '`') {
|
|
130
|
+
return this.parseDelimited(input, pos, '`', '`', TokenType.BACKTICK_SUBSTITUTION);
|
|
131
|
+
}
|
|
132
|
+
// ── Variable ${...} or $NAME ─────────────────────
|
|
133
|
+
if (ch === '$') {
|
|
134
|
+
if (input[pos + 1] === '{') {
|
|
135
|
+
return this.parseDelimited(input, pos, '${', '}', TokenType.VARIABLE);
|
|
136
|
+
}
|
|
137
|
+
// Simple variable: $NAME, $1, $@, $?
|
|
138
|
+
let end = pos + 1;
|
|
139
|
+
if (/[A-Za-z0-9_?!@#*]/.test(input[end] || '')) {
|
|
140
|
+
end++;
|
|
141
|
+
while (end < input.length && /[A-Za-z0-9_]/.test(input[end]))
|
|
142
|
+
end++;
|
|
143
|
+
}
|
|
144
|
+
return {
|
|
145
|
+
token: { type: TokenType.VARIABLE, value: input.slice(pos, end), start: pos, end },
|
|
146
|
+
nextPos: end,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
// ── Subshell (...) ────────────────────────────────
|
|
150
|
+
if (ch === '(') {
|
|
151
|
+
return this.parseDelimited(input, pos, '(', ')', TokenType.SUBSHELL);
|
|
152
|
+
}
|
|
153
|
+
// ── Single-quoted string ──────────────────────────
|
|
154
|
+
if (ch === "'") {
|
|
155
|
+
const end = input.indexOf("'", pos + 1);
|
|
156
|
+
if (end === -1) {
|
|
157
|
+
// Unterminated — consume rest
|
|
158
|
+
return {
|
|
159
|
+
token: { type: TokenType.STRING, value: input.slice(pos), start: pos, end: input.length },
|
|
160
|
+
nextPos: input.length,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
return {
|
|
164
|
+
token: { type: TokenType.STRING, value: input.slice(pos, end + 1), start: pos, end: end + 1 },
|
|
165
|
+
nextPos: end + 1,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
// ── Double-quoted string ──────────────────────────
|
|
169
|
+
if (ch === '"') {
|
|
170
|
+
const end = input.indexOf('"', pos + 1);
|
|
171
|
+
if (end === -1) {
|
|
172
|
+
return {
|
|
173
|
+
token: { type: TokenType.STRING, value: input.slice(pos), start: pos, end: input.length },
|
|
174
|
+
nextPos: input.length,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
return {
|
|
178
|
+
token: { type: TokenType.STRING, value: input.slice(pos, end + 1), start: pos, end: end + 1 },
|
|
179
|
+
nextPos: end + 1,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
// ── Word (unquoted command/argument) ──────────────
|
|
183
|
+
let end = pos;
|
|
184
|
+
while (end < input.length &&
|
|
185
|
+
!/\s/.test(input[end]) &&
|
|
186
|
+
!'|&;<>$`\'"()'.includes(input[end])) {
|
|
187
|
+
end++;
|
|
188
|
+
}
|
|
189
|
+
if (end > pos) {
|
|
190
|
+
return {
|
|
191
|
+
token: { type: TokenType.WORD, value: input.slice(pos, end), start: pos, end },
|
|
192
|
+
nextPos: end,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
// Consume unknown char
|
|
196
|
+
return {
|
|
197
|
+
token: { type: TokenType.WORD, value: ch, start: pos, end: pos + 1 },
|
|
198
|
+
nextPos: pos + 1,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Parse a delimited token like $(...), ${...}, `...`, (...).
|
|
203
|
+
* Recursively tokenizes inner content.
|
|
204
|
+
*/
|
|
205
|
+
parseDelimited(input, pos, open, close, type) {
|
|
206
|
+
let depth = 1;
|
|
207
|
+
let index = pos + open.length;
|
|
208
|
+
const start = pos;
|
|
209
|
+
while (index < input.length && depth > 0) {
|
|
210
|
+
if (input.slice(index, index + open.length) === open && type === TokenType.SUBSHELL) {
|
|
211
|
+
depth++;
|
|
212
|
+
index += open.length;
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
if (input.slice(index, index + close.length) === close) {
|
|
216
|
+
depth--;
|
|
217
|
+
if (depth === 0) {
|
|
218
|
+
index += close.length;
|
|
219
|
+
break;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
index++;
|
|
223
|
+
}
|
|
224
|
+
const inner = input.slice(start + open.length, index - close.length);
|
|
225
|
+
const innerAst = this.tokenize(inner);
|
|
226
|
+
return {
|
|
227
|
+
token: {
|
|
228
|
+
type,
|
|
229
|
+
value: input.slice(start, index),
|
|
230
|
+
start,
|
|
231
|
+
end: index,
|
|
232
|
+
children: innerAst.commands.length > 0 ? innerAst.commands : undefined,
|
|
233
|
+
},
|
|
234
|
+
nextPos: index,
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Analyze a token for risk.
|
|
239
|
+
*/
|
|
240
|
+
analyzeRisk(tokens) {
|
|
241
|
+
const risk = {
|
|
242
|
+
hasCommandSubstitution: false,
|
|
243
|
+
hasPipes: false,
|
|
244
|
+
hasRedirects: false,
|
|
245
|
+
hasLogicalChains: false,
|
|
246
|
+
dangerousCommands: [],
|
|
247
|
+
shellMetacharacters: [],
|
|
248
|
+
};
|
|
249
|
+
const walkTokens = (list) => {
|
|
250
|
+
for (const token of list) {
|
|
251
|
+
switch (token.type) {
|
|
252
|
+
case TokenType.COMMAND_SUBSTITUTION:
|
|
253
|
+
case TokenType.BACKTICK_SUBSTITUTION:
|
|
254
|
+
risk.hasCommandSubstitution = true;
|
|
255
|
+
if (token.children)
|
|
256
|
+
walkTokens(token.children);
|
|
257
|
+
break;
|
|
258
|
+
case TokenType.PIPE:
|
|
259
|
+
risk.hasPipes = true;
|
|
260
|
+
break;
|
|
261
|
+
case TokenType.REDIRECT:
|
|
262
|
+
risk.hasRedirects = true;
|
|
263
|
+
break;
|
|
264
|
+
case TokenType.AND_IF:
|
|
265
|
+
case TokenType.OR_IF:
|
|
266
|
+
risk.hasLogicalChains = true;
|
|
267
|
+
break;
|
|
268
|
+
case TokenType.WORD:
|
|
269
|
+
if (this.DANGEROUS_COMMANDS.has(token.value.toLowerCase())) {
|
|
270
|
+
if (!risk.dangerousCommands.includes(token.value)) {
|
|
271
|
+
risk.dangerousCommands.push(token.value);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
break;
|
|
275
|
+
case TokenType.SUBSHELL:
|
|
276
|
+
risk.shellMetacharacters.push('(...)');
|
|
277
|
+
if (token.children)
|
|
278
|
+
walkTokens(token.children);
|
|
279
|
+
break;
|
|
280
|
+
case TokenType.VARIABLE:
|
|
281
|
+
risk.shellMetacharacters.push(token.value);
|
|
282
|
+
break;
|
|
283
|
+
default:
|
|
284
|
+
break;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
walkTokens(tokens);
|
|
289
|
+
return risk;
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Full semantic analysis: tokenize + assess risk.
|
|
293
|
+
*/
|
|
294
|
+
analyze(input) {
|
|
295
|
+
const ast = this.tokenize(input);
|
|
296
|
+
const risk = this.analyzeRisk(ast.commands);
|
|
297
|
+
return { ast, risk };
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
//# sourceMappingURL=shell-tokenizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shell-tokenizer.js","sourceRoot":"","sources":["../../src/policy/shell-tokenizer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,CAAN,IAAY,SAaX;AAbD,WAAY,SAAS;IACnB,0BAAa,CAAA;IACb,8BAAiB,CAAA;IACjB,kCAAqB,CAAA;IACrB,0DAA6C,CAAA;IAC7C,4DAA+C,CAAA;IAC/C,0BAAa,CAAA;IACb,kCAAqB,CAAA;IACrB,oCAAuB,CAAA;IACvB,8BAAiB,CAAA;IACjB,4BAAe,CAAA;IACf,sCAAyB,CAAA;IACzB,kCAAqB,CAAA;AACvB,CAAC,EAbW,SAAS,KAAT,SAAS,QAapB;AAsCD;;;;GAIG;AACH,MAAM,OAAO,cAAc;IACR,kBAAkB,GAAG,IAAI,GAAG,CAAC;QAC5C,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;QACpC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ;QAC7C,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ;QAC1C,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK;QAC7C,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK;QACvC,KAAK,EAAE,KAAK,EAAE,OAAO;QACrB,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM;QAC7C,SAAS,EAAE,MAAM,EAAE,YAAY;KAChC,CAAC,CAAC;IAEH;;OAEG;IACH,QAAQ,CAAC,KAAa;QACpB,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,MAAM,MAAM,GAAY,EAAE,CAAC;QAC3B,IAAI,GAAG,GAAG,CAAC,CAAC;QAEZ,OAAO,GAAG,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;YAC1B,kBAAkB;YAClB,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAE,CAAC,EAAE,CAAC;gBAC3B,GAAG,EAAE,CAAC;gBACN,SAAS;YACX,CAAC;YAED,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;YAC1C,IAAI,CAAC,MAAM;gBAAE,MAAM;YAEnB,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC1B,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC;YAErB,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,IAAI,EAAE,CAAC;gBACzC,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC;gBAC9C,IAAI,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;oBACtC,QAAQ,CAAC,IAAI,CAAC,gCAAgC,MAAM,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC;gBACvE,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;IACxC,CAAC;IAED;;OAEG;IACK,SAAS,CAAC,KAAa,EAAE,GAAW;QAC1C,MAAM,EAAE,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;QACtB,IAAI,EAAE,KAAK,SAAS;YAAE,OAAO,IAAI,CAAC;QAElC,qDAAqD;QACrD,IAAI,EAAE,KAAK,GAAG,IAAI,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;YACzC,OAAO;gBACL,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,GAAG,CAAC,EAAE;gBACrE,OAAO,EAAE,GAAG,GAAG,CAAC;aACjB,CAAC;QACJ,CAAC;QAED,sDAAsD;QACtD,IAAI,EAAE,KAAK,GAAG,IAAI,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;YACzC,OAAO;gBACL,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,GAAG,CAAC,EAAE;gBACxE,OAAO,EAAE,GAAG,GAAG,CAAC;aACjB,CAAC;QACJ,CAAC;QACD,IAAI,EAAE,KAAK,GAAG,IAAI,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;YACzC,OAAO;gBACL,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,GAAG,CAAC,EAAE;gBACvE,OAAO,EAAE,GAAG,GAAG,CAAC;aACjB,CAAC;QACJ,CAAC;QAED,qDAAqD;QACrD,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACf,OAAO;gBACL,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,CAAC,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,GAAG,CAAC,EAAE;gBAC1E,OAAO,EAAE,GAAG,GAAG,CAAC;aACjB,CAAC;QACJ,CAAC;QAED,qDAAqD;QACrD,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACf,OAAO;gBACL,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,CAAC,UAAU,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,GAAG,CAAC,EAAE;gBAC3E,OAAO,EAAE,GAAG,GAAG,CAAC;aACjB,CAAC;QACJ,CAAC;QAED,qDAAqD;QACrD,IAAI,EAAE,KAAK,GAAG,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YAC7B,IAAI,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC;YAClB,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,GAAG,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE;gBAAE,GAAG,EAAE,CAAC;YACnD,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,GAAG,IAAI,EAAE,KAAK,GAAG;gBAAE,GAAG,EAAE,CAAC;YAC5C,OAAO;gBACL,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,CAAC,QAAQ,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE;gBAClF,OAAO,EAAE,GAAG;aACb,CAAC;QACJ,CAAC;QAED,sDAAsD;QACtD,IAAI,EAAE,KAAK,GAAG,IAAI,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;YACzC,OAAO,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,SAAS,CAAC,oBAAoB,CAAC,CAAC;QACpF,CAAC;QAED,sDAAsD;QACtD,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACf,OAAO,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,SAAS,CAAC,qBAAqB,CAAC,CAAC;QACpF,CAAC;QAED,oDAAoD;QACpD,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACf,IAAI,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;gBAC3B,OAAO,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC;YACxE,CAAC;YACD,qCAAqC;YACrC,IAAI,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC;YAClB,IAAI,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;gBAC/C,GAAG,EAAE,CAAC;gBACN,OAAO,GAAG,GAAG,KAAK,CAAC,MAAM,IAAI,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAE,CAAC;oBAAE,GAAG,EAAE,CAAC;YACvE,CAAC;YACD,OAAO;gBACL,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,CAAC,QAAQ,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE;gBAClF,OAAO,EAAE,GAAG;aACb,CAAC;QACJ,CAAC;QAED,qDAAqD;QACrD,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACf,OAAO,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC;QACvE,CAAC;QAED,qDAAqD;QACrD,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACf,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC;YACxC,IAAI,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC;gBACf,8BAA8B;gBAC9B,OAAO;oBACL,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,CAAC,MAAM,EAAE;oBACzF,OAAO,EAAE,KAAK,CAAC,MAAM;iBACtB,CAAC;YACJ,CAAC;YACD,OAAO;gBACL,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,GAAG,CAAC,EAAE;gBAC7F,OAAO,EAAE,GAAG,GAAG,CAAC;aACjB,CAAC;QACJ,CAAC;QAED,qDAAqD;QACrD,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACf,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC;YACxC,IAAI,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC;gBACf,OAAO;oBACL,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,CAAC,MAAM,EAAE;oBACzF,OAAO,EAAE,KAAK,CAAC,MAAM;iBACtB,CAAC;YACJ,CAAC;YACD,OAAO;gBACL,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,GAAG,CAAC,EAAE;gBAC7F,OAAO,EAAE,GAAG,GAAG,CAAC;aACjB,CAAC;QACJ,CAAC;QAED,qDAAqD;QACrD,IAAI,GAAG,GAAG,GAAG,CAAC;QACd,OACE,GAAG,GAAG,KAAK,CAAC,MAAM;YAClB,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAE,CAAC;YACvB,CAAC,cAAc,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAE,CAAC,EACrC,CAAC;YACD,GAAG,EAAE,CAAC;QACR,CAAC;QACD,IAAI,GAAG,GAAG,GAAG,EAAE,CAAC;YACd,OAAO;gBACL,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE;gBAC9E,OAAO,EAAE,GAAG;aACb,CAAC;QACJ,CAAC;QAED,uBAAuB;QACvB,OAAO;YACL,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,GAAG,CAAC,EAAE;YACpE,OAAO,EAAE,GAAG,GAAG,CAAC;SACjB,CAAC;IACJ,CAAC;IAED;;;OAGG;IACK,cAAc,CACpB,KAAa,EACb,GAAW,EACX,IAAY,EACZ,KAAa,EACb,IAAe;QAEf,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,IAAI,KAAK,GAAG,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC;QAC9B,MAAM,KAAK,GAAG,GAAG,CAAC;QAElB,OAAO,KAAK,GAAG,KAAK,CAAC,MAAM,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;YACzC,IAAI,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,IAAI,IAAI,KAAK,SAAS,CAAC,QAAQ,EAAE,CAAC;gBACpF,KAAK,EAAE,CAAC;gBACR,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC;gBACrB,SAAS;YACX,CAAC;YACD,IAAI,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,KAAK,EAAE,CAAC;gBACvD,KAAK,EAAE,CAAC;gBACR,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;oBAChB,KAAK,IAAI,KAAK,CAAC,MAAM,CAAC;oBACtB,MAAM;gBACR,CAAC;YACH,CAAC;YACD,KAAK,EAAE,CAAC;QACV,CAAC;QAED,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;QACrE,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAEtC,OAAO;YACL,KAAK,EAAE;gBACL,IAAI;gBACJ,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC;gBAChC,KAAK;gBACL,GAAG,EAAE,KAAK;gBACV,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;aACvE;YACD,OAAO,EAAE,KAAK;SACf,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,WAAW,CAAC,MAAe;QACzB,MAAM,IAAI,GAAgB;YACxB,sBAAsB,EAAE,KAAK;YAC7B,QAAQ,EAAE,KAAK;YACf,YAAY,EAAE,KAAK;YACnB,gBAAgB,EAAE,KAAK;YACvB,iBAAiB,EAAE,EAAE;YACrB,mBAAmB,EAAE,EAAE;SACxB,CAAC;QAEF,MAAM,UAAU,GAAG,CAAC,IAAa,EAAQ,EAAE;YACzC,KAAK,MAAM,KAAK,IAAI,IAAI,EAAE,CAAC;gBACzB,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;oBACnB,KAAK,SAAS,CAAC,oBAAoB,CAAC;oBACpC,KAAK,SAAS,CAAC,qBAAqB;wBAClC,IAAI,CAAC,sBAAsB,GAAG,IAAI,CAAC;wBACnC,IAAI,KAAK,CAAC,QAAQ;4BAAE,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;wBAC/C,MAAM;oBACR,KAAK,SAAS,CAAC,IAAI;wBACjB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;wBACrB,MAAM;oBACR,KAAK,SAAS,CAAC,QAAQ;wBACrB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;wBACzB,MAAM;oBACR,KAAK,SAAS,CAAC,MAAM,CAAC;oBACtB,KAAK,SAAS,CAAC,KAAK;wBAClB,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;wBAC7B,MAAM;oBACR,KAAK,SAAS,CAAC,IAAI;wBACjB,IAAI,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;4BAC3D,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;gCAClD,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;4BAC3C,CAAC;wBACH,CAAC;wBACD,MAAM;oBACR,KAAK,SAAS,CAAC,QAAQ;wBACrB,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;wBACvC,IAAI,KAAK,CAAC,QAAQ;4BAAE,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;wBAC/C,MAAM;oBACR,KAAK,SAAS,CAAC,QAAQ;wBACrB,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;wBAC3C,MAAM;oBACR;wBACE,MAAM;gBACV,CAAC;YACH,CAAC;QACH,CAAC,CAAC;QAEF,UAAU,CAAC,MAAM,CAAC,CAAC;QACnB,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,OAAO,CAAC,KAAa;QACnB,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACjC,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC5C,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;IACvB,CAAC;CACF"}
|
|
@@ -1,10 +1,19 @@
|
|
|
1
|
+
import { createServer } from 'http';
|
|
1
2
|
import { PolicyWatcher } from '../policy/policy-watcher.js';
|
|
3
|
+
import { DashboardAuth } from '../auth/dashboard-auth.js';
|
|
2
4
|
/**
|
|
3
5
|
* Lightweight dashboard server that serves:
|
|
4
|
-
* - / — the dashboard HTML
|
|
5
|
-
* - /
|
|
6
|
-
* - /api/
|
|
7
|
-
* - /
|
|
6
|
+
* - / — the dashboard HTML (requires auth if enabled)
|
|
7
|
+
* - /login — login page (when JWT auth is enabled)
|
|
8
|
+
* - /api/login — POST login endpoint
|
|
9
|
+
* - /api/policy — current policy (JSON, requires auth)
|
|
10
|
+
* - /api/policy/reload — trigger policy reload (requires auth)
|
|
11
|
+
* - /metrics — Prometheus metrics (can be auth-gated or public via DASHBOARD_METRICS_PUBLIC=true)
|
|
12
|
+
*
|
|
13
|
+
* v1.2: Integrated DashboardAuth for JWT/API key authentication, CSRF protection.
|
|
8
14
|
*/
|
|
9
|
-
export declare function startDashboardServer(port?: number, policyWatcher?: PolicyWatcher): Promise<
|
|
15
|
+
export declare function startDashboardServer(port?: number, policyWatcher?: PolicyWatcher, dashboardAuth?: DashboardAuth): Promise<{
|
|
16
|
+
auth: DashboardAuth;
|
|
17
|
+
server: ReturnType<typeof createServer>;
|
|
18
|
+
}>;
|
|
10
19
|
//# sourceMappingURL=dashboard-server.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dashboard-server.d.ts","sourceRoot":"","sources":["../../src/utils/dashboard-server.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"dashboard-server.d.ts","sourceRoot":"","sources":["../../src/utils/dashboard-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAmC,MAAM,MAAM,CAAC;AAKrE,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAM1D;;;;;;;;;;GAUG;AACH,wBAAsB,oBAAoB,CACxC,IAAI,GAAE,MAAa,EACnB,aAAa,CAAC,EAAE,aAAa,EAC7B,aAAa,CAAC,EAAE,aAAa,GAC5B,OAAO,CAAC;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,CAAA;CAAE,CAAC,CA2P3E"}
|