@upx-us/shield 0.6.5 → 0.6.6

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/CHANGELOG.md CHANGED
@@ -4,6 +4,23 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  ---
6
6
 
7
+ ## [0.6.6] — 2026-03-10
8
+
9
+ ### Added
10
+ - **Plugin lifecycle events** — the plugin now reports key lifecycle signals to the USS platform via the existing `PUT /v1/instance` channel (no new endpoint). Signals are forwarded by Cloud Run as an optional `lifecycle_event` field in the instance telemetry PATCH to the platform. Absent on older plugin versions — fully backward compatible.
11
+ - `plugin_started`: emitted on every successful startup. Includes `version`, `reason` (`'update'` | `'normal'`), and `previous_version` when applicable. Enables the platform to confirm end-to-end update success.
12
+ - `update_restart_failed`: emitted after all gateway restart retries are exhausted. Includes `new_version`, `running_version`, `attempts`, `error`.
13
+ - `plugin_integrity_drift`: emitted when `openclaw.json` version diverges from the installed version after a self-update. Includes `installed_version`, `registered_version`.
14
+ - `update_check_failing`: emitted after 3 consecutive npm registry check failures. Includes `consecutive_failures`, `last_error`, `next_retry_at`.
15
+
16
+ ### Changed
17
+ - `reportPluginEvent()` removed from `sender.ts` — replaced by `reportLifecycleEvent()` which reuses the existing `PUT /v1/instance` telemetry channel.
18
+
19
+ ### Fixed
20
+ - `SHIELD_AUTO_UPDATE=false` environment variable now correctly disables auto-update (was being read as truthy string `'false'`).
21
+
22
+ ---
23
+
7
24
  ## [0.6.5] — 2026-03-09
8
25
 
9
26
  ### Added
package/dist/index.js CHANGED
@@ -648,6 +648,18 @@ exports.default = {
648
648
  catch (err) {
649
649
  log.debug('case-monitor', `Direct send setup failed (non-fatal): ${err instanceof Error ? err.message : String(err)}`);
650
650
  }
651
+ try {
652
+ const updateState = (0, updater_1.loadUpdateState)();
653
+ const previousVersion = updateState.rollbackVersion ?? null;
654
+ const startReason = previousVersion ? 'update' : 'normal';
655
+ const { reportLifecycleEvent } = await Promise.resolve().then(() => __importStar(require('./src/sender')));
656
+ void reportLifecycleEvent('plugin_started', {
657
+ version: version_1.VERSION,
658
+ reason: startReason,
659
+ ...(previousVersion ? { previous_version: previousVersion } : {}),
660
+ }, credentials);
661
+ }
662
+ catch { }
651
663
  const autoUpdateMode = pluginConfig.autoUpdate ?? true;
652
664
  log.info('updater', `Startup update check (autoUpdate=${autoUpdateMode}, current=${version_1.VERSION})`);
653
665
  const startupUpdate = (0, updater_1.performAutoUpdate)(autoUpdateMode, 0);
package/dist/src/index.js CHANGED
@@ -73,7 +73,8 @@ async function poll() {
73
73
  (0, event_store_1.initEventStore)(SHIELD_DATA_DIR, { maxEvents: config.localEventLimit });
74
74
  }
75
75
  log.info('bridge', `Starting — dryRun=${config.dryRun} poll=${config.pollIntervalMs}ms maxEvents=${config.maxEvents || 'unlimited'} redaction=${config.redactionEnabled} logLevel=${process.env.LOG_LEVEL || 'info'}`);
76
- const autoUpdateMode = process.env.SHIELD_AUTO_UPDATE ?? true;
76
+ const _rawEnvStartup = process.env.SHIELD_AUTO_UPDATE;
77
+ const autoUpdateMode = _rawEnvStartup === 'false' ? false : _rawEnvStartup ?? true;
77
78
  log.info('updater', `Startup update check (autoUpdate=${autoUpdateMode}, current=${version_1.VERSION})`);
78
79
  const startupUpdate = (0, updater_1.performAutoUpdate)(autoUpdateMode, 0);
79
80
  if (startupUpdate.action === "none") {
@@ -147,7 +148,8 @@ async function poll() {
147
148
  continue;
148
149
  }
149
150
  }
150
- const autoUpdateMode = process.env.SHIELD_AUTO_UPDATE ?? true;
151
+ const _rawEnvLoop = process.env.SHIELD_AUTO_UPDATE;
152
+ const autoUpdateMode = _rawEnvLoop === 'false' ? false : _rawEnvLoop ?? true;
151
153
  const updateResult = (0, updater_1.performAutoUpdate)(autoUpdateMode);
152
154
  if (updateResult.action !== "none") {
153
155
  if (updateResult.action === "notify") {
@@ -24,3 +24,4 @@ export interface ReportInstanceResult {
24
24
  score?: InstanceScore;
25
25
  }
26
26
  export declare function reportInstance(payload: Record<string, unknown>, credentials: ShieldCredentials): Promise<ReportInstanceResult>;
27
+ export declare function reportLifecycleEvent(type: 'plugin_started' | 'update_restart_failed' | 'plugin_integrity_drift' | 'update_check_failing', data: Record<string, unknown>, credentials: ShieldCredentials): Promise<void>;
@@ -37,6 +37,7 @@ exports.CIRCUIT_BREAKER_THRESHOLD = exports.REQUEST_TIMEOUT_MS = void 0;
37
37
  exports._signRequestWithSecret = _signRequestWithSecret;
38
38
  exports.sendEvents = sendEvents;
39
39
  exports.reportInstance = reportInstance;
40
+ exports.reportLifecycleEvent = reportLifecycleEvent;
40
41
  const crypto_1 = require("crypto");
41
42
  const log = __importStar(require("./log"));
42
43
  const version_1 = require("./version");
@@ -233,3 +234,16 @@ async function reportInstance(payload, credentials) {
233
234
  return { ok: false };
234
235
  }
235
236
  }
237
+ async function reportLifecycleEvent(type, data, credentials) {
238
+ try {
239
+ await reportInstance({
240
+ lifecycle_event: {
241
+ type,
242
+ timestamp: new Date().toISOString(),
243
+ data,
244
+ },
245
+ }, credentials);
246
+ }
247
+ catch {
248
+ }
249
+ }
@@ -53,6 +53,8 @@ const os_1 = require("os");
53
53
  const crypto_1 = require("crypto");
54
54
  const log = __importStar(require("./log"));
55
55
  const version_1 = require("./version");
56
+ const config_1 = require("./config");
57
+ const sender_1 = require("./sender");
56
58
  const PACKAGE_NAME = '@upx-us/shield';
57
59
  const CHECK_INTERVAL_MS = 6 * 60 * 60 * 1000;
58
60
  const MIN_CHECK_INTERVAL_MS = 60 * 1000;
@@ -163,13 +165,28 @@ function checkForUpdate(overrideInterval) {
163
165
  state.currentVersion = version_1.VERSION;
164
166
  if (!latestVersion) {
165
167
  state.lastError = 'Failed to query npm registry';
168
+ state.consecutiveFailures = (state.consecutiveFailures ?? 0) + 1;
166
169
  saveUpdateState(state);
170
+ const FAILURE_THRESHOLD = 3;
171
+ if (state.consecutiveFailures >= FAILURE_THRESHOLD) {
172
+ const nextRetryAt = new Date(now + CHECK_INTERVAL_MS).toISOString();
173
+ try {
174
+ const creds = (0, config_1.loadCredentials)();
175
+ void (0, sender_1.reportLifecycleEvent)('update_check_failing', {
176
+ consecutive_failures: state.consecutiveFailures,
177
+ last_error: state.lastError,
178
+ next_retry_at: nextRetryAt,
179
+ }, creds);
180
+ }
181
+ catch { }
182
+ }
167
183
  return null;
168
184
  }
169
185
  state.latestVersion = latestVersion;
170
186
  if (isNewerVersion(version_1.VERSION, latestVersion)) {
171
187
  state.updateAvailable = true;
172
188
  state.lastError = null;
189
+ state.consecutiveFailures = 0;
173
190
  saveUpdateState(state);
174
191
  const classification = classifyUpdate(version_1.VERSION, latestVersion);
175
192
  log.info('updater', `Update available: ${version_1.VERSION} → ${latestVersion} (${classification.isPatch ? 'patch' : classification.isMinor ? 'minor' : 'major'})`);
@@ -182,6 +199,7 @@ function checkForUpdate(overrideInterval) {
182
199
  }
183
200
  state.updateAvailable = false;
184
201
  state.lastError = null;
202
+ state.consecutiveFailures = 0;
185
203
  saveUpdateState(state);
186
204
  return null;
187
205
  }
@@ -302,6 +320,24 @@ function updateOpenClawPluginMetadata(newVersion, shasum) {
302
320
  install.installedAt = new Date().toISOString();
303
321
  (0, safe_io_1.writeJsonSafe)(configPath, config);
304
322
  log.info('updater', `Updated openclaw.json plugin metadata → ${newVersion}`);
323
+ try {
324
+ const written = JSON.parse((0, fs_1.readFileSync)(configPath, 'utf-8'));
325
+ const installedVersion = written?.plugins?.installs?.shield?.version;
326
+ if (installedVersion !== newVersion) {
327
+ log.warn('updater', `openclaw.json integrity check failed: expected=${newVersion} got=${installedVersion ?? '(missing)'}`);
328
+ try {
329
+ const creds = (0, config_1.loadCredentials)();
330
+ void (0, sender_1.reportLifecycleEvent)('plugin_integrity_drift', {
331
+ expected_version: newVersion,
332
+ installed_version: installedVersion ?? null,
333
+ }, creds);
334
+ }
335
+ catch { }
336
+ }
337
+ }
338
+ catch (verifyErr) {
339
+ log.warn('updater', `openclaw.json read-back failed: ${verifyErr instanceof Error ? verifyErr.message : String(verifyErr)}`);
340
+ }
305
341
  }
306
342
  catch (err) {
307
343
  log.warn('updater', `Failed to update openclaw.json metadata: ${err instanceof Error ? err.message : String(err)}`);
@@ -386,6 +422,16 @@ function performAutoUpdate(mode, checkIntervalMs) {
386
422
  const MAX_RESTART_ATTEMPTS = 5;
387
423
  if ((state.restartAttempts ?? 0) >= MAX_RESTART_ATTEMPTS) {
388
424
  log.warn('updater', `Gateway restart failed ${MAX_RESTART_ATTEMPTS}x after update to ${state.currentVersion} — rolling back`);
425
+ try {
426
+ const creds = (0, config_1.loadCredentials)();
427
+ void (0, sender_1.reportLifecycleEvent)('update_restart_failed', {
428
+ new_version: state.currentVersion,
429
+ running_version: version_1.VERSION,
430
+ attempts: state.restartAttempts ?? MAX_RESTART_ATTEMPTS,
431
+ error: state.lastError ?? 'gateway restart exhausted all retries',
432
+ }, creds);
433
+ }
434
+ catch { }
389
435
  const backups = listBackups();
390
436
  if (backups.length > 0) {
391
437
  restoreFromBackup(backups[0]);
@@ -2,7 +2,7 @@
2
2
  "id": "shield",
3
3
  "name": "OpenClaw Shield",
4
4
  "description": "Real-time security monitoring \u2014 streams enriched, redacted security events to the Shield detection platform.",
5
- "version": "0.6.5",
5
+ "version": "0.6.6",
6
6
  "skills": [
7
7
  "./skills"
8
8
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@upx-us/shield",
3
- "version": "0.6.5",
3
+ "version": "0.6.6",
4
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",