podwatch 1.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.
Files changed (51) hide show
  1. package/LICENSE +28 -0
  2. package/README.md +92 -0
  3. package/bin/podwatch.js +10 -0
  4. package/dist/classifier.d.ts +22 -0
  5. package/dist/classifier.d.ts.map +1 -0
  6. package/dist/classifier.js +157 -0
  7. package/dist/classifier.js.map +1 -0
  8. package/dist/hooks/cost.d.ts +26 -0
  9. package/dist/hooks/cost.d.ts.map +1 -0
  10. package/dist/hooks/cost.js +107 -0
  11. package/dist/hooks/cost.js.map +1 -0
  12. package/dist/hooks/lifecycle.d.ts +16 -0
  13. package/dist/hooks/lifecycle.d.ts.map +1 -0
  14. package/dist/hooks/lifecycle.js +273 -0
  15. package/dist/hooks/lifecycle.js.map +1 -0
  16. package/dist/hooks/security.d.ts +19 -0
  17. package/dist/hooks/security.d.ts.map +1 -0
  18. package/dist/hooks/security.js +128 -0
  19. package/dist/hooks/security.js.map +1 -0
  20. package/dist/hooks/sessions.d.ts +10 -0
  21. package/dist/hooks/sessions.d.ts.map +1 -0
  22. package/dist/hooks/sessions.js +53 -0
  23. package/dist/hooks/sessions.js.map +1 -0
  24. package/dist/index.d.ts +32 -0
  25. package/dist/index.d.ts.map +1 -0
  26. package/dist/index.js +120 -0
  27. package/dist/index.js.map +1 -0
  28. package/dist/redact.d.ts +35 -0
  29. package/dist/redact.d.ts.map +1 -0
  30. package/dist/redact.js +372 -0
  31. package/dist/redact.js.map +1 -0
  32. package/dist/scanner.d.ts +27 -0
  33. package/dist/scanner.d.ts.map +1 -0
  34. package/dist/scanner.js +117 -0
  35. package/dist/scanner.js.map +1 -0
  36. package/dist/transmitter.d.ts +58 -0
  37. package/dist/transmitter.d.ts.map +1 -0
  38. package/dist/transmitter.js +654 -0
  39. package/dist/transmitter.js.map +1 -0
  40. package/dist/types.d.ts +116 -0
  41. package/dist/types.d.ts.map +1 -0
  42. package/dist/types.js +9 -0
  43. package/dist/types.js.map +1 -0
  44. package/dist/updater.d.ts +168 -0
  45. package/dist/updater.d.ts.map +1 -0
  46. package/dist/updater.js +579 -0
  47. package/dist/updater.js.map +1 -0
  48. package/lib/installer.js +599 -0
  49. package/openclaw.plugin.json +59 -0
  50. package/package.json +56 -0
  51. package/skills/podwatch/SKILL.md +112 -0
package/dist/index.js ADDED
@@ -0,0 +1,120 @@
1
+ "use strict";
2
+ /**
3
+ * Podwatch Plugin — OpenClaw cost monitoring, budget enforcement, and security alerts.
4
+ *
5
+ * Registers hook handlers and subscribes to diagnostic events to capture:
6
+ * - Cost/token data per LLM call (onDiagnosticEvent → model.usage)
7
+ * - Tool security scanning + budget blocking (before_tool_call)
8
+ * - Tool latency + success/failure (after_tool_call)
9
+ * - Session lifecycle (session_start, session_end)
10
+ * - Context pressure (before_compaction)
11
+ * - Pulse alive-ping + skill/plugin scanning (register())
12
+ * - Graceful shutdown (gateway_stop)
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.default = register;
16
+ const cost_js_1 = require("./hooks/cost.js");
17
+ const security_js_1 = require("./hooks/security.js");
18
+ const sessions_js_1 = require("./hooks/sessions.js");
19
+ const lifecycle_js_1 = require("./hooks/lifecycle.js");
20
+ const transmitter_js_1 = require("./transmitter.js");
21
+ const updater_js_1 = require("./updater.js");
22
+ // ---------------------------------------------------------------------------
23
+ // Plugin registration
24
+ // ---------------------------------------------------------------------------
25
+ const DEBUG = !!process.env.PODWATCH_DEBUG;
26
+ /**
27
+ * Redact sensitive fields from an object for safe debug logging.
28
+ * Returns a shallow copy with secret values replaced by '***'.
29
+ */
30
+ function redactForLog(obj) {
31
+ if (!obj || typeof obj !== "object")
32
+ return obj;
33
+ const SENSITIVE_KEYS = ["apiKey", "apiSecret", "secret", "token", "password", "key"];
34
+ const redacted = { ...obj };
35
+ for (const k of SENSITIVE_KEYS) {
36
+ if (k in redacted && redacted[k]) {
37
+ redacted[k] = "***";
38
+ }
39
+ }
40
+ return redacted;
41
+ }
42
+ /**
43
+ * OpenClaw plugin entry point.
44
+ * Called by the Gateway when the plugin is loaded.
45
+ */
46
+ function register(api) {
47
+ if (DEBUG) {
48
+ console.log("[podwatch:debug] register() called");
49
+ console.log("[podwatch:debug] api object keys:", Object.keys(api));
50
+ // Log only safe gateway config fields — never dump the full api.config
51
+ const safeConfigKeys = api.config
52
+ ? { diagnostics: api.config.diagnostics, agents: api.config.agents ? "(present)" : "(absent)" }
53
+ : "(undefined)";
54
+ console.log("[podwatch:debug] api.config (safe fields):", JSON.stringify(safeConfigKeys, null, 2));
55
+ console.log("[podwatch:debug] api.pluginConfig:", JSON.stringify(redactForLog(api.pluginConfig ?? {}), null, 2));
56
+ console.log("[podwatch:debug] api.runtime keys:", api.runtime ? Object.keys(api.runtime) : "undefined");
57
+ }
58
+ const config = resolveConfig(api);
59
+ if (DEBUG) {
60
+ console.log("[podwatch:debug] Resolved config:", JSON.stringify(redactForLog(config), null, 2));
61
+ }
62
+ if (!config.apiKey) {
63
+ api.logger.error("[podwatch] No API key configured. Set it in plugins.entries.podwatch.config.apiKey");
64
+ return;
65
+ }
66
+ // Start the transmitter (batched HTTP to Podwatch cloud)
67
+ transmitter_js_1.transmitter.start({
68
+ apiKey: config.apiKey,
69
+ endpoint: config.endpoint ?? "https://podwatch.app/api",
70
+ batchSize: 50,
71
+ flushIntervalMs: 30_000,
72
+ });
73
+ // Check if diagnostics are enabled
74
+ const diagnosticsEnabled = api.config?.diagnostics?.enabled === true;
75
+ if (!diagnosticsEnabled) {
76
+ api.logger.warn("[podwatch] diagnostics.enabled is not set to true in gateway config. " +
77
+ "Cost tracking will not work. Enable it: diagnostics: { enabled: true }");
78
+ // POST setup warning to dashboard
79
+ transmitter_js_1.transmitter.enqueue({
80
+ type: "setup_warning",
81
+ message: "Enable diagnostics for cost tracking: set diagnostics.enabled: true in openclaw.json",
82
+ ts: Date.now(),
83
+ });
84
+ }
85
+ // Register all hook handlers
86
+ (0, cost_js_1.registerCostHandler)(api, config, diagnosticsEnabled);
87
+ (0, security_js_1.registerSecurityHandlers)(api, config);
88
+ (0, sessions_js_1.registerSessionHandlers)(api);
89
+ (0, lifecycle_js_1.registerLifecycleHandlers)(api, config);
90
+ // Schedule non-blocking auto-update check (30s after boot, 24h cooldown)
91
+ // Auto-update is opt-in (default false) for supply chain security.
92
+ const currentVersion = api.version ?? "0.0.0";
93
+ const endpoint = config.endpoint ?? "https://podwatch.app/api";
94
+ (0, updater_js_1.scheduleUpdateCheck)(currentVersion, endpoint, api.logger, { autoUpdate: config.autoUpdate });
95
+ api.logger.info(`[podwatch] Plugin loaded (v${currentVersion}). Budget enforcement: ${config.enableBudgetEnforcement ? "ON" : "OFF"}, ` +
96
+ `Security alerts: ${config.enableSecurityAlerts ? "ON" : "OFF"}, ` +
97
+ `Diagnostics: ${diagnosticsEnabled ? "ON" : "OFF"}`);
98
+ }
99
+ // ---------------------------------------------------------------------------
100
+ // Config resolution
101
+ // ---------------------------------------------------------------------------
102
+ function resolveConfig(api) {
103
+ const pluginConfig = api.pluginConfig ?? {};
104
+ if (DEBUG) {
105
+ console.log("[podwatch:debug] resolveConfig() — raw pluginConfig:", JSON.stringify(redactForLog(pluginConfig), null, 2));
106
+ console.log("[podwatch:debug] resolveConfig() — env PODWATCH_API_KEY set:", !!process.env.PODWATCH_API_KEY);
107
+ console.log("[podwatch:debug] resolveConfig() — env PODWATCH_ENDPOINT:", process.env.PODWATCH_ENDPOINT ?? "(unset)");
108
+ }
109
+ return {
110
+ apiKey: pluginConfig.apiKey ?? process.env.PODWATCH_API_KEY ?? "",
111
+ endpoint: pluginConfig.endpoint ?? process.env.PODWATCH_ENDPOINT,
112
+ enableBudgetEnforcement: pluginConfig.enableBudgetEnforcement ?? true,
113
+ enableSecurityAlerts: pluginConfig.enableSecurityAlerts ?? true,
114
+ autoUpdate: pluginConfig.autoUpdate ?? false,
115
+ // Backward compat: fall back to heartbeatIntervalMs if pulseIntervalMs not set
116
+ pulseIntervalMs: pluginConfig.pulseIntervalMs ?? pluginConfig.heartbeatIntervalMs ?? 300_000,
117
+ scanIntervalMs: pluginConfig.scanIntervalMs ?? 21_600_000, // 6 hours
118
+ };
119
+ }
120
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Param redaction — strips sensitive values before transmitting to dashboard.
3
+ *
4
+ * Keeps structure but replaces values of sensitive keys with "[REDACTED]".
5
+ * Truncates long string values to prevent bloated payloads.
6
+ *
7
+ * Returns { result, redactedCount } so callers can track how many fields
8
+ * were scrubbed (heavy redaction > 3 feeds into risk classification).
9
+ */
10
+ declare const SENSITIVE_KEYS: Set<string>;
11
+ declare const SENSITIVE_VALUE_PATTERNS: RegExp[];
12
+ /**
13
+ * Calculate Shannon entropy of a string.
14
+ * Higher values indicate more randomness (potential secrets).
15
+ */
16
+ declare function shannonEntropy(s: string): number;
17
+ declare function looksLikeToken(s: string): boolean;
18
+ /**
19
+ * Length-based entropy thresholds.
20
+ * Short high-entropy strings (20-32 chars) are often UUIDs/hashes, not secrets.
21
+ * Longer strings need less entropy to be suspicious.
22
+ */
23
+ declare function getEntropyThreshold(length: number): number;
24
+ declare function isHighEntropySecret(s: string): boolean;
25
+ export interface RedactResult {
26
+ result: Record<string, unknown>;
27
+ redactedCount: number;
28
+ }
29
+ /**
30
+ * Redact sensitive values from tool call params.
31
+ * Returns the scrubbed object and a count of how many values were redacted.
32
+ */
33
+ export declare function redactParams(params: Record<string, unknown>): RedactResult;
34
+ export { shannonEntropy, looksLikeToken, isHighEntropySecret, getEntropyThreshold, SENSITIVE_VALUE_PATTERNS, SENSITIVE_KEYS };
35
+ //# sourceMappingURL=redact.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redact.d.ts","sourceRoot":"","sources":["../src/redact.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,QAAA,MAAM,cAAc,aAgFlB,CAAC;AAMH,QAAA,MAAM,wBAAwB,EAAE,MAAM,EAmGrC,CAAC;AAMF;;;GAGG;AACH,iBAAS,cAAc,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAYzC;AAcD,iBAAS,cAAc,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAY1C;AAID;;;;GAIG;AACH,iBAAS,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAInD;AAED,iBAAS,mBAAmB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAI/C;AAaD,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,aAAa,EAAE,MAAM,CAAC;CACvB;AA4CD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,YAAY,CAK1E;AA+ED,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,cAAc,EAAE,CAAC"}
package/dist/redact.js ADDED
@@ -0,0 +1,372 @@
1
+ "use strict";
2
+ /**
3
+ * Param redaction — strips sensitive values before transmitting to dashboard.
4
+ *
5
+ * Keeps structure but replaces values of sensitive keys with "[REDACTED]".
6
+ * Truncates long string values to prevent bloated payloads.
7
+ *
8
+ * Returns { result, redactedCount } so callers can track how many fields
9
+ * were scrubbed (heavy redaction > 3 feeds into risk classification).
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.SENSITIVE_KEYS = exports.SENSITIVE_VALUE_PATTERNS = void 0;
13
+ exports.redactParams = redactParams;
14
+ exports.shannonEntropy = shannonEntropy;
15
+ exports.looksLikeToken = looksLikeToken;
16
+ exports.isHighEntropySecret = isHighEntropySecret;
17
+ exports.getEntropyThreshold = getEntropyThreshold;
18
+ // ---------------------------------------------------------------------------
19
+ // Sensitive key patterns (normalized: lowercase, no hyphens/underscores)
20
+ // ---------------------------------------------------------------------------
21
+ const SENSITIVE_KEYS = new Set([
22
+ // Original
23
+ "password",
24
+ "secret",
25
+ "token",
26
+ "apikey",
27
+ "api_key",
28
+ "authorization",
29
+ "credentials",
30
+ "private_key",
31
+ "privatekey",
32
+ "access_token",
33
+ "accesstoken",
34
+ "refresh_token",
35
+ "refreshtoken",
36
+ "client_secret",
37
+ "clientsecret",
38
+ "bearer",
39
+ "cookie",
40
+ "session_id",
41
+ "sessionid",
42
+ "passphrase",
43
+ // Encryption / signing
44
+ "encryptionkey",
45
+ "encryption_key",
46
+ "signingkey",
47
+ "signing_key",
48
+ "masterkey",
49
+ "master_key",
50
+ // Database
51
+ "databaseurl",
52
+ "database_url",
53
+ "dburl",
54
+ "db_url",
55
+ "dbpassword",
56
+ "db_password",
57
+ "connectionstring",
58
+ "connection_string",
59
+ // Communication / SMTP
60
+ "smtppassword",
61
+ "smtp_password",
62
+ "webhooksecret",
63
+ "webhook_secret",
64
+ // JWT / App
65
+ "jwtsecret",
66
+ "jwt_secret",
67
+ "appsecret",
68
+ "app_secret",
69
+ // Crypto primitives (when used as keys)
70
+ "hmac",
71
+ "nonce",
72
+ "salt",
73
+ // Provider-specific key names
74
+ "resendapikey",
75
+ "resend_api_key",
76
+ "inngestkey",
77
+ "inngest_signing_key",
78
+ "planetscaletoken",
79
+ "planetscale_token",
80
+ "railwaytoken",
81
+ "railway_token",
82
+ "renderkey",
83
+ "render_api_key",
84
+ "postmarktoken",
85
+ "postmark_server_token",
86
+ "postmark_api_token",
87
+ "lemonsqueezyapikey",
88
+ "lemon_squeezy_api_key",
89
+ "pineconeapikey",
90
+ "pinecone_api_key",
91
+ "weaviateapikey",
92
+ "weaviate_api_key",
93
+ "flyapitoken",
94
+ "fly_api_token",
95
+ ]);
96
+ exports.SENSITIVE_KEYS = SENSITIVE_KEYS;
97
+ // ---------------------------------------------------------------------------
98
+ // Value-based patterns (regex detection on string values)
99
+ // ---------------------------------------------------------------------------
100
+ const SENSITIVE_VALUE_PATTERNS = [
101
+ // --- AI / LLM Providers ---
102
+ /^sk-[a-zA-Z0-9]{20,}/, // OpenAI keys
103
+ /sk-ant-api03-[a-zA-Z0-9_-]{93}AA/, // Anthropic API key
104
+ /sk-ant-admin01-[a-zA-Z0-9_-]{93}AA/, // Anthropic admin key
105
+ /AIza[0-9A-Za-z_-]{35}/, // Google/GCP API key
106
+ /GOCSPX-[a-zA-Z0-9_-]+/, // Google OAuth client secret
107
+ /^co-[a-zA-Z0-9]{40}$/, // Cohere API key
108
+ /^r8_[a-zA-Z0-9]{40}$/, // Replicate API key
109
+ /^hf_[a-zA-Z0-9]{34}$/, // HuggingFace token
110
+ // --- Auth / Identity Providers ---
111
+ /^sk_live_[a-zA-Z0-9]+/, // Clerk/Stripe live secret
112
+ /^pk_live_[a-zA-Z0-9]+/, // Clerk/Stripe live public
113
+ /^sk_test_[a-zA-Z0-9]+/, // Clerk/Stripe test secret
114
+ /^pk_test_[a-zA-Z0-9]+/, // Clerk/Stripe test public
115
+ /^sbp_[a-zA-Z0-9]+/, // Supabase project token
116
+ /^eyJ[a-zA-Z0-9._-]{50,}/, // JWT tokens (also catches Supabase service role JWTs)
117
+ // --- Cloud / Infrastructure ---
118
+ /^AKIA[A-Z0-9]{16}/, // AWS access key (permanent)
119
+ /^ASIA[A-Z0-9]{16}/, // AWS access key (temporary/STS)
120
+ /^ABIA[A-Z0-9]{16}/, // AWS access key (STS for billing)
121
+ /^vercel_[a-zA-Z0-9_]+/, // Vercel token
122
+ /^hvs\.[a-zA-Z0-9_-]+/, // Hashicorp Vault token
123
+ /^dp\.st\.[a-zA-Z0-9_-]+/, // Doppler service token
124
+ /[a-zA-Z0-9]{14}\.atlasv1\.[a-zA-Z0-9_-]{60,}/, // Terraform Cloud token
125
+ // --- Database / Connection Strings (CRITICAL) ---
126
+ /postgres(?:ql)?:\/\/[^:]+:[^@]+@[^\s]+/, // Postgres connection string
127
+ /mysql:\/\/[^:]+:[^@]+@[^\s]+/, // MySQL connection string
128
+ /mongodb(?:\+srv)?:\/\/[^:]+:[^@]+@[^\s]+/, // MongoDB connection string
129
+ /redis:\/\/[^:]+:[^@]+@[^\s]+/, // Redis connection string
130
+ /[a-zA-Z][a-zA-Z0-9+.-]*:\/\/[^:]+:[^@]+@/, // Any URI with embedded credentials
131
+ // --- Communication ---
132
+ /^xoxb-[0-9]+-[0-9A-Za-z]+/, // Slack bot token
133
+ /^xoxp-[0-9]+-[0-9A-Za-z]+/, // Slack user token
134
+ /^xapp-[0-9]+-[0-9A-Za-z]+/, // Slack app token
135
+ /^SG\.[a-zA-Z0-9_-]{22}\.[a-zA-Z0-9_-]{43}$/, // SendGrid API key
136
+ /^SK[a-f0-9]{32}$/, // Twilio API key
137
+ /[0-9]+:AA[a-zA-Z0-9_-]{33}/, // Telegram bot token
138
+ // --- Package Registries ---
139
+ /^npm_[a-zA-Z0-9]{36}$/, // npm token
140
+ /^pypi-[a-zA-Z0-9_-]{100,}/, // PyPI token
141
+ // --- Secret Management ---
142
+ /^ops_eyJ[a-zA-Z0-9+/]{250,}={0,3}$/, // 1Password service token
143
+ /^A3-[A-Z0-9]{6}-[A-Z0-9]{6,11}-[A-Z0-9]{5}-[A-Z0-9]{5}-[A-Z0-9]{5}$/, // 1Password secret key
144
+ // --- Crypto ---
145
+ /^AGE-SECRET-KEY-1[A-Z0-9]{58}$/, // Age encryption key
146
+ // --- SSH / Certificates ---
147
+ /-----BEGIN\s+PRIVATE\s+KEY/, // PKCS8 generic
148
+ /-----BEGIN\s+RSA\s+PRIVATE\s+KEY/, // RSA
149
+ /-----BEGIN\s+OPENSSH\s+PRIVATE\s+KEY/, // OpenSSH
150
+ /-----BEGIN\s+EC\s+PRIVATE\s+KEY/, // EC
151
+ /-----BEGIN\s+DSA\s+PRIVATE\s+KEY/, // DSA
152
+ /-----BEGIN\s+ENCRYPTED\s+PRIVATE\s+KEY/, // Encrypted PKCS8
153
+ /-----BEGIN\s+CERTIFICATE/, // X.509 certificate
154
+ // --- Auth headers ---
155
+ /^Bearer\s+[a-zA-Z0-9._-]{20,}/i, // Bearer tokens
156
+ /^Basic\s+[a-zA-Z0-9+/=]{20,}/i, // Basic auth
157
+ // --- GitHub ---
158
+ /^ghp_[a-zA-Z0-9]{36,}/, // GitHub PAT
159
+ /^gho_[a-zA-Z0-9]{36,}/, // GitHub OAuth
160
+ /^ghs_[a-zA-Z0-9]{36,}/, // GitHub App installation
161
+ /^ghr_[a-zA-Z0-9]{36,}/, // GitHub refresh token
162
+ // --- Podwatch ---
163
+ /^pw_[a-zA-Z0-9]{20,}/, // Podwatch keys
164
+ // --- Tavily ---
165
+ /^tvly-[a-zA-Z0-9]{20,}/, // Tavily keys
166
+ // --- Discord ---
167
+ /[MN][A-Za-z0-9]{23,}\.[A-Za-z0-9_-]{6}\.[A-Za-z0-9_-]{27,}/, // Discord bot token
168
+ // --- Resend ---
169
+ /^re_[a-zA-Z0-9]{20,}/, // Resend API key
170
+ // --- PlanetScale ---
171
+ /^pscale_(?:tkn|pw|oauth)_[a-zA-Z0-9_-]{20,}/, // PlanetScale token/password
172
+ // --- Fly.io ---
173
+ /^fo1_[a-zA-Z0-9_-]{20,}/, // Fly.io token
174
+ // --- Render ---
175
+ /^rnd_[a-zA-Z0-9]{20,}/, // Render API key
176
+ // --- Inngest ---
177
+ /^signkey-[a-zA-Z0-9_-]{20,}/, // Inngest signing key
178
+ // --- Pinecone ---
179
+ /^pcsk_[a-zA-Z0-9_-]{20,}/, // Pinecone API key
180
+ ];
181
+ exports.SENSITIVE_VALUE_PATTERNS = SENSITIVE_VALUE_PATTERNS;
182
+ // ---------------------------------------------------------------------------
183
+ // Shannon entropy for high-entropy catch-all
184
+ // ---------------------------------------------------------------------------
185
+ /**
186
+ * Calculate Shannon entropy of a string.
187
+ * Higher values indicate more randomness (potential secrets).
188
+ */
189
+ function shannonEntropy(s) {
190
+ const freq = new Map();
191
+ for (const c of s) {
192
+ freq.set(c, (freq.get(c) ?? 0) + 1);
193
+ }
194
+ const len = s.length;
195
+ let entropy = 0;
196
+ for (const count of freq.values()) {
197
+ const p = count / len;
198
+ entropy -= p * Math.log2(p);
199
+ }
200
+ return entropy;
201
+ }
202
+ /**
203
+ * Heuristic: does this string look like a random token/secret?
204
+ * - No spaces
205
+ * - Primarily alphanumeric + limited special chars (-_=+/.)
206
+ * - Not a common word or path-like string
207
+ */
208
+ const TOKEN_CHARS_RE = /^[a-zA-Z0-9_+/=.-]+$/;
209
+ const COMMON_WORD_RE = /^[a-z]+$/i; // pure alpha could be a word
210
+ const PATH_LIKE_RE = /^(\/[a-zA-Z0-9._-]+)+\/?$/; // e.g. /usr/bin/node
211
+ const HEX_LIKE_RE = /^(0x)?[0-9a-fA-F]+$/; // plain hex number
212
+ const URL_LIKE_NO_CREDS = /^https?:\/\/[^@]+$/; // URL without embedded creds
213
+ function looksLikeToken(s) {
214
+ // Must match token character set (no spaces, no weird chars)
215
+ if (!TOKEN_CHARS_RE.test(s))
216
+ return false;
217
+ // Skip pure alphabetic (could be a word/identifier)
218
+ if (COMMON_WORD_RE.test(s) && s.length < 40)
219
+ return false;
220
+ // Skip path-like strings
221
+ if (PATH_LIKE_RE.test(s))
222
+ return false;
223
+ // Skip plain hex numbers (hashes, IDs)
224
+ if (HEX_LIKE_RE.test(s) && s.length < 40)
225
+ return false;
226
+ // Skip normal URLs without credentials
227
+ if (URL_LIKE_NO_CREDS.test(s))
228
+ return false;
229
+ return true;
230
+ }
231
+ const ENTROPY_MIN_LENGTH = 20;
232
+ /**
233
+ * Length-based entropy thresholds.
234
+ * Short high-entropy strings (20-32 chars) are often UUIDs/hashes, not secrets.
235
+ * Longer strings need less entropy to be suspicious.
236
+ */
237
+ function getEntropyThreshold(length) {
238
+ if (length <= 32)
239
+ return 4.8; // Short: stricter (avoid UUID false positives)
240
+ if (length <= 64)
241
+ return 4.5; // Medium: standard
242
+ return 4.2; // Long: slightly relaxed (long random tokens)
243
+ }
244
+ function isHighEntropySecret(s) {
245
+ if (s.length < ENTROPY_MIN_LENGTH)
246
+ return false;
247
+ if (!looksLikeToken(s))
248
+ return false;
249
+ return shannonEntropy(s) >= getEntropyThreshold(s.length);
250
+ }
251
+ // ---------------------------------------------------------------------------
252
+ // Constants
253
+ // ---------------------------------------------------------------------------
254
+ const MAX_VALUE_LENGTH = 500;
255
+ const REDACTED = "[REDACTED]";
256
+ // ---------------------------------------------------------------------------
257
+ // Redaction audit mode (opt-in via PODWATCH_REDACTION_AUDIT env var)
258
+ // ---------------------------------------------------------------------------
259
+ const REDACTION_AUDIT = !!process.env.PODWATCH_REDACTION_AUDIT;
260
+ /**
261
+ * Log fields that were NOT redacted so we can spot gaps.
262
+ * Shows field name + first 4 chars + entropy score without exposing actual values.
263
+ */
264
+ function auditUnredactedFields(obj, prefix = '') {
265
+ if (!REDACTION_AUDIT)
266
+ return;
267
+ for (const [key, value] of Object.entries(obj)) {
268
+ const fieldPath = prefix ? `${prefix}.${key}` : key;
269
+ if (typeof value === 'string') {
270
+ if (value !== REDACTED && !value.startsWith('[truncated]')) {
271
+ const preview = value.slice(0, 4);
272
+ const entropy = shannonEntropy(value).toFixed(2);
273
+ console.log(`[podwatch:audit] PASS field="${fieldPath}" preview="${preview}…" len=${value.length} entropy=${entropy}`);
274
+ }
275
+ }
276
+ else if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
277
+ auditUnredactedFields(value, fieldPath);
278
+ }
279
+ else if (Array.isArray(value)) {
280
+ value.forEach((item, i) => {
281
+ if (typeof item === 'string' && item !== REDACTED) {
282
+ const preview = item.slice(0, 4);
283
+ const entropy = shannonEntropy(item).toFixed(2);
284
+ console.log(`[podwatch:audit] PASS field="${fieldPath}[${i}]" preview="${preview}…" len=${item.length} entropy=${entropy}`);
285
+ }
286
+ else if (item !== null && typeof item === 'object') {
287
+ auditUnredactedFields(item, `${fieldPath}[${i}]`);
288
+ }
289
+ });
290
+ }
291
+ }
292
+ }
293
+ // ---------------------------------------------------------------------------
294
+ // Public API
295
+ // ---------------------------------------------------------------------------
296
+ /**
297
+ * Redact sensitive values from tool call params.
298
+ * Returns the scrubbed object and a count of how many values were redacted.
299
+ */
300
+ function redactParams(params) {
301
+ const counter = { count: 0 };
302
+ const result = redactObject(params, 0, counter);
303
+ auditUnredactedFields(result);
304
+ return { result, redactedCount: counter.count };
305
+ }
306
+ // ---------------------------------------------------------------------------
307
+ // Internal helpers
308
+ // ---------------------------------------------------------------------------
309
+ function isSensitiveValue(value) {
310
+ if (SENSITIVE_VALUE_PATTERNS.some((p) => p.test(value)))
311
+ return true;
312
+ if (isHighEntropySecret(value))
313
+ return true;
314
+ return false;
315
+ }
316
+ function redactObject(obj, depth, counter) {
317
+ if (depth > 5)
318
+ return { "[truncated]": "nested too deep" };
319
+ const result = {};
320
+ for (const [key, value] of Object.entries(obj)) {
321
+ const keyLower = key.toLowerCase().replace(/[-_]/g, "");
322
+ // Key-based redaction
323
+ if (SENSITIVE_KEYS.has(key.toLowerCase()) || SENSITIVE_KEYS.has(keyLower)) {
324
+ result[key] = REDACTED;
325
+ counter.count++;
326
+ continue;
327
+ }
328
+ // Value-based redaction + truncation
329
+ if (typeof value === "string") {
330
+ if (isSensitiveValue(value)) {
331
+ result[key] = REDACTED;
332
+ counter.count++;
333
+ }
334
+ else if (value.length > MAX_VALUE_LENGTH) {
335
+ result[key] = value.slice(0, MAX_VALUE_LENGTH) + `… [${value.length} chars]`;
336
+ }
337
+ else {
338
+ result[key] = value;
339
+ }
340
+ continue;
341
+ }
342
+ // Recurse into nested objects
343
+ if (value !== null && typeof value === "object" && !Array.isArray(value)) {
344
+ result[key] = redactObject(value, depth + 1, counter);
345
+ continue;
346
+ }
347
+ // Arrays — redact string elements, recurse into objects
348
+ if (Array.isArray(value)) {
349
+ result[key] = value.map((item) => {
350
+ if (typeof item === "string") {
351
+ if (isSensitiveValue(item)) {
352
+ counter.count++;
353
+ return REDACTED;
354
+ }
355
+ if (item.length > MAX_VALUE_LENGTH) {
356
+ return item.slice(0, MAX_VALUE_LENGTH) + `… [${item.length} chars]`;
357
+ }
358
+ return item;
359
+ }
360
+ if (item !== null && typeof item === "object" && !Array.isArray(item)) {
361
+ return redactObject(item, depth + 1, counter);
362
+ }
363
+ return item;
364
+ });
365
+ continue;
366
+ }
367
+ // Primitives pass through
368
+ result[key] = value;
369
+ }
370
+ return result;
371
+ }
372
+ //# sourceMappingURL=redact.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redact.js","sourceRoot":"","sources":["../src/redact.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Skill/plugin scanner — scans installed skills and plugins.
3
+ *
4
+ * Scans:
5
+ * - ~/.openclaw/skills/ (managed skills)
6
+ * - <workspace>/skills/ (workspace skills)
7
+ * - ~/.openclaw/extensions/ (installed plugins)
8
+ *
9
+ * Reports: name, version, source, permissions, risk indicators.
10
+ */
11
+ interface ScannedItem {
12
+ name: string;
13
+ type: "skill" | "plugin";
14
+ source: string;
15
+ version?: string;
16
+ description?: string;
17
+ permissions?: string[];
18
+ riskIndicators?: string[];
19
+ }
20
+ interface ScanResults {
21
+ skills: ScannedItem[];
22
+ plugins: ScannedItem[];
23
+ scannedAt: number;
24
+ }
25
+ export declare function scanSkillsAndPlugins(workspaceDir?: string): Promise<ScanResults>;
26
+ export {};
27
+ //# sourceMappingURL=scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAUH,UAAU,WAAW;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,GAAG,QAAQ,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED,UAAU,WAAW;IACnB,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CACnB;AAMD,wBAAsB,oBAAoB,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAoCtF"}