clawsec 0.0.1 → 0.0.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.
- package/dist/src/actions/block.js +2 -2
- package/dist/src/actions/block.js.map +1 -1
- package/dist/src/actions/confirm.d.ts +1 -1
- package/dist/src/actions/confirm.d.ts.map +1 -1
- package/dist/src/actions/confirm.js +57 -26
- package/dist/src/actions/confirm.js.map +1 -1
- package/dist/src/actions/executor.d.ts +3 -1
- package/dist/src/actions/executor.d.ts.map +1 -1
- package/dist/src/actions/executor.js +48 -11
- package/dist/src/actions/executor.js.map +1 -1
- package/dist/src/actions/warn.js +2 -2
- package/dist/src/actions/warn.js.map +1 -1
- package/dist/src/approval/agent-confirm.d.ts +4 -0
- package/dist/src/approval/agent-confirm.d.ts.map +1 -1
- package/dist/src/approval/agent-confirm.js +14 -0
- package/dist/src/approval/agent-confirm.js.map +1 -1
- package/dist/src/approval/store.d.ts +4 -0
- package/dist/src/approval/store.d.ts.map +1 -1
- package/dist/src/approval/store.js +19 -0
- package/dist/src/approval/store.js.map +1 -1
- package/dist/src/config/loader.d.ts +7 -4
- package/dist/src/config/loader.d.ts.map +1 -1
- package/dist/src/config/loader.js +58 -27
- package/dist/src/config/loader.js.map +1 -1
- package/dist/src/config/schema.d.ts +60 -41
- package/dist/src/config/schema.d.ts.map +1 -1
- package/dist/src/config/schema.js +12 -0
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/config/template-loader.d.ts +34 -0
- package/dist/src/config/template-loader.d.ts.map +1 -0
- package/dist/src/config/template-loader.js +127 -0
- package/dist/src/config/template-loader.js.map +1 -0
- package/dist/src/detectors/destructive/cloud-detector.d.ts +10 -3
- package/dist/src/detectors/destructive/cloud-detector.d.ts.map +1 -1
- package/dist/src/detectors/destructive/cloud-detector.js +45 -5
- package/dist/src/detectors/destructive/cloud-detector.js.map +1 -1
- package/dist/src/detectors/destructive/code-detector.d.ts +9 -2
- package/dist/src/detectors/destructive/code-detector.d.ts.map +1 -1
- package/dist/src/detectors/destructive/code-detector.js +43 -4
- package/dist/src/detectors/destructive/code-detector.js.map +1 -1
- package/dist/src/detectors/destructive/index.d.ts +5 -3
- package/dist/src/detectors/destructive/index.d.ts.map +1 -1
- package/dist/src/detectors/destructive/index.js +42 -10
- package/dist/src/detectors/destructive/index.js.map +1 -1
- package/dist/src/detectors/destructive/shell-detector.d.ts +10 -3
- package/dist/src/detectors/destructive/shell-detector.d.ts.map +1 -1
- package/dist/src/detectors/destructive/shell-detector.js +44 -5
- package/dist/src/detectors/destructive/shell-detector.js.map +1 -1
- package/dist/src/detectors/destructive/types.d.ts +6 -0
- package/dist/src/detectors/destructive/types.d.ts.map +1 -1
- package/dist/src/detectors/exfiltration/cloud-detector.d.ts +3 -2
- package/dist/src/detectors/exfiltration/cloud-detector.d.ts.map +1 -1
- package/dist/src/detectors/exfiltration/cloud-detector.js +21 -3
- package/dist/src/detectors/exfiltration/cloud-detector.js.map +1 -1
- package/dist/src/detectors/exfiltration/http-detector.d.ts +3 -2
- package/dist/src/detectors/exfiltration/http-detector.d.ts.map +1 -1
- package/dist/src/detectors/exfiltration/http-detector.js +21 -3
- package/dist/src/detectors/exfiltration/http-detector.js.map +1 -1
- package/dist/src/detectors/exfiltration/index.d.ts +5 -3
- package/dist/src/detectors/exfiltration/index.d.ts.map +1 -1
- package/dist/src/detectors/exfiltration/index.js +44 -11
- package/dist/src/detectors/exfiltration/index.js.map +1 -1
- package/dist/src/detectors/exfiltration/network-detector.d.ts +3 -2
- package/dist/src/detectors/exfiltration/network-detector.d.ts.map +1 -1
- package/dist/src/detectors/exfiltration/network-detector.js +26 -8
- package/dist/src/detectors/exfiltration/network-detector.js.map +1 -1
- package/dist/src/detectors/exfiltration/types.d.ts +2 -0
- package/dist/src/detectors/exfiltration/types.d.ts.map +1 -1
- package/dist/src/detectors/purchase/domain-detector.d.ts +1 -1
- package/dist/src/detectors/purchase/domain-detector.d.ts.map +1 -1
- package/dist/src/detectors/purchase/domain-detector.js +1 -1
- package/dist/src/detectors/purchase/domain-detector.js.map +1 -1
- package/dist/src/detectors/purchase/form-detector.d.ts +2 -2
- package/dist/src/detectors/purchase/form-detector.d.ts.map +1 -1
- package/dist/src/detectors/purchase/form-detector.js +7 -4
- package/dist/src/detectors/purchase/form-detector.js.map +1 -1
- package/dist/src/detectors/purchase/index.d.ts +5 -3
- package/dist/src/detectors/purchase/index.d.ts.map +1 -1
- package/dist/src/detectors/purchase/index.js +35 -6
- package/dist/src/detectors/purchase/index.js.map +1 -1
- package/dist/src/detectors/purchase/spend-tracker.d.ts +6 -2
- package/dist/src/detectors/purchase/spend-tracker.d.ts.map +1 -1
- package/dist/src/detectors/purchase/spend-tracker.js +19 -3
- package/dist/src/detectors/purchase/spend-tracker.js.map +1 -1
- package/dist/src/detectors/purchase/url-detector.d.ts +2 -2
- package/dist/src/detectors/purchase/url-detector.d.ts.map +1 -1
- package/dist/src/detectors/purchase/url-detector.js +3 -3
- package/dist/src/detectors/purchase/url-detector.js.map +1 -1
- package/dist/src/detectors/secrets/api-key-detector.d.ts +6 -6
- package/dist/src/detectors/secrets/api-key-detector.d.ts.map +1 -1
- package/dist/src/detectors/secrets/api-key-detector.js +33 -7
- package/dist/src/detectors/secrets/api-key-detector.js.map +1 -1
- package/dist/src/detectors/secrets/index.d.ts +5 -3
- package/dist/src/detectors/secrets/index.d.ts.map +1 -1
- package/dist/src/detectors/secrets/index.js +52 -11
- package/dist/src/detectors/secrets/index.js.map +1 -1
- package/dist/src/detectors/secrets/pii-detector.d.ts +2 -2
- package/dist/src/detectors/secrets/pii-detector.d.ts.map +1 -1
- package/dist/src/detectors/secrets/pii-detector.js +3 -3
- package/dist/src/detectors/secrets/pii-detector.js.map +1 -1
- package/dist/src/detectors/secrets/token-detector.d.ts +2 -2
- package/dist/src/detectors/secrets/token-detector.d.ts.map +1 -1
- package/dist/src/detectors/secrets/token-detector.js +3 -3
- package/dist/src/detectors/secrets/token-detector.js.map +1 -1
- package/dist/src/detectors/secrets/types.d.ts +5 -3
- package/dist/src/detectors/secrets/types.d.ts.map +1 -1
- package/dist/src/detectors/website/index.d.ts +5 -3
- package/dist/src/detectors/website/index.d.ts.map +1 -1
- package/dist/src/detectors/website/index.js +21 -6
- package/dist/src/detectors/website/index.js.map +1 -1
- package/dist/src/engine/analyzer.d.ts +3 -1
- package/dist/src/engine/analyzer.d.ts.map +1 -1
- package/dist/src/engine/analyzer.js +66 -10
- package/dist/src/engine/analyzer.js.map +1 -1
- package/dist/src/engine/types.d.ts +4 -1
- package/dist/src/engine/types.d.ts.map +1 -1
- package/dist/src/engine/types.js.map +1 -1
- package/dist/src/hooks/before-agent-start/handler.d.ts +3 -1
- package/dist/src/hooks/before-agent-start/handler.d.ts.map +1 -1
- package/dist/src/hooks/before-agent-start/handler.js +59 -12
- package/dist/src/hooks/before-agent-start/handler.js.map +1 -1
- package/dist/src/hooks/before-tool-call/handler.d.ts +3 -1
- package/dist/src/hooks/before-tool-call/handler.d.ts.map +1 -1
- package/dist/src/hooks/before-tool-call/handler.js +86 -54
- package/dist/src/hooks/before-tool-call/handler.js.map +1 -1
- package/dist/src/hooks/tool-result-persist/handler.d.ts +3 -1
- package/dist/src/hooks/tool-result-persist/handler.d.ts.map +1 -1
- package/dist/src/hooks/tool-result-persist/handler.js +36 -34
- package/dist/src/hooks/tool-result-persist/handler.js.map +1 -1
- package/dist/src/index.d.ts +45 -47
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +120 -96
- package/dist/src/index.js.map +1 -1
- package/dist/src/notifications/index.d.ts.map +1 -1
- package/dist/src/notifications/index.js +2 -1
- package/dist/src/notifications/index.js.map +1 -1
- package/dist/src/notifications/telegram.js +1 -1
- package/dist/src/notifications/telegram.js.map +1 -1
- package/dist/src/notifications/types.d.ts +1 -1
- package/dist/src/notifications/types.d.ts.map +1 -1
- package/dist/src/utils/logger.d.ts +26 -0
- package/dist/src/utils/logger.d.ts.map +1 -0
- package/dist/src/utils/logger.js +76 -0
- package/dist/src/utils/logger.js.map +1 -0
- package/openclaw.plugin.json +7 -22
- package/package.json +8 -2
|
@@ -8,28 +8,30 @@ import { createAnalyzer } from '../../engine/analyzer.js';
|
|
|
8
8
|
import { createActionExecutor } from '../../actions/executor.js';
|
|
9
9
|
import { createAgentConfirmHandler } from '../../approval/agent-confirm.js';
|
|
10
10
|
import { getDefaultApprovalStore } from '../../approval/store.js';
|
|
11
|
+
import { createLogger } from '../../utils/logger.js';
|
|
11
12
|
/**
|
|
12
13
|
* Convert hook ToolCallContext to engine ToolCallContext
|
|
13
14
|
* The engine context has a slightly different shape
|
|
14
15
|
*/
|
|
15
16
|
function toEngineContext(hookContext) {
|
|
17
|
+
const toolInput = hookContext.toolInput || {};
|
|
16
18
|
return {
|
|
17
19
|
toolName: hookContext.toolName,
|
|
18
|
-
toolInput
|
|
20
|
+
toolInput,
|
|
19
21
|
// url can be extracted from toolInput if present
|
|
20
|
-
url: typeof
|
|
22
|
+
url: typeof toolInput.url === 'string' ? toolInput.url : undefined,
|
|
21
23
|
};
|
|
22
24
|
}
|
|
23
25
|
/**
|
|
24
|
-
* Convert analysis result and action result to BeforeToolCallResult
|
|
26
|
+
* Convert analysis result and action result to BeforeToolCallResult (modern API)
|
|
25
27
|
*/
|
|
26
28
|
function toBeforeToolCallResult(actionResult, detection) {
|
|
27
29
|
const result = {
|
|
28
|
-
|
|
30
|
+
block: !actionResult.allowed, // Inverted: !allow = block
|
|
29
31
|
};
|
|
30
|
-
// Add block
|
|
32
|
+
// Add block reason if blocked
|
|
31
33
|
if (!actionResult.allowed && actionResult.message) {
|
|
32
|
-
result.
|
|
34
|
+
result.blockReason = actionResult.message;
|
|
33
35
|
}
|
|
34
36
|
// Add metadata from primary detection
|
|
35
37
|
if (detection) {
|
|
@@ -43,48 +45,48 @@ function toBeforeToolCallResult(actionResult, detection) {
|
|
|
43
45
|
result.metadata.rule = detection.metadata.rule;
|
|
44
46
|
}
|
|
45
47
|
}
|
|
46
|
-
// Add pending approval instructions to block
|
|
48
|
+
// Add pending approval instructions to block reason if present
|
|
47
49
|
if (actionResult.pendingApproval) {
|
|
48
50
|
const approvalInfo = `\n\nApproval ID: ${actionResult.pendingApproval.id}\nTimeout: ${actionResult.pendingApproval.timeout}s\nMethods: ${actionResult.pendingApproval.methods.join(', ')}`;
|
|
49
|
-
result.
|
|
51
|
+
result.blockReason = (result.blockReason || 'Approval required') + approvalInfo;
|
|
50
52
|
}
|
|
51
53
|
return result;
|
|
52
54
|
}
|
|
53
55
|
/**
|
|
54
|
-
* Create the allow result for when no threats are detected
|
|
56
|
+
* Create the allow result for when no threats are detected (modern API)
|
|
55
57
|
*/
|
|
56
58
|
function createAllowResult() {
|
|
57
59
|
return {
|
|
58
|
-
|
|
60
|
+
block: false, // Modern: explicit false means allow
|
|
59
61
|
};
|
|
60
62
|
}
|
|
61
63
|
/**
|
|
62
|
-
* Create a result for valid agent-confirm flow
|
|
64
|
+
* Create a result for valid agent-confirm flow (modern API)
|
|
63
65
|
*/
|
|
64
66
|
function createAgentConfirmAllowResult(strippedInput) {
|
|
65
67
|
return {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
+
block: false,
|
|
69
|
+
params: strippedInput, // Modern: renamed from modifiedInput
|
|
68
70
|
};
|
|
69
71
|
}
|
|
70
72
|
/**
|
|
71
|
-
* Create a result for invalid agent-confirm flow
|
|
73
|
+
* Create a result for invalid agent-confirm flow (modern API)
|
|
72
74
|
*/
|
|
73
75
|
function createAgentConfirmInvalidResult(error) {
|
|
74
76
|
return {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
+
block: true, // Modern: true = block
|
|
78
|
+
blockReason: error || 'Invalid or expired approval confirmation',
|
|
77
79
|
metadata: {
|
|
78
80
|
reason: 'Agent confirmation parameter was present but invalid',
|
|
79
81
|
},
|
|
80
82
|
};
|
|
81
83
|
}
|
|
82
84
|
/**
|
|
83
|
-
* Create a result for disabled plugin
|
|
85
|
+
* Create a result for disabled plugin (modern API)
|
|
84
86
|
*/
|
|
85
87
|
function createDisabledResult() {
|
|
86
88
|
return {
|
|
87
|
-
|
|
89
|
+
block: false,
|
|
88
90
|
};
|
|
89
91
|
}
|
|
90
92
|
/**
|
|
@@ -99,58 +101,88 @@ function createDisabledResult() {
|
|
|
99
101
|
*
|
|
100
102
|
* @param config - Clawsec configuration
|
|
101
103
|
* @param options - Optional custom components
|
|
104
|
+
* @param logger - Optional logger instance
|
|
102
105
|
* @returns BeforeToolCallHandler function
|
|
103
106
|
*/
|
|
104
|
-
export function createBeforeToolCallHandler(config, options) {
|
|
107
|
+
export function createBeforeToolCallHandler(config, options, logger) {
|
|
108
|
+
const log = logger ?? createLogger(null, null);
|
|
105
109
|
// Create or use provided components
|
|
106
|
-
const analyzer = options?.analyzer ?? createAnalyzer(config);
|
|
107
|
-
const executor = options?.executor ?? createActionExecutor();
|
|
110
|
+
const analyzer = options?.analyzer ?? createAnalyzer(config, undefined, log);
|
|
111
|
+
const executor = options?.executor ?? createActionExecutor({ logger: log });
|
|
108
112
|
const agentConfirm = options?.agentConfirm ??
|
|
109
113
|
createAgentConfirmHandler({
|
|
110
114
|
enabled: config.approval?.agentConfirm?.enabled ?? true,
|
|
111
115
|
parameterName: config.approval?.agentConfirm?.parameterName,
|
|
112
116
|
store: getDefaultApprovalStore(),
|
|
117
|
+
logger: log,
|
|
113
118
|
});
|
|
114
119
|
// Get the parameter name from config
|
|
115
120
|
const confirmParamName = config.approval?.agentConfirm?.parameterName ?? '_clawsec_confirm';
|
|
116
121
|
return async (context) => {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
122
|
+
try {
|
|
123
|
+
// Normalize context: OpenClaw may send 'params' instead of 'toolInput'
|
|
124
|
+
// Support both field names for backward compatibility
|
|
125
|
+
const normalizedContext = {
|
|
126
|
+
...context,
|
|
127
|
+
toolInput: context.toolInput || context.params || {},
|
|
128
|
+
};
|
|
129
|
+
const toolName = normalizedContext.toolName;
|
|
130
|
+
log.info(`[Hook:before-tool-call] Entry: tool=${toolName}`);
|
|
131
|
+
// Validate context (using normalized version)
|
|
132
|
+
if (!normalizedContext || !normalizedContext.toolName || !normalizedContext.toolInput) {
|
|
133
|
+
log.error(`[Hook:before-tool-call] Invalid context received`, context);
|
|
134
|
+
return createAllowResult(); // Fail-open for invalid context
|
|
135
|
+
}
|
|
136
|
+
// 1. Check if plugin is disabled
|
|
137
|
+
if (config.global?.enabled === false) {
|
|
138
|
+
log.info(`[Hook:before-tool-call] Plugin disabled, allowing tool`);
|
|
139
|
+
return createDisabledResult();
|
|
140
|
+
}
|
|
141
|
+
// 2. Check for agent-confirm parameter
|
|
142
|
+
if (config.approval?.agentConfirm?.enabled !== false) {
|
|
143
|
+
const confirmResult = agentConfirm.checkConfirmation(normalizedContext.toolInput, confirmParamName);
|
|
144
|
+
if (confirmResult.confirmed) {
|
|
145
|
+
// Agent is trying to confirm a previous action
|
|
146
|
+
const processResult = agentConfirm.processConfirmation(normalizedContext.toolInput, confirmParamName);
|
|
147
|
+
if (processResult.valid) {
|
|
148
|
+
// Valid confirmation - strip the parameter and allow
|
|
149
|
+
const strippedInput = agentConfirm.stripConfirmParameter(normalizedContext.toolInput, confirmParamName);
|
|
150
|
+
log.info(`[Hook:before-tool-call] Exit: tool=${toolName}, result=allow (agent-confirm validated)`);
|
|
151
|
+
return createAgentConfirmAllowResult(strippedInput);
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
// Invalid confirmation - block
|
|
155
|
+
log.warn(`[Hook:before-tool-call] Exit: tool=${toolName}, result=block (invalid agent-confirm)`);
|
|
156
|
+
return createAgentConfirmInvalidResult(processResult.error);
|
|
157
|
+
}
|
|
135
158
|
}
|
|
136
159
|
}
|
|
160
|
+
// 3. Run the analyzer (using normalized context)
|
|
161
|
+
const engineContext = toEngineContext(normalizedContext);
|
|
162
|
+
const analysis = await analyzer.analyze(engineContext);
|
|
163
|
+
// 4. If no detections or action is allow/log/warn, handle appropriately
|
|
164
|
+
if (analysis.action === 'allow') {
|
|
165
|
+
log.debug(`[Hook:before-tool-call] Exit: tool=${toolName}, result=allow`);
|
|
166
|
+
return createAllowResult();
|
|
167
|
+
}
|
|
168
|
+
// 5. Execute the action
|
|
169
|
+
const actionContext = {
|
|
170
|
+
analysis,
|
|
171
|
+
toolCall: engineContext,
|
|
172
|
+
config,
|
|
173
|
+
};
|
|
174
|
+
const actionResult = await executor.execute(actionContext);
|
|
175
|
+
// 6. Convert to BeforeToolCallResult
|
|
176
|
+
const result = toBeforeToolCallResult(actionResult, analysis.primaryDetection);
|
|
177
|
+
log.info(`[Hook:before-tool-call] Exit: tool=${toolName}, result=${result.block ? 'block' : 'allow'}`);
|
|
178
|
+
return result;
|
|
137
179
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
return createAllowResult();
|
|
180
|
+
catch (error) {
|
|
181
|
+
// Error handling: log and fail-open (allow the action)
|
|
182
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
183
|
+
log.error(`[Hook:before-tool-call] Unhandled error: ${errorMessage}`, error);
|
|
184
|
+
return createAllowResult(); // Fail-open on errors
|
|
144
185
|
}
|
|
145
|
-
// 5. Execute the action
|
|
146
|
-
const actionContext = {
|
|
147
|
-
analysis,
|
|
148
|
-
toolCall: engineContext,
|
|
149
|
-
config,
|
|
150
|
-
};
|
|
151
|
-
const actionResult = await executor.execute(actionContext);
|
|
152
|
-
// 6. Convert to BeforeToolCallResult
|
|
153
|
-
return toBeforeToolCallResult(actionResult, analysis.primaryDetection);
|
|
154
186
|
};
|
|
155
187
|
}
|
|
156
188
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../../../../src/hooks/before-tool-call/handler.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAiBH,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,EAAE,yBAAyB,EAAE,MAAM,iCAAiC,CAAC;AAC5E,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAclE;;;GAGG;AACH,SAAS,eAAe,CAAC,WAAgC;IACvD,OAAO;QACL,QAAQ,EAAE,WAAW,CAAC,QAAQ;QAC9B,SAAS
|
|
1
|
+
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../../../../src/hooks/before-tool-call/handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import type { ToolResultPersistHandler } from '../../index.js';
|
|
8
8
|
import type { ClawsecConfig } from '../../config/schema.js';
|
|
9
|
+
import { type Logger } from '../../utils/logger.js';
|
|
9
10
|
/**
|
|
10
11
|
* Options for creating a tool-result-persist handler
|
|
11
12
|
*/
|
|
@@ -39,9 +40,10 @@ export interface ToolResultPersistHandlerOptions {
|
|
|
39
40
|
*
|
|
40
41
|
* @param config - Clawsec configuration
|
|
41
42
|
* @param options - Optional handler options
|
|
43
|
+
* @param logger - Optional logger instance
|
|
42
44
|
* @returns ToolResultPersistHandler function
|
|
43
45
|
*/
|
|
44
|
-
export declare function createToolResultPersistHandler(config: ClawsecConfig, options?: ToolResultPersistHandlerOptions): ToolResultPersistHandler;
|
|
46
|
+
export declare function createToolResultPersistHandler(config: ClawsecConfig, options?: ToolResultPersistHandlerOptions, logger?: Logger): ToolResultPersistHandler;
|
|
45
47
|
/**
|
|
46
48
|
* Create a default tool-result-persist handler with default configuration
|
|
47
49
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../../src/hooks/tool-result-persist/handler.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAGV,wBAAwB,EACzB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../../src/hooks/tool-result-persist/handler.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAGV,wBAAwB,EACzB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAK5D,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAElE;;GAEG;AACH,MAAM,WAAW,+BAA+B;IAC9C;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAqDD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,8BAA8B,CAC5C,MAAM,EAAE,aAAa,EACrB,OAAO,CAAC,EAAE,+BAA+B,EACzC,MAAM,CAAC,EAAE,MAAM,GACd,wBAAwB,CA8F1B;AAED;;GAEG;AACH,wBAAgB,qCAAqC,IAAI,wBAAwB,CAmEhF"}
|
|
@@ -4,34 +4,37 @@
|
|
|
4
4
|
* Hook handler that scans tool outputs for secrets/PII, prompt injections,
|
|
5
5
|
* and filters sensitive data before it's persisted.
|
|
6
6
|
*/
|
|
7
|
-
import { createSecretsDetector } from '../../detectors/secrets/index.js';
|
|
8
7
|
import { scan, sanitize } from '../../sanitization/scanner.js';
|
|
9
8
|
import { filterOutput } from './filter.js';
|
|
9
|
+
import { createLogger } from '../../utils/logger.js';
|
|
10
10
|
/**
|
|
11
|
-
* Create an allow result with no filtering
|
|
11
|
+
* Create an allow result with no filtering (modern API)
|
|
12
12
|
*/
|
|
13
13
|
function createAllowResult() {
|
|
14
|
-
return {
|
|
15
|
-
allow: true,
|
|
16
|
-
};
|
|
14
|
+
return {}; // Modern API: empty object means no changes (allow)
|
|
17
15
|
}
|
|
18
16
|
/**
|
|
19
|
-
* Create a block result for detected prompt injections
|
|
17
|
+
* Create a block result for detected prompt injections (modern API)
|
|
18
|
+
* Note: Modern API doesn't support blocking, only filtering.
|
|
19
|
+
* We'll return empty message with redactions metadata.
|
|
20
20
|
*/
|
|
21
21
|
function createBlockResult(redactions) {
|
|
22
22
|
return {
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
message: {
|
|
24
|
+
content: '[BLOCKED: Content violated security policy]',
|
|
25
|
+
redactions,
|
|
26
|
+
},
|
|
25
27
|
};
|
|
26
28
|
}
|
|
27
29
|
/**
|
|
28
|
-
* Create a result with filtered output and redaction info
|
|
30
|
+
* Create a result with filtered output and redaction info (modern API)
|
|
29
31
|
*/
|
|
30
32
|
function createFilteredResult(filteredOutput, redactions) {
|
|
31
33
|
return {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
message: {
|
|
35
|
+
content: filteredOutput,
|
|
36
|
+
redactions,
|
|
37
|
+
},
|
|
35
38
|
};
|
|
36
39
|
}
|
|
37
40
|
/**
|
|
@@ -64,17 +67,15 @@ function outputToString(output) {
|
|
|
64
67
|
*
|
|
65
68
|
* @param config - Clawsec configuration
|
|
66
69
|
* @param options - Optional handler options
|
|
70
|
+
* @param logger - Optional logger instance
|
|
67
71
|
* @returns ToolResultPersistHandler function
|
|
68
72
|
*/
|
|
69
|
-
export function createToolResultPersistHandler(config, options) {
|
|
73
|
+
export function createToolResultPersistHandler(config, options, logger) {
|
|
74
|
+
const log = logger ?? createLogger(null, null);
|
|
70
75
|
const filterEnabled = options?.filter ?? true;
|
|
71
76
|
const scanInjectionsEnabled = options?.scanInjections ?? true;
|
|
72
|
-
//
|
|
73
|
-
|
|
74
|
-
enabled: config.rules?.secrets?.enabled ?? true,
|
|
75
|
-
severity: config.rules?.secrets?.severity ?? 'critical',
|
|
76
|
-
action: config.rules?.secrets?.action ?? 'block',
|
|
77
|
-
});
|
|
77
|
+
// Note: We don't use the async secrets detector here because this handler
|
|
78
|
+
// must be synchronous. The filterOutput function provides synchronous pattern matching.
|
|
78
79
|
// Create scanner config from sanitization rules
|
|
79
80
|
const sanitizationConfig = config.rules?.sanitization;
|
|
80
81
|
const scannerConfig = {
|
|
@@ -88,27 +89,35 @@ export function createToolResultPersistHandler(config, options) {
|
|
|
88
89
|
minConfidence: sanitizationConfig?.minConfidence ?? 0.5,
|
|
89
90
|
redactMatches: sanitizationConfig?.redactMatches ?? false,
|
|
90
91
|
};
|
|
91
|
-
return
|
|
92
|
+
return (context) => {
|
|
93
|
+
const toolName = context.toolName;
|
|
94
|
+
log.debug(`[Hook:tool-result-persist] Entry: tool=${toolName}`);
|
|
92
95
|
// 1. Check if plugin is globally disabled
|
|
93
96
|
if (config.global?.enabled === false) {
|
|
97
|
+
log.debug(`[Hook:tool-result-persist] Plugin disabled, allowing output`);
|
|
94
98
|
return createAllowResult();
|
|
95
99
|
}
|
|
96
100
|
// Convert output to string for scanning
|
|
97
101
|
const toolOutputString = outputToString(context.toolOutput);
|
|
98
102
|
// 2. Run prompt injection scanner if enabled
|
|
99
103
|
if (scanInjectionsEnabled && sanitizationConfig?.enabled !== false && toolOutputString) {
|
|
104
|
+
log.debug(`[Hook:tool-result-persist] Scanning for prompt injections`);
|
|
100
105
|
const scanResult = scan(toolOutputString, scannerConfig);
|
|
101
106
|
if (scanResult.hasInjection) {
|
|
107
|
+
const categories = [...new Set(scanResult.matches.map(m => m.category))];
|
|
108
|
+
log.warn(`[Hook:tool-result-persist] Prompt injection detected: categories=${categories.join(',')}, matches=${scanResult.matches.length}`);
|
|
102
109
|
const injectionRedactions = scanResult.matches.map(match => ({
|
|
103
110
|
type: `injection-${match.category}`,
|
|
104
111
|
description: `Prompt injection detected: ${match.match.substring(0, 50)}${match.match.length > 50 ? '...' : ''}`,
|
|
105
112
|
}));
|
|
106
113
|
// If action is 'block', reject the output entirely
|
|
107
114
|
if (sanitizationConfig?.action === 'block') {
|
|
115
|
+
log.info(`[Hook:tool-result-persist] Blocking output due to injection`);
|
|
108
116
|
return createBlockResult(injectionRedactions);
|
|
109
117
|
}
|
|
110
118
|
// If redactMatches is enabled, sanitize the output
|
|
111
119
|
if (sanitizationConfig?.redactMatches) {
|
|
120
|
+
log.info(`[Hook:tool-result-persist] Sanitizing injection patterns`);
|
|
112
121
|
const sanitizedOutput = sanitize(toolOutputString, scanResult.matches);
|
|
113
122
|
return createFilteredResult(sanitizedOutput, injectionRedactions);
|
|
114
123
|
}
|
|
@@ -120,27 +129,20 @@ export function createToolResultPersistHandler(config, options) {
|
|
|
120
129
|
if (!filterEnabled || config.rules?.secrets?.enabled === false) {
|
|
121
130
|
return createAllowResult();
|
|
122
131
|
}
|
|
123
|
-
// 4.
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
toolInput: context.toolInput,
|
|
129
|
-
toolOutput: toolOutputString,
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
catch {
|
|
133
|
-
// If detection fails, allow the output through without filtering
|
|
134
|
-
// This ensures tool results aren't lost due to detector errors
|
|
135
|
-
return createAllowResult();
|
|
136
|
-
}
|
|
132
|
+
// 4. Skip async secrets detector - filterOutput below does synchronous pattern matching
|
|
133
|
+
// Note: This handler must be synchronous per OpenClaw requirements
|
|
134
|
+
// The filterOutput function (line 211) catches secrets via regex patterns
|
|
135
|
+
log.debug(`[Hook:tool-result-persist] Using synchronous pattern matching for secrets`);
|
|
136
|
+
const detections = [];
|
|
137
137
|
// 5. Filter output with pattern matching (catches secrets detector might have missed)
|
|
138
138
|
const filterResult = filterOutput(context.toolOutput, detections);
|
|
139
139
|
// 6. If nothing was redacted, allow through unchanged
|
|
140
140
|
if (!filterResult.wasRedacted) {
|
|
141
|
+
log.debug(`[Hook:tool-result-persist] Exit: tool=${toolName}, no filtering needed`);
|
|
141
142
|
return createAllowResult();
|
|
142
143
|
}
|
|
143
144
|
// 7. Return filtered result with redaction metadata
|
|
145
|
+
log.info(`[Hook:tool-result-persist] Exit: tool=${toolName}, redactions=${filterResult.redactions.length}`);
|
|
144
146
|
return createFilteredResult(filterResult.filteredOutput, filterResult.redactions);
|
|
145
147
|
};
|
|
146
148
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../../../../src/hooks/tool-result-persist/handler.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../../../../src/hooks/tool-result-persist/handler.ts"],"names":[],"mappings":"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"}
|
package/dist/src/index.d.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
export declare const VERSION = "0.0.1";
|
|
6
6
|
export declare const PLUGIN_ID = "clawsec";
|
|
7
7
|
export declare const PLUGIN_NAME = "Clawsec Security Plugin";
|
|
8
|
+
import { type Logger } from './utils/logger.js';
|
|
8
9
|
/**
|
|
9
10
|
* Severity levels for security detections
|
|
10
11
|
*/
|
|
@@ -16,12 +17,12 @@ export type Action = 'block' | 'confirm' | 'agent-confirm' | 'warn' | 'log';
|
|
|
16
17
|
/**
|
|
17
18
|
* Categories of security threats
|
|
18
19
|
*/
|
|
19
|
-
export type ThreatCategory = 'purchase' | 'website' | 'destructive' | 'secrets' | 'exfiltration';
|
|
20
|
+
export type ThreatCategory = 'purchase' | 'website' | 'destructive' | 'secrets' | 'exfiltration' | 'unknown';
|
|
20
21
|
/**
|
|
21
22
|
* Base context provided to all hooks
|
|
22
23
|
*/
|
|
23
24
|
export interface HookContext {
|
|
24
|
-
sessionId
|
|
25
|
+
sessionId?: string;
|
|
25
26
|
userId?: string;
|
|
26
27
|
timestamp: number;
|
|
27
28
|
}
|
|
@@ -30,22 +31,23 @@ export interface HookContext {
|
|
|
30
31
|
*/
|
|
31
32
|
export interface ToolCallContext extends HookContext {
|
|
32
33
|
toolName: string;
|
|
33
|
-
toolInput
|
|
34
|
+
toolInput?: Record<string, unknown>;
|
|
35
|
+
params?: Record<string, unknown>;
|
|
34
36
|
conversationHistory?: Array<{
|
|
35
37
|
role: 'user' | 'assistant';
|
|
36
38
|
content: string;
|
|
37
39
|
}>;
|
|
38
40
|
}
|
|
39
41
|
/**
|
|
40
|
-
* Result from before-tool-call hook
|
|
42
|
+
* Result from before-tool-call hook (modern API)
|
|
41
43
|
*/
|
|
42
44
|
export interface BeforeToolCallResult {
|
|
43
|
-
/** Whether to
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
|
|
45
|
+
/** Whether to block the tool call (default: false = allow) */
|
|
46
|
+
block?: boolean;
|
|
47
|
+
/** Reason for blocking (if blocked) */
|
|
48
|
+
blockReason?: string;
|
|
49
|
+
/** Modified tool parameters (if transformed) */
|
|
50
|
+
params?: Record<string, unknown>;
|
|
49
51
|
/** Metadata about the detection */
|
|
50
52
|
metadata?: {
|
|
51
53
|
category?: ThreatCategory;
|
|
@@ -64,13 +66,22 @@ export type BeforeToolCallHandler = (context: ToolCallContext) => Promise<Before
|
|
|
64
66
|
export interface AgentStartContext extends HookContext {
|
|
65
67
|
systemPrompt?: string;
|
|
66
68
|
agentConfig?: Record<string, unknown>;
|
|
69
|
+
prompt?: string;
|
|
70
|
+
messages?: Array<{
|
|
71
|
+
role: 'user' | 'assistant' | 'toolResult' | string;
|
|
72
|
+
content: unknown;
|
|
73
|
+
timestamp?: number;
|
|
74
|
+
[key: string]: unknown;
|
|
75
|
+
}>;
|
|
67
76
|
}
|
|
68
77
|
/**
|
|
69
|
-
* Result from before-agent-start hook
|
|
78
|
+
* Result from before-agent-start hook (modern API)
|
|
70
79
|
*/
|
|
71
80
|
export interface BeforeAgentStartResult {
|
|
72
|
-
/**
|
|
73
|
-
|
|
81
|
+
/** System prompt replacement (replaces entire prompt) */
|
|
82
|
+
systemPrompt?: string;
|
|
83
|
+
/** Context to prepend before user message (OpenClaw's actual API field) */
|
|
84
|
+
prependContext?: string;
|
|
74
85
|
/** Modified agent configuration */
|
|
75
86
|
modifiedConfig?: Record<string, unknown>;
|
|
76
87
|
}
|
|
@@ -87,49 +98,38 @@ export interface ToolResultContext extends HookContext {
|
|
|
87
98
|
toolOutput: unknown;
|
|
88
99
|
}
|
|
89
100
|
/**
|
|
90
|
-
* Result from tool-result-persist hook
|
|
101
|
+
* Result from tool-result-persist hook (modern API)
|
|
91
102
|
*/
|
|
92
103
|
export interface ToolResultPersistResult {
|
|
93
|
-
/**
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}>;
|
|
104
|
+
/** Modified message object (if filtering/redacting) */
|
|
105
|
+
message?: {
|
|
106
|
+
content?: unknown;
|
|
107
|
+
redactions?: Array<{
|
|
108
|
+
type: string;
|
|
109
|
+
description: string;
|
|
110
|
+
}>;
|
|
111
|
+
};
|
|
102
112
|
}
|
|
103
113
|
/**
|
|
104
114
|
* Handler type for tool-result-persist hook
|
|
115
|
+
* Note: This hook must be synchronous per OpenClaw requirements
|
|
105
116
|
*/
|
|
106
|
-
export type ToolResultPersistHandler = (context: ToolResultContext) =>
|
|
117
|
+
export type ToolResultPersistHandler = (context: ToolResultContext) => ToolResultPersistResult;
|
|
107
118
|
/**
|
|
108
119
|
* OpenClaw plugin API interface
|
|
109
120
|
*/
|
|
110
121
|
export interface OpenClawPluginAPI {
|
|
111
|
-
/** Register a hook handler */
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
|
|
122
|
+
/** Register a hook handler (modern event-based API) */
|
|
123
|
+
on: (hookName: string, handler: unknown, options?: {
|
|
124
|
+
priority?: number;
|
|
125
|
+
}) => void;
|
|
126
|
+
/** Plugin configuration */
|
|
127
|
+
config: PluginConfig;
|
|
117
128
|
/** Log a message */
|
|
118
129
|
log: (level: 'debug' | 'info' | 'warn' | 'error', message: string, data?: unknown) => void;
|
|
119
130
|
/** Request user approval */
|
|
120
131
|
requestApproval: (request: ApprovalRequest) => Promise<ApprovalResponse>;
|
|
121
132
|
}
|
|
122
|
-
/**
|
|
123
|
-
* Hook registration options
|
|
124
|
-
*/
|
|
125
|
-
export interface HookOptions {
|
|
126
|
-
/** Unique identifier for this handler */
|
|
127
|
-
id?: string;
|
|
128
|
-
/** Priority (lower runs first) */
|
|
129
|
-
priority?: number;
|
|
130
|
-
/** Whether this hook is enabled */
|
|
131
|
-
enabled?: boolean;
|
|
132
|
-
}
|
|
133
133
|
/**
|
|
134
134
|
* Plugin configuration from OpenClaw
|
|
135
135
|
*/
|
|
@@ -161,15 +161,13 @@ export interface ApprovalResponse {
|
|
|
161
161
|
approvedBy?: string;
|
|
162
162
|
timestamp: number;
|
|
163
163
|
}
|
|
164
|
+
import type { ClawsecConfig } from './config/schema.js';
|
|
164
165
|
interface PluginState {
|
|
165
166
|
api: OpenClawPluginAPI | null;
|
|
166
167
|
config: PluginConfig | null;
|
|
168
|
+
clawsecConfig: ClawsecConfig | null;
|
|
167
169
|
initialized: boolean;
|
|
168
|
-
|
|
169
|
-
beforeToolCall: BeforeToolCallHandler | null;
|
|
170
|
-
beforeAgentStart: BeforeAgentStartHandler | null;
|
|
171
|
-
toolResultPersist: ToolResultPersistHandler | null;
|
|
172
|
-
};
|
|
170
|
+
logger: Logger;
|
|
173
171
|
}
|
|
174
172
|
/**
|
|
175
173
|
* Activates the Clawsec security plugin and registers all hooks.
|
|
@@ -221,7 +219,7 @@ export declare const pluginConfigSchema: {
|
|
|
221
219
|
*
|
|
222
220
|
* @param api - The OpenClaw plugin API
|
|
223
221
|
*/
|
|
224
|
-
declare function register(api: OpenClawPluginAPI): void;
|
|
222
|
+
declare function register(api: OpenClawPluginAPI): () => void;
|
|
225
223
|
declare const _default: {
|
|
226
224
|
id: string;
|
|
227
225
|
name: string;
|