openclaw-plugin-vt-sentinel 0.12.0 → 0.12.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/CHANGELOG.md +52 -0
- package/dist/compliance-snapshot.d.ts +23 -0
- package/dist/compliance-snapshot.js +104 -3
- package/dist/index.d.ts +27 -2
- package/dist/index.js +46 -1
- package/dist/status-renderer.js +1 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,58 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `openclaw-plugin-vt-sentinel`.
|
|
4
4
|
|
|
5
|
+
## 0.12.2 — Audit collector accuracy + legacy log sanitization
|
|
6
|
+
|
|
7
|
+
Small follow-up to 0.12.1. The static collector could only see
|
|
8
|
+
user-configured watch dirs (never the runtime auto-derived ones like
|
|
9
|
+
`/tmp`, `~/Downloads`, OpenClaw state subdirs), so its auto-scan finding
|
|
10
|
+
read "Watching 0 directories" on fresh installs — technically correct but
|
|
11
|
+
misleading to operators.
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- **Auto-scan finding text reflects the snapshot source.** The
|
|
16
|
+
`buildComplianceSnapshot` helper now accepts `source: 'runtime' | 'static'`.
|
|
17
|
+
Runtime (gateway) callers still report the live watcher list.
|
|
18
|
+
Static (CLI audit) callers now spell out that additional dirs are
|
|
19
|
+
auto-derived by the gateway and point to `vt_sentinel_status` for the
|
|
20
|
+
live list.
|
|
21
|
+
- **Legacy audit-log paths mentioned in `vt_sentinel_help` updated.** The
|
|
22
|
+
help text used to say `~/.openclaw/vt-sentinel-uploads.log` and
|
|
23
|
+
`vt-sentinel-detections.log`; since 0.12.0 they live in
|
|
24
|
+
`<stateDir>/vt-sentinel-audit/{uploads,detections}.log`.
|
|
25
|
+
- **Legacy log files tightened to `0o600` on plugin load.** Pre-0.12.0
|
|
26
|
+
installs left the old stateDir-root log files (`vt-sentinel-uploads.log`,
|
|
27
|
+
`vt-sentinel-detections.log`) at the process default (typically `0o664`).
|
|
28
|
+
On each gateway start the plugin now best-effort `chmod 0o600`s them and
|
|
29
|
+
logs the change. POSIX-only; no-op on Windows.
|
|
30
|
+
- **`package-lock.json` regenerated to the new version** — the shipped
|
|
31
|
+
tarball never included it, but a stale lock on disk caused confusion.
|
|
32
|
+
|
|
33
|
+
## 0.12.1 — Security audit collector: dual-path wiring
|
|
34
|
+
|
|
35
|
+
Fix for the collector introduced in 0.12.0. The in-gateway registration via
|
|
36
|
+
`api.registerSecurityAuditCollector` was insufficient: `openclaw security audit
|
|
37
|
+
--deep` runs in a fresh Node process that doesn't share state with the gateway
|
|
38
|
+
and reads collectors from the plugin's **module-level** `securityAuditCollectors`
|
|
39
|
+
field instead. Verified empirically on the production Linux VM (OpenClaw
|
|
40
|
+
2026.4.12): 0.12.0 shipped with a runtime-only collector that emitted zero
|
|
41
|
+
`vt-sentinel.*` findings under `openclaw security audit --deep --json`.
|
|
42
|
+
|
|
43
|
+
### Fixed
|
|
44
|
+
|
|
45
|
+
- **`securityAuditCollectors` declared at module level.** The default export
|
|
46
|
+
is now a plugin-definition object: `{ id, name, register, securityAuditCollectors }`.
|
|
47
|
+
The CLI audit picks up the collector from the object's field; the gateway
|
|
48
|
+
still registers it at runtime via `api.registerSecurityAuditCollector` for
|
|
49
|
+
any in-process audit surface that uses `getActivePluginRegistry()`. Both
|
|
50
|
+
paths now light up.
|
|
51
|
+
- **`vtSentinelAuditCollector` is self-contained.** It rebuilds the
|
|
52
|
+
compliance snapshot exclusively from `ctx.config`, `ctx.stateDir`, and
|
|
53
|
+
`ctx.configPath` — no closure state, no shared-module variables. Usable
|
|
54
|
+
from a cold-loaded plugin metadata snapshot.
|
|
55
|
+
- Runtime behavior (scanning, hooks, policies) unchanged.
|
|
56
|
+
|
|
5
57
|
## 0.12.0 — Transparency surface + log hygiene
|
|
6
58
|
|
|
7
59
|
**Headline:** what VT Sentinel does at runtime is now auditable from two
|
|
@@ -39,6 +39,16 @@ export interface ComplianceSnapshotInput {
|
|
|
39
39
|
agentPublicHandle?: string;
|
|
40
40
|
/** Optional: pre-collected log permission info (see `collectLogModes`). */
|
|
41
41
|
logModes?: LogModesInfo;
|
|
42
|
+
/**
|
|
43
|
+
* Where the snapshot is being built from. `runtime` means the gateway is
|
|
44
|
+
* running and `watchDirs` reflects the live watcher state (including
|
|
45
|
+
* auto-derived dirs like `/tmp`, `~/Downloads`, OpenClaw state subdirs).
|
|
46
|
+
* `static` means the snapshot is being built by a fresh CLI process
|
|
47
|
+
* (e.g. `openclaw security audit --deep`) that cannot see auto-derived
|
|
48
|
+
* dirs — only the user-configured `config.watchDirs` entries.
|
|
49
|
+
* Defaults to `static`.
|
|
50
|
+
*/
|
|
51
|
+
source?: 'runtime' | 'static';
|
|
42
52
|
}
|
|
43
53
|
export interface ComplianceSnapshot {
|
|
44
54
|
credentialMode: CredentialMode;
|
|
@@ -103,3 +113,16 @@ export declare function collectLogModes(stateDir: string): LogModesInfo;
|
|
|
103
113
|
* first and pass the result as `input.logModes`.
|
|
104
114
|
*/
|
|
105
115
|
export declare function buildComplianceSnapshot(input: ComplianceSnapshotInput): ComplianceSnapshot;
|
|
116
|
+
interface AuditCollectorCtx {
|
|
117
|
+
config: any;
|
|
118
|
+
sourceConfig: any;
|
|
119
|
+
env: NodeJS.ProcessEnv;
|
|
120
|
+
stateDir: string;
|
|
121
|
+
configPath: string;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Static security-audit collector. Pass this to OpenClaw via the plugin's
|
|
125
|
+
* module-level default export (`securityAuditCollectors: [vtSentinelAuditCollector]`).
|
|
126
|
+
*/
|
|
127
|
+
export declare function vtSentinelAuditCollector(ctx: AuditCollectorCtx): AuditFinding[];
|
|
128
|
+
export {};
|
|
@@ -53,8 +53,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
53
53
|
exports.computePaths = computePaths;
|
|
54
54
|
exports.collectLogModes = collectLogModes;
|
|
55
55
|
exports.buildComplianceSnapshot = buildComplianceSnapshot;
|
|
56
|
+
exports.vtSentinelAuditCollector = vtSentinelAuditCollector;
|
|
56
57
|
const fs = __importStar(require("fs"));
|
|
57
58
|
const path = __importStar(require("path"));
|
|
59
|
+
const config_manager_1 = require("./config-manager");
|
|
58
60
|
// --- Core paths helper (pure) ---
|
|
59
61
|
function computePaths(stateDir) {
|
|
60
62
|
const auditDir = path.join(stateDir, 'vt-sentinel-audit');
|
|
@@ -131,6 +133,7 @@ function isBroadWatchDir(dir) {
|
|
|
131
133
|
*/
|
|
132
134
|
function buildComplianceSnapshot(input) {
|
|
133
135
|
const { config, stateDir, credentialMode, watchDirs, agentPublicHandle, logModes } = input;
|
|
136
|
+
const source = input.source ?? 'static';
|
|
134
137
|
const paths = computePaths(stateDir);
|
|
135
138
|
const identity = {
|
|
136
139
|
displayNameSet: !!config.agentDisplayName,
|
|
@@ -161,13 +164,34 @@ function buildComplianceSnapshot(input) {
|
|
|
161
164
|
(credentialMode === 'vtai' ? 'ai.virustotal.com (scan requests)\n' : '') +
|
|
162
165
|
'registry.npmjs.org + clawhub.ai — only when the user explicitly invokes vt_sentinel_update.',
|
|
163
166
|
});
|
|
167
|
+
// Auto-scan finding. Detail text branches on (a) whether autoScan is on
|
|
168
|
+
// and (b) whether we're building the snapshot at runtime (live watcher
|
|
169
|
+
// list available) or statically (CLI audit process — only config.watchDirs
|
|
170
|
+
// is visible; auto-derived dirs like /tmp/Downloads/Desktop/OpenClaw state
|
|
171
|
+
// subdirs are computed by the gateway at runtime and cannot be recovered
|
|
172
|
+
// here).
|
|
173
|
+
const autoScanDetail = (() => {
|
|
174
|
+
if (!config.autoScan) {
|
|
175
|
+
return `Active protection hooks remain registered (block mode: ${config.blockMode}) but no background watcher is running.`;
|
|
176
|
+
}
|
|
177
|
+
const suffix = ` block mode: ${config.blockMode}. notify level: ${config.notifyLevel}.`;
|
|
178
|
+
if (source === 'runtime') {
|
|
179
|
+
return `Watching ${watchDirs.length} director${watchDirs.length === 1 ? 'y' : 'ies'}.${suffix}`;
|
|
180
|
+
}
|
|
181
|
+
// Static/CLI snapshot.
|
|
182
|
+
if (watchDirs.length > 0) {
|
|
183
|
+
return `User-configured watch dirs (${watchDirs.length}): ${watchDirs.join(', ')}. ` +
|
|
184
|
+
`Additional dirs auto-derived at gateway runtime (OS temp, ~/Downloads, ~/Desktop, OpenClaw state subdirs, workspace). ` +
|
|
185
|
+
`Run vt_sentinel_status inside the gateway for the live list.${suffix}`;
|
|
186
|
+
}
|
|
187
|
+
return `No user-configured watch dirs. At runtime the gateway auto-derives monitors from OS temp, ~/Downloads, ~/Desktop, and the OpenClaw state subdirs (skills, extensions, hooks, workspace). ` +
|
|
188
|
+
`Run vt_sentinel_status inside the gateway for the live list.${suffix}`;
|
|
189
|
+
})();
|
|
164
190
|
baseline.push({
|
|
165
191
|
checkId: 'vt-sentinel.auto-scan',
|
|
166
192
|
severity: 'info',
|
|
167
193
|
title: `Auto-scan: ${config.autoScan ? 'enabled' : 'disabled'}`,
|
|
168
|
-
detail:
|
|
169
|
-
? `Watching ${watchDirs.length} director${watchDirs.length === 1 ? 'y' : 'ies'}. block mode: ${config.blockMode}. notify level: ${config.notifyLevel}.`
|
|
170
|
-
: `Active protection hooks remain registered (block mode: ${config.blockMode}) but no background watcher is running.`,
|
|
194
|
+
detail: autoScanDetail,
|
|
171
195
|
});
|
|
172
196
|
baseline.push({
|
|
173
197
|
checkId: 'vt-sentinel.upload-policies',
|
|
@@ -301,3 +325,80 @@ function buildComplianceSnapshot(input) {
|
|
|
301
325
|
risks,
|
|
302
326
|
};
|
|
303
327
|
}
|
|
328
|
+
// --- Static (module-level) security audit collector ---
|
|
329
|
+
//
|
|
330
|
+
// The OpenClaw `security audit --deep` CLI runs in a fresh process that
|
|
331
|
+
// does NOT share state with the gateway. It therefore reads
|
|
332
|
+
// `securityAuditCollectors` from the plugin's module-level definition, NOT
|
|
333
|
+
// from runtime `api.registerSecurityAuditCollector(...)` calls.
|
|
334
|
+
//
|
|
335
|
+
// This function is the canonical collector used by the CLI. It derives the
|
|
336
|
+
// same snapshot as the gateway-side collector, but exclusively from the
|
|
337
|
+
// audit context (ctx.config, ctx.stateDir, ctx.configPath) — no closure
|
|
338
|
+
// state, no cross-module shared variables. Everything is reconstructable
|
|
339
|
+
// from what the CLI hands us.
|
|
340
|
+
//
|
|
341
|
+
// Differences from the gateway-side invocation:
|
|
342
|
+
// - `watchDirs` only includes user-configured dirs (`cfg.watchDirs`); the
|
|
343
|
+
// auto-derived dirs (tmp, ~/Downloads, etc.) are a runtime concept.
|
|
344
|
+
// - `credentialMode` is inferred from (a) presence of `cfg.apiKey` and
|
|
345
|
+
// (b) presence of the persisted agent credentials file on disk.
|
|
346
|
+
const PLUGIN_ID = 'openclaw-plugin-vt-sentinel';
|
|
347
|
+
function extractPluginConfig(cfg) {
|
|
348
|
+
try {
|
|
349
|
+
return cfg?.plugins?.entries?.[PLUGIN_ID]?.config ?? null;
|
|
350
|
+
}
|
|
351
|
+
catch {
|
|
352
|
+
return null;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
function readAgentPublicHandle(stateDir) {
|
|
356
|
+
try {
|
|
357
|
+
const raw = fs.readFileSync(path.join(stateDir, 'vt-sentinel-agent.json'), 'utf-8');
|
|
358
|
+
const parsed = JSON.parse(raw);
|
|
359
|
+
return typeof parsed?.publicHandle === 'string' ? parsed.publicHandle : undefined;
|
|
360
|
+
}
|
|
361
|
+
catch {
|
|
362
|
+
return undefined;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
function credentialsFileExists(stateDir) {
|
|
366
|
+
try {
|
|
367
|
+
return fs.statSync(path.join(stateDir, 'vt-sentinel-agent.json')).isFile();
|
|
368
|
+
}
|
|
369
|
+
catch {
|
|
370
|
+
return false;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Static security-audit collector. Pass this to OpenClaw via the plugin's
|
|
375
|
+
* module-level default export (`securityAuditCollectors: [vtSentinelAuditCollector]`).
|
|
376
|
+
*/
|
|
377
|
+
function vtSentinelAuditCollector(ctx) {
|
|
378
|
+
try {
|
|
379
|
+
const staticCfg = extractPluginConfig(ctx.config) ?? extractPluginConfig(ctx.sourceConfig);
|
|
380
|
+
const cm = new config_manager_1.ConfigManager(staticCfg);
|
|
381
|
+
const eff = cm.getEffective();
|
|
382
|
+
const hasUserKey = typeof staticCfg?.['apiKey'] === 'string' && staticCfg['apiKey'].trim().length > 0;
|
|
383
|
+
const hasCachedVtai = credentialsFileExists(ctx.stateDir);
|
|
384
|
+
const credentialMode = hasUserKey ? 'user_key' : (hasCachedVtai ? 'vtai' : 'none');
|
|
385
|
+
const watchDirs = Array.isArray(eff.watchDirs) ? [...eff.watchDirs] : [];
|
|
386
|
+
const snap = buildComplianceSnapshot({
|
|
387
|
+
config: eff,
|
|
388
|
+
stateDir: ctx.stateDir,
|
|
389
|
+
credentialMode,
|
|
390
|
+
watchDirs,
|
|
391
|
+
agentPublicHandle: readAgentPublicHandle(ctx.stateDir),
|
|
392
|
+
logModes: collectLogModes(ctx.stateDir),
|
|
393
|
+
});
|
|
394
|
+
return [...snap.baseline, ...snap.risks];
|
|
395
|
+
}
|
|
396
|
+
catch (err) {
|
|
397
|
+
return [{
|
|
398
|
+
checkId: 'vt-sentinel.audit-collector-error',
|
|
399
|
+
severity: 'warn',
|
|
400
|
+
title: 'VT Sentinel compliance snapshot failed to build',
|
|
401
|
+
detail: `Collector threw while assembling audit findings: ${err?.message || String(err)}`,
|
|
402
|
+
}];
|
|
403
|
+
}
|
|
404
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { SensitiveFilePolicy } from './scanner';
|
|
2
2
|
import { getCurrentVersion } from './version';
|
|
3
3
|
import { generateUpdateCommands } from './update-commands';
|
|
4
|
+
import { vtSentinelAuditCollector } from './compliance-snapshot';
|
|
4
5
|
interface VTSentinelConfig {
|
|
5
6
|
apiKey?: string;
|
|
6
7
|
watchDirs?: string[];
|
|
@@ -77,10 +78,34 @@ declare function buildEnhancedBio(eff: {
|
|
|
77
78
|
configPreset?: string;
|
|
78
79
|
autoScan?: boolean;
|
|
79
80
|
}): string;
|
|
80
|
-
|
|
81
|
+
declare function vtSentinelPlugin(api: PluginApi): void;
|
|
81
82
|
export declare const _generateUpdateCommands: typeof generateUpdateCommands;
|
|
82
83
|
export declare const _fetchLatestVersion: typeof fetchLatestVersion;
|
|
83
84
|
export declare const _getCurrentVersion: typeof getCurrentVersion;
|
|
84
85
|
export declare const _generateAgentName: typeof generateAgentName;
|
|
85
86
|
export declare const _buildEnhancedBio: typeof buildEnhancedBio;
|
|
86
|
-
|
|
87
|
+
/**
|
|
88
|
+
* Module-level plugin definition.
|
|
89
|
+
*
|
|
90
|
+
* `register(api)` runs inside the gateway — it's where the plugin wires up
|
|
91
|
+
* tools, hooks, the service, the runtime security-audit collector, and
|
|
92
|
+
* everything else that needs access to the live gateway API.
|
|
93
|
+
*
|
|
94
|
+
* `securityAuditCollectors` is read by `openclaw security audit --deep` in
|
|
95
|
+
* a FRESH Node process that does NOT share state with the gateway. That
|
|
96
|
+
* collector (`vtSentinelAuditCollector`) is self-contained: it rebuilds the
|
|
97
|
+
* compliance snapshot from ctx alone. Keeping it at module level is how
|
|
98
|
+
* plugin-declared findings land in `security audit` output.
|
|
99
|
+
*
|
|
100
|
+
* The dual-path wiring (runtime via `api.registerSecurityAuditCollector`
|
|
101
|
+
* inside `register`, static via `securityAuditCollectors` here) lets both
|
|
102
|
+
* the in-gateway audit flow and the out-of-process CLI flow surface the
|
|
103
|
+
* same data.
|
|
104
|
+
*/
|
|
105
|
+
declare const _default: {
|
|
106
|
+
id: string;
|
|
107
|
+
name: string;
|
|
108
|
+
register: typeof vtSentinelPlugin;
|
|
109
|
+
securityAuditCollectors: (typeof vtSentinelAuditCollector)[];
|
|
110
|
+
};
|
|
111
|
+
export default _default;
|
package/dist/index.js
CHANGED
|
@@ -39,7 +39,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
39
39
|
exports._buildEnhancedBio = exports._generateAgentName = exports._getCurrentVersion = exports._fetchLatestVersion = exports._generateUpdateCommands = void 0;
|
|
40
40
|
exports.isNewerVersion = isNewerVersion;
|
|
41
41
|
exports.isSelfPath = isSelfPath;
|
|
42
|
-
exports.default = vtSentinelPlugin;
|
|
43
42
|
const axios_1 = __importDefault(require("axios"));
|
|
44
43
|
const chokidar = __importStar(require("chokidar"));
|
|
45
44
|
const fs = __importStar(require("fs"));
|
|
@@ -360,6 +359,26 @@ function vtSentinelPlugin(api) {
|
|
|
360
359
|
const logDir = (0, audit_log_1.getLogDir)(resolvedStateDir);
|
|
361
360
|
const uploadLog = new audit_log_1.AuditLog(path.join(logDir, 'uploads.log'));
|
|
362
361
|
const detectionLog = new audit_log_1.AuditLog(path.join(logDir, 'detections.log'));
|
|
362
|
+
// v0.12.2: pre-0.12.0 installs left `vt-sentinel-uploads.log` and
|
|
363
|
+
// `vt-sentinel-detections.log` at the stateDir root with the process
|
|
364
|
+
// umask (typically 0o664). Upgrading doesn't rewrite them. Best-effort
|
|
365
|
+
// tighten-to-0o600 on load so operators who upgraded in place don't
|
|
366
|
+
// keep world-readable audit history. POSIX-only — no-op on Windows.
|
|
367
|
+
if (process.platform !== 'win32') {
|
|
368
|
+
for (const legacyName of ['vt-sentinel-uploads.log', 'vt-sentinel-detections.log']) {
|
|
369
|
+
const legacyPath = path.join(resolvedStateDir, legacyName);
|
|
370
|
+
try {
|
|
371
|
+
if (fs.existsSync(legacyPath)) {
|
|
372
|
+
const mode = fs.statSync(legacyPath).mode & 0o777;
|
|
373
|
+
if (mode !== 0o600) {
|
|
374
|
+
fs.chmodSync(legacyPath, 0o600);
|
|
375
|
+
api.logger.info(`[VT-Sentinel] Tightened permissions on legacy audit log ${legacyPath} (0o${mode.toString(8)} → 0o600)`);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
catch { /* best-effort */ }
|
|
380
|
+
}
|
|
381
|
+
}
|
|
363
382
|
/** Log a scan result to the appropriate audit log(s). */
|
|
364
383
|
const auditResult = (result) => {
|
|
365
384
|
if (!result.sha256)
|
|
@@ -765,6 +784,7 @@ function vtSentinelPlugin(api) {
|
|
|
765
784
|
watchDirs: [...watchRoots],
|
|
766
785
|
agentPublicHandle: (0, vt_api_1.loadAgentCredentials)()?.publicHandle,
|
|
767
786
|
logModes,
|
|
787
|
+
source: 'runtime',
|
|
768
788
|
});
|
|
769
789
|
return [...snap.baseline, ...snap.risks].map(f => ({
|
|
770
790
|
checkId: f.checkId,
|
|
@@ -959,6 +979,7 @@ function vtSentinelPlugin(api) {
|
|
|
959
979
|
watchDirs: [...watchRoots],
|
|
960
980
|
agentPublicHandle: (0, vt_api_1.loadAgentCredentials)()?.publicHandle,
|
|
961
981
|
logModes: (0, compliance_snapshot_1.collectLogModes)(resolvedStateDir),
|
|
982
|
+
source: 'runtime',
|
|
962
983
|
});
|
|
963
984
|
return textResponse((0, status_renderer_1.renderStatus)({
|
|
964
985
|
version: (0, version_1.getCurrentVersion)(),
|
|
@@ -1612,3 +1633,27 @@ exports._fetchLatestVersion = fetchLatestVersion;
|
|
|
1612
1633
|
exports._getCurrentVersion = version_1.getCurrentVersion;
|
|
1613
1634
|
exports._generateAgentName = generateAgentName;
|
|
1614
1635
|
exports._buildEnhancedBio = buildEnhancedBio;
|
|
1636
|
+
/**
|
|
1637
|
+
* Module-level plugin definition.
|
|
1638
|
+
*
|
|
1639
|
+
* `register(api)` runs inside the gateway — it's where the plugin wires up
|
|
1640
|
+
* tools, hooks, the service, the runtime security-audit collector, and
|
|
1641
|
+
* everything else that needs access to the live gateway API.
|
|
1642
|
+
*
|
|
1643
|
+
* `securityAuditCollectors` is read by `openclaw security audit --deep` in
|
|
1644
|
+
* a FRESH Node process that does NOT share state with the gateway. That
|
|
1645
|
+
* collector (`vtSentinelAuditCollector`) is self-contained: it rebuilds the
|
|
1646
|
+
* compliance snapshot from ctx alone. Keeping it at module level is how
|
|
1647
|
+
* plugin-declared findings land in `security audit` output.
|
|
1648
|
+
*
|
|
1649
|
+
* The dual-path wiring (runtime via `api.registerSecurityAuditCollector`
|
|
1650
|
+
* inside `register`, static via `securityAuditCollectors` here) lets both
|
|
1651
|
+
* the in-gateway audit flow and the out-of-process CLI flow surface the
|
|
1652
|
+
* same data.
|
|
1653
|
+
*/
|
|
1654
|
+
exports.default = {
|
|
1655
|
+
id: 'openclaw-plugin-vt-sentinel',
|
|
1656
|
+
name: 'VT Sentinel',
|
|
1657
|
+
register: vtSentinelPlugin,
|
|
1658
|
+
securityAuditCollectors: [compliance_snapshot_1.vtSentinelAuditCollector],
|
|
1659
|
+
};
|
package/dist/status-renderer.js
CHANGED
|
@@ -224,7 +224,7 @@ function renderHelp() {
|
|
|
224
224
|
lines.push(' - Files read by the agent (read tool) are hash-checked only, never auto-uploaded.');
|
|
225
225
|
lines.push(' - Session memory files are NEVER uploaded (privacy protection).');
|
|
226
226
|
lines.push(' - autoScan=false disables hook scanning (active blocking remains on).');
|
|
227
|
-
lines.push(' - Audit logs:
|
|
227
|
+
lines.push(' - Audit logs: <stateDir>/vt-sentinel-audit/uploads.log + detections.log (rotating; dir 0o700, files 0o600).');
|
|
228
228
|
return lines.join('\n');
|
|
229
229
|
}
|
|
230
230
|
// --- Config Change Result ---
|
package/openclaw.plugin.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "openclaw-plugin-vt-sentinel",
|
|
3
3
|
"name": "VT Sentinel",
|
|
4
4
|
"description": "VirusTotal Sentinel for OpenClaw — malware detection, active protection, and AI-powered code analysis.",
|
|
5
|
-
"version": "0.12.
|
|
5
|
+
"version": "0.12.2",
|
|
6
6
|
"skills": ["./skills"],
|
|
7
7
|
"contracts": {
|
|
8
8
|
"tools": [
|
package/package.json
CHANGED