@upx-us/shield 0.3.29 → 0.4.36

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.
@@ -34,6 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.resolveOpenClawVersion = resolveOpenClawVersion;
37
+ exports._resetCachedOpenClawVersion = _resetCachedOpenClawVersion;
37
38
  exports.resolveAgentLabel = resolveAgentLabel;
38
39
  exports.getCachedPublicIp = getCachedPublicIp;
39
40
  exports.resolveOutboundIp = resolveOutboundIp;
@@ -41,37 +42,59 @@ exports.transformEntries = transformEntries;
41
42
  exports.generateHostTelemetry = generateHostTelemetry;
42
43
  const os = __importStar(require("os"));
43
44
  const fs = __importStar(require("fs"));
45
+ const safe_io_1 = require("./safe-io");
44
46
  const path = __importStar(require("path"));
45
47
  const dgram_1 = require("dgram");
46
48
  const events_1 = require("./events");
47
49
  const log = __importStar(require("./log"));
48
50
  const version_1 = require("./version");
49
51
  const counters_1 = require("./counters");
52
+ const inventory_1 = require("./inventory");
53
+ let _cachedOpenClawVersion = "";
50
54
  function resolveOpenClawVersion() {
51
- if (process.env.OPENCLAW_VERSION)
52
- return process.env.OPENCLAW_VERSION;
53
- const candidates = [
54
- '/opt/homebrew/lib/node_modules/openclaw/package.json',
55
- '/usr/local/lib/node_modules/openclaw/package.json',
56
- path.join(os.homedir(), '.nvm/versions/node/*/lib/node_modules/openclaw/package.json'),
57
- ];
58
- for (const p of candidates) {
59
- try {
60
- if (fs.existsSync(p)) {
61
- const pkg = JSON.parse(fs.readFileSync(p, 'utf8'));
62
- if (pkg.version)
63
- return pkg.version;
64
- }
55
+ if (_cachedOpenClawVersion !== "")
56
+ return _cachedOpenClawVersion;
57
+ if (process.env.OPENCLAW_VERSION) {
58
+ _cachedOpenClawVersion = process.env.OPENCLAW_VERSION;
59
+ return _cachedOpenClawVersion;
60
+ }
61
+ try {
62
+ const pkgPath = require.resolve('openclaw/package.json');
63
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
64
+ if (pkg.version) {
65
+ _cachedOpenClawVersion = pkg.version;
66
+ return _cachedOpenClawVersion;
65
67
  }
66
- catch { }
67
68
  }
69
+ catch { }
68
70
  try {
69
- const cfg = JSON.parse(fs.readFileSync(path.join(os.homedir(), '.openclaw/openclaw.json'), 'utf8'));
70
- return cfg?.meta?.lastTouchedVersion || 'unknown';
71
+ const { execSync } = require('child_process');
72
+ const output = execSync('openclaw --version', {
73
+ timeout: 5000,
74
+ stdio: ['ignore', 'pipe', 'ignore'],
75
+ encoding: 'utf8',
76
+ }).trim();
77
+ const version = output.includes('/') ? output.split('/').pop() : output;
78
+ if (version && version !== 'unknown') {
79
+ _cachedOpenClawVersion = version;
80
+ return _cachedOpenClawVersion;
81
+ }
71
82
  }
72
- catch {
73
- return 'unknown';
83
+ catch { }
84
+ try {
85
+ const cfg = JSON.parse(fs.readFileSync(path.join(os.homedir(), '.openclaw/openclaw.json'), 'utf8'));
86
+ const v = cfg?.meta?.lastTouchedVersion;
87
+ if (v) {
88
+ _cachedOpenClawVersion = v;
89
+ return _cachedOpenClawVersion;
90
+ }
74
91
  }
92
+ catch { }
93
+ _cachedOpenClawVersion = 'unknown';
94
+ return _cachedOpenClawVersion;
95
+ }
96
+ function _resetCachedOpenClawVersion() {
97
+ _cachedOpenClawVersion = "";
75
98
  }
76
99
  function resolveAgentLabel(agentId) {
77
100
  if (process.env.OPENCLAW_AGENT_LABEL)
@@ -113,7 +136,7 @@ function writeIpCache(ip) {
113
136
  const dir = path.dirname(IP_CACHE_FILE);
114
137
  if (!fs.existsSync(dir))
115
138
  fs.mkdirSync(dir, { recursive: true });
116
- fs.writeFileSync(IP_CACHE_FILE, JSON.stringify({ ip, resolvedAt: Date.now() }));
139
+ (0, safe_io_1.writeJsonSafe)(IP_CACHE_FILE, { ip, resolvedAt: Date.now() });
117
140
  }
118
141
  catch { }
119
142
  }
@@ -205,6 +228,8 @@ function isAdministrativeEvent(toolName, args, sessionId) {
205
228
  return true;
206
229
  if (/openclaw\s+cron\s+(list|log|runs|status)/.test(cmd))
207
230
  return true;
231
+ if (/openclaw\s+shield\s+cases/.test(cmd))
232
+ return true;
208
233
  if (/ps\s+aux.*grep.*(ts-node|bridge|shield)/.test(cmd))
209
234
  return true;
210
235
  if (/gcloud\s+auth\s+print-access-token/.test(cmd))
@@ -223,6 +248,8 @@ function isAdministrativeEvent(toolName, args, sessionId) {
223
248
  return true;
224
249
  if (['sessions_list', 'sessions_history', 'session_status'].includes(toolName))
225
250
  return true;
251
+ if (/^shield\.cases_/.test(toolName) || /^shield\.status$/.test(toolName))
252
+ return true;
226
253
  return false;
227
254
  }
228
255
  function transformEntries(entries) {
@@ -251,6 +278,18 @@ function transformEntries(entries) {
251
278
  event.tool_metadata = {};
252
279
  event.tool_metadata['openclaw.is_administrative'] = 'true';
253
280
  }
281
+ const crossText = [
282
+ args.command || '',
283
+ args.file_path || args.path || args.filePath || '',
284
+ args.url || '',
285
+ ].join(' ');
286
+ const targetWorkspace = (0, inventory_1.detectCrossWorkspace)(crossText, agentId);
287
+ if (targetWorkspace) {
288
+ if (!event.tool_metadata)
289
+ event.tool_metadata = {};
290
+ event.tool_metadata['openclaw.cross_workspace_access'] = 'true';
291
+ event.tool_metadata['openclaw.target_workspace'] = targetWorkspace;
292
+ }
254
293
  log.debug('transformer', `TOOL_CALL tool=${toolName} session=${entry._sessionId} agent=${agentId} schema=${schema.constructor?.name || 'unknown'} admin=${event.tool_metadata?.['openclaw.is_administrative'] === 'true'}`, log.isDebug ? event : undefined);
255
294
  (0, counters_1.recordEventType)(event.event_type);
256
295
  envelopes.push({ source, event });
@@ -47,6 +47,7 @@ exports.performAutoUpdate = performAutoUpdate;
47
47
  exports.requestGatewayRestart = requestGatewayRestart;
48
48
  const child_process_1 = require("child_process");
49
49
  const fs_1 = require("fs");
50
+ const safe_io_1 = require("./safe-io");
50
51
  const path_1 = require("path");
51
52
  const os_1 = require("os");
52
53
  const crypto_1 = require("crypto");
@@ -101,13 +102,7 @@ function ensureDir(dir) {
101
102
  (0, fs_1.mkdirSync)(dir, { recursive: true });
102
103
  }
103
104
  function loadUpdateState() {
104
- try {
105
- if ((0, fs_1.existsSync)(UPDATE_STATE_FILE)) {
106
- return JSON.parse((0, fs_1.readFileSync)(UPDATE_STATE_FILE, 'utf-8'));
107
- }
108
- }
109
- catch { }
110
- return {
105
+ const defaults = {
111
106
  lastCheckAt: 0,
112
107
  lastUpdateAt: 0,
113
108
  currentVersion: version_1.VERSION,
@@ -117,10 +112,14 @@ function loadUpdateState() {
117
112
  rollbackVersion: null,
118
113
  consecutiveFailures: 0,
119
114
  };
115
+ if (!(0, fs_1.existsSync)(UPDATE_STATE_FILE))
116
+ return defaults;
117
+ const loaded = (0, safe_io_1.readJsonSafe)(UPDATE_STATE_FILE, {}, 'update-state');
118
+ return { ...defaults, ...loaded };
120
119
  }
121
120
  function saveUpdateState(state) {
122
121
  ensureDir((0, path_1.dirname)(UPDATE_STATE_FILE));
123
- (0, fs_1.writeFileSync)(UPDATE_STATE_FILE, JSON.stringify(state, null, 2));
122
+ (0, safe_io_1.writeJsonSafe)(UPDATE_STATE_FILE, state);
124
123
  }
125
124
  function checkNpmVersion() {
126
125
  try {
@@ -291,7 +290,7 @@ function updateOpenClawPluginMetadata(newVersion, shasum) {
291
290
  delete install.shasum;
292
291
  }
293
292
  install.installedAt = new Date().toISOString();
294
- (0, fs_1.writeFileSync)(configPath, JSON.stringify(config, null, 2) + '\n');
293
+ (0, safe_io_1.writeJsonSafe)(configPath, config);
295
294
  log.info('updater', `Updated openclaw.json plugin metadata → ${newVersion}`);
296
295
  }
297
296
  catch (err) {
@@ -1,79 +1,84 @@
1
1
  {
2
- "id": "shield",
3
- "name": "OpenClaw Shield",
4
- "description": "Real-time security monitoring \u2014 streams enriched, redacted security events to the Shield detection platform.",
5
- "version": "0.3.29",
6
- "skills": [
7
- "./skills"
8
- ],
9
- "configSchema": {
10
- "type": "object",
11
- "additionalProperties": false,
12
- "properties": {
13
- "installationKey": {
14
- "type": "string",
15
- "description": "One-time installation key from the Shield portal. The plugin uses this to register the instance and obtain credentials automatically. Can be removed from config after first activation."
16
- },
17
- "enabled": {
18
- "type": "boolean",
19
- "default": true
20
- },
21
- "dryRun": {
22
- "type": "boolean",
23
- "default": false
24
- },
25
- "redactionEnabled": {
26
- "type": "boolean",
27
- "default": true
28
- },
29
- "pollIntervalMs": {
30
- "type": "number",
31
- "default": 30000
32
- },
33
- "collectHostMetrics": {
34
- "type": "boolean",
35
- "default": false
36
- },
37
- "autoUpdate": {
38
- "oneOf": [
39
- {
40
- "type": "boolean"
41
- },
42
- {
43
- "type": "string",
44
- "enum": [
45
- "notify-only"
46
- ]
47
- }
48
- ],
49
- "default": true,
50
- "description": "Auto-update mode: true (auto-update patch versions), false (disabled), or 'notify-only' (log available updates without installing)."
51
- }
52
- }
2
+ "id": "shield",
3
+ "name": "OpenClaw Shield",
4
+ "description": "Real-time security monitoring \u2014 streams enriched, redacted security events to the Shield detection platform.",
5
+ "version": "0.4.36",
6
+ "skills": [
7
+ "./skills"
8
+ ],
9
+ "configSchema": {
10
+ "type": "object",
11
+ "additionalProperties": false,
12
+ "properties": {
13
+ "installationKey": {
14
+ "type": "string",
15
+ "description": "One-time installation key from the Shield portal. The plugin uses this to register the instance and obtain credentials automatically. Can be removed from config after first activation."
16
+ },
17
+ "enabled": {
18
+ "type": "boolean",
19
+ "default": true
20
+ },
21
+ "dryRun": {
22
+ "type": "boolean",
23
+ "default": false
24
+ },
25
+ "redactionEnabled": {
26
+ "type": "boolean",
27
+ "default": true
28
+ },
29
+ "pollIntervalMs": {
30
+ "type": "number",
31
+ "default": 30000
32
+ },
33
+ "collectHostMetrics": {
34
+ "type": "boolean",
35
+ "default": false
36
+ },
37
+ "autoUpdate": {
38
+ "oneOf": [
39
+ {
40
+ "type": "boolean"
41
+ },
42
+ {
43
+ "type": "string",
44
+ "enum": [
45
+ "notify-only"
46
+ ]
47
+ }
48
+ ],
49
+ "default": true,
50
+ "description": "Auto-update mode: true (auto-update patch versions), false (disabled), or 'notify-only' (log available updates without installing)."
51
+ }
52
+ }
53
+ },
54
+ "uiHints": {
55
+ "installationKey": {
56
+ "label": "Installation Key",
57
+ "description": "One-time key from the Shield portal (https://uss.upx.com). Required for first-time activation only."
58
+ },
59
+ "enabled": {
60
+ "label": "Enable security monitoring"
61
+ },
62
+ "dryRun": {
63
+ "label": "Dry run (log events locally, do not transmit)"
64
+ },
65
+ "redactionEnabled": {
66
+ "label": "Redact sensitive values before transmitting"
67
+ },
68
+ "pollIntervalMs": {
69
+ "label": "Polling interval (milliseconds)"
70
+ },
71
+ "collectHostMetrics": {
72
+ "label": "Collect host telemetry metrics"
53
73
  },
54
- "uiHints": {
55
- "installationKey": {
56
- "label": "Installation Key",
57
- "description": "One-time key from the Shield portal (https://uss.upx.com). Required for first-time activation only."
58
- },
59
- "enabled": {
60
- "label": "Enable security monitoring"
61
- },
62
- "dryRun": {
63
- "label": "Dry run (log events locally, do not transmit)"
64
- },
65
- "redactionEnabled": {
66
- "label": "Redact sensitive values before transmitting"
67
- },
68
- "pollIntervalMs": {
69
- "label": "Polling interval (milliseconds)"
70
- },
71
- "collectHostMetrics": {
72
- "label": "Collect host telemetry metrics"
73
- },
74
- "autoUpdate": {
75
- "label": "Auto-update mode",
76
- "description": "true = auto-install patch updates, 'notify-only' = log only, false = disabled"
77
- }
74
+ "autoUpdate": {
75
+ "label": "Auto-update mode",
76
+ "description": "true = auto-install patch updates, 'notify-only' = log only, false = disabled"
78
77
  }
78
+ },
79
+ "clawhub": {
80
+ "slug": "openclaw-shield-upx",
81
+ "skillVersion": "1.0.2",
82
+ "note": "ClawHub auto-increments on publish. Update this after each clawhub submission."
83
+ }
79
84
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@upx-us/shield",
3
- "version": "0.3.29",
4
- "description": "Security monitoring plugin for OpenClaw agents \u2014 streams enriched security events to the Shield detection platform",
3
+ "version": "0.4.36",
4
+ "description": "Security monitoring plugin for OpenClaw agents streams enriched security events to the Shield detection platform",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "bin": {
@@ -39,16 +39,21 @@
39
39
  "package:pack": "npm pack",
40
40
  "package:publish": "npm run package:validate && npm publish --access public",
41
41
  "start": "node dist/src/index.js",
42
- "setup": "node dist/src/setup.js"
42
+ "setup": "node dist/src/setup.js",
43
+ "prepublishOnly": "npm run build"
43
44
  },
44
45
  "keywords": [
46
+ "agent-monitoring",
47
+ "ai-security",
48
+ "clawhub",
49
+ "compliance",
50
+ "detection",
51
+ "monitoring",
45
52
  "openclaw",
46
53
  "openclaw-plugin",
54
+ "openclaw-skill",
47
55
  "security",
48
- "monitoring",
49
- "detection",
50
- "siem",
51
- "compliance"
56
+ "siem"
52
57
  ],
53
58
  "author": "UPX Security Services",
54
59
  "license": "SEE LICENSE IN LICENSE",
@@ -69,5 +74,9 @@
69
74
  "ts-json-schema-generator": "^2.5.0",
70
75
  "tsx": "^4.21.0",
71
76
  "typescript": "^5.9.3"
77
+ },
78
+ "homepage": "https://clawhub.ai/brunopradof/openclaw-shield-upx",
79
+ "clawhub": {
80
+ "slug": "openclaw-shield-upx"
72
81
  }
73
- }
82
+ }
@@ -0,0 +1,39 @@
1
+ # OpenClaw Shield — Security Specialist
2
+
3
+ A skill that turns your OpenClaw agent into a cybersecurity specialist.
4
+
5
+ ## What it does
6
+
7
+ When Shield is installed, your agent can:
8
+
9
+ - **Monitor** — check Shield health, event counts, and sync status
10
+ - **Inspect** — view host agent inventory and redaction vault via `shield vault show`
11
+ - **Interpret** — analyze security events and explain what they mean
12
+ - **Advise** — recommend remediation, hardening, and next steps
13
+ - **Triage** — assess alert severity and prioritize response
14
+ - **Explain** — break down attack techniques, privacy model, and detection scope
15
+
16
+ ## Requirements
17
+
18
+ - [OpenClaw Shield plugin](https://www.npmjs.com/package/@upx-us/shield) installed and activated
19
+ - Active Shield subscription from [UPX](https://upx.com) — [start a free 30-day trial](https://www.upx.com/pt/lp/openclaw-shield-upx)
20
+
21
+ ## Install
22
+
23
+ This skill is bundled with the Shield plugin. Install the plugin and the skill is available automatically:
24
+
25
+ ```bash
26
+ openclaw plugins install @upx-us/shield
27
+ openclaw shield activate <YOUR_KEY>
28
+ openclaw gateway restart
29
+ ```
30
+
31
+ ## Links
32
+
33
+ - **Plugin (npm)**: [@upx-us/shield](https://www.npmjs.com/package/@upx-us/shield)
34
+ - **Skill (ClawHub)**: [openclaw-shield-upx](https://clawhub.ai/brunopradof/openclaw-shield-upx)
35
+ - **Dashboard**: [uss.upx.com](https://uss.upx.com)
36
+
37
+ ## About
38
+
39
+ Made by [UPX](https://upx.com) — cybersecurity engineering for critical environments.
@@ -0,0 +1,66 @@
1
+ ---
2
+ name: openclaw-shield-upx
3
+ description: "Security monitoring for OpenClaw agents — check Shield health, review events, inspect vault. Use when: user asks about security status, Shield health, event logs, or redaction vault. NOT for: general OS hardening, firewall config, or network security."
4
+ metadata: {"openclaw": {"requires": {"config": ["plugins.entries.shield"]}, "homepage": "https://clawhub.ai/brunopradof/openclaw-shield-upx", "emoji": "🛡️"}}
5
+ ---
6
+
7
+ # OpenClaw Shield
8
+
9
+ Security monitoring for OpenClaw agents by [UPX](https://www.upx.com). Shield runs as a plugin inside the OpenClaw gateway, capturing agent activity and sending redacted telemetry to the UPX detection platform.
10
+
11
+ ## Getting started
12
+
13
+ Shield requires the `@upx-us/shield` plugin and an active subscription.
14
+
15
+ - **Plugin (npm)**: [@upx-us/shield](https://www.npmjs.com/package/@upx-us/shield)
16
+ - **Subscribe / Free 30-day trial**: [upx.com/pt/lp/openclaw-shield-upx](https://www.upx.com/pt/lp/openclaw-shield-upx)
17
+ - **Dashboard**: [uss.upx.com](https://uss.upx.com)
18
+
19
+ ## Commands
20
+
21
+ | Command | What it does |
22
+ |---|---|
23
+ | `openclaw shield status` | Plugin health, connection state, event counts, last sync |
24
+ | `openclaw shield flush` | Force an immediate sync to the platform |
25
+ | `openclaw shield activate <KEY>` | One-time activation with an Installation Key |
26
+ | `openclaw shield logs` | Recent events from the local buffer (last 24h) |
27
+ | `openclaw shield logs --last 20` | Show last N events |
28
+ | `openclaw shield logs --type TOOL_CALL --since 1h` | Filter by event type or time window |
29
+ | `openclaw shield logs --format json` | JSON output |
30
+ | `openclaw shield vault show` | Agent and workspace inventory (hashed IDs) |
31
+ | `openclaw shield vault redactions` | Redaction summary — token categories and counts |
32
+ | `openclaw shield cases` | List open security cases |
33
+ | `openclaw shield cases show <ID>` | Full case detail with events, rule, playbook |
34
+ | `openclaw shield cases resolve <ID>` | Resolve a case (--resolution, --root-cause, --comment) |
35
+
36
+ ## When to use this skill
37
+
38
+ - "Is Shield running?" → `openclaw shield status`
39
+ - "What did Shield capture recently?" → `openclaw shield logs`
40
+ - "How many agents are on this machine?" → `openclaw shield vault show`
41
+ - "Force a sync now" → `openclaw shield flush`
42
+ - User asks about a security alert or event → interpret using your security knowledge and Shield data
43
+ - User asks about Shield's privacy model → all data is redacted on-device before transmission; raw values never leave the machine
44
+
45
+ ## Status interpretation
46
+
47
+ After running `openclaw shield status`, check:
48
+
49
+ - **Connected** → healthy, nothing to do
50
+ - **Disconnected** → gateway may need a restart
51
+ - **High failure count** → platform connectivity issue, usually self-recovers; try `openclaw shield flush`
52
+ - **Rising quarantine** → possible version mismatch, suggest checking for plugin updates
53
+
54
+ ## Cases
55
+
56
+ Cases are created automatically when detection rules fire. Check during heartbeats via `shield.cases_list`. If `pending_count > 0`, notify the user, then call `shield.cases_ack` to mark seen.
57
+
58
+ | RPC | Params | Purpose |
59
+ |---|---|---|
60
+ | `shield.cases_list` | `status`, `limit`, `since` | List open cases + pending notifications |
61
+ | `shield.case_detail` | `id` | Full case with events, rule, playbook |
62
+ | `shield.case_resolve` | `id`, `resolution`, `root_cause`, `comment` | Close a case |
63
+ | `shield.cases_ack` | `ids` | Mark cases as notified |
64
+
65
+ **Resolve values:** `true_positive`, `false_positive`, `benign`, `duplicate`
66
+ **Root cause values:** `user_initiated`, `misconfiguration`, `expected_behavior`, `actual_threat`, `testing`, `unknown`