openclaw-plugin-vt-sentinel 0.9.0 → 0.9.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/config-manager.js +28 -11
- package/dist/index.js +42 -5
- package/package.json +1 -1
package/dist/config-manager.js
CHANGED
|
@@ -195,48 +195,65 @@ function validateOverrides(input) {
|
|
|
195
195
|
}
|
|
196
196
|
}
|
|
197
197
|
// --- Agent identity fields ---
|
|
198
|
+
// Empty string or null clears the field (sets to undefined in overrides).
|
|
198
199
|
if ('agentDisplayName' in input) {
|
|
199
200
|
const v = input.agentDisplayName;
|
|
200
|
-
if (
|
|
201
|
+
if (v === '' || v === null) {
|
|
202
|
+
valid.agentDisplayName = undefined;
|
|
203
|
+
}
|
|
204
|
+
else if (typeof v === 'string' && v.length >= 1 && v.length <= 50 && DISPLAY_NAME_RE.test(v)) {
|
|
201
205
|
valid.agentDisplayName = v;
|
|
202
206
|
}
|
|
203
207
|
else {
|
|
204
|
-
errors.push('agentDisplayName must be 1-50 chars matching [a-zA-Z0-9 _-]');
|
|
208
|
+
errors.push('agentDisplayName must be 1-50 chars matching [a-zA-Z0-9 _-] (or empty to clear)');
|
|
205
209
|
}
|
|
206
210
|
}
|
|
207
211
|
if ('agentHumanAlias' in input) {
|
|
208
212
|
const v = input.agentHumanAlias;
|
|
209
|
-
if (
|
|
213
|
+
if (v === '' || v === null) {
|
|
214
|
+
valid.agentHumanAlias = undefined;
|
|
215
|
+
}
|
|
216
|
+
else if (typeof v === 'string' && v.length >= 1 && v.length <= 50 && HUMAN_ALIAS_RE.test(v)) {
|
|
210
217
|
valid.agentHumanAlias = v;
|
|
211
218
|
}
|
|
212
219
|
else {
|
|
213
|
-
errors.push('agentHumanAlias must be 1-50 chars matching [a-zA-Z0-9_-] (
|
|
220
|
+
errors.push('agentHumanAlias must be 1-50 chars matching [a-zA-Z0-9_-] (or empty to clear)');
|
|
214
221
|
}
|
|
215
222
|
}
|
|
216
223
|
if ('agentBio' in input) {
|
|
217
224
|
const v = input.agentBio;
|
|
218
|
-
if (
|
|
225
|
+
if (v === '' || v === null) {
|
|
226
|
+
valid.agentBio = undefined;
|
|
227
|
+
}
|
|
228
|
+
else if (typeof v === 'string' && v.length >= 1 && v.length <= 200) {
|
|
219
229
|
valid.agentBio = v;
|
|
220
230
|
}
|
|
221
231
|
else {
|
|
222
|
-
errors.push('agentBio must be 1-200 chars');
|
|
232
|
+
errors.push('agentBio must be 1-200 chars (or empty to clear)');
|
|
223
233
|
}
|
|
224
234
|
}
|
|
225
235
|
if ('agentContactEmail' in input) {
|
|
226
236
|
const v = input.agentContactEmail;
|
|
227
|
-
if (
|
|
237
|
+
if (v === '' || v === null) {
|
|
238
|
+
valid.agentContactEmail = undefined;
|
|
239
|
+
}
|
|
240
|
+
else if (typeof v === 'string' && v.length <= 100 && EMAIL_RE.test(v)) {
|
|
228
241
|
valid.agentContactEmail = v;
|
|
229
242
|
}
|
|
230
243
|
else {
|
|
231
|
-
errors.push('agentContactEmail must be a valid email (
|
|
244
|
+
errors.push('agentContactEmail must be a valid email (or empty to clear)');
|
|
232
245
|
}
|
|
233
246
|
}
|
|
234
247
|
if ('agentMetadataMode' in input) {
|
|
235
|
-
|
|
236
|
-
|
|
248
|
+
const v = input.agentMetadataMode;
|
|
249
|
+
if (v === '' || v === null) {
|
|
250
|
+
valid.agentMetadataMode = undefined;
|
|
251
|
+
}
|
|
252
|
+
else if (VALID_METADATA_MODES.has(v)) {
|
|
253
|
+
valid.agentMetadataMode = v;
|
|
237
254
|
}
|
|
238
255
|
else {
|
|
239
|
-
errors.push('agentMetadataMode must be: minimal, enhanced');
|
|
256
|
+
errors.push('agentMetadataMode must be: minimal, enhanced (or empty to clear)');
|
|
240
257
|
}
|
|
241
258
|
}
|
|
242
259
|
return { valid, errors };
|
package/dist/index.js
CHANGED
|
@@ -291,13 +291,26 @@ function vtSentinelPlugin(api) {
|
|
|
291
291
|
catch { }
|
|
292
292
|
return pluginVer.slice(0, 20);
|
|
293
293
|
}
|
|
294
|
+
// VTAI API field constraints (used to sanitize static config values)
|
|
295
|
+
const VTAI_DISPLAY_NAME_RE = /^[a-zA-Z0-9 _-]+$/;
|
|
296
|
+
const VTAI_HUMAN_ALIAS_RE = /^[a-zA-Z0-9_-]+$/;
|
|
297
|
+
const VTAI_EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
294
298
|
/**
|
|
295
299
|
* Build registration opts from effective config.
|
|
300
|
+
* Sanitizes identity fields against VTAI API constraints to prevent
|
|
301
|
+
* registration failures from invalid static config values.
|
|
296
302
|
*/
|
|
297
303
|
function buildRegistrationOpts() {
|
|
298
304
|
const eff = configManager.getEffective();
|
|
299
305
|
// Resolve display name: config > persisted auto-name > generate new
|
|
300
306
|
let displayName = eff.agentDisplayName;
|
|
307
|
+
if (displayName) {
|
|
308
|
+
// Validate against VTAI constraints: 1-50 chars, [a-zA-Z0-9 _-]+
|
|
309
|
+
if (displayName.length > 50 || !VTAI_DISPLAY_NAME_RE.test(displayName)) {
|
|
310
|
+
api.logger.warn(`[VT-Sentinel] Invalid agentDisplayName in config: "${displayName.substring(0, 20)}..." — falling back to auto-generated name`);
|
|
311
|
+
displayName = undefined;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
301
314
|
if (!displayName) {
|
|
302
315
|
let autoName = stateStore.getAutoAgentName();
|
|
303
316
|
if (!autoName) {
|
|
@@ -311,12 +324,28 @@ function vtSentinelPlugin(api) {
|
|
|
311
324
|
agentVersion: buildAgentVersion(),
|
|
312
325
|
displayName,
|
|
313
326
|
};
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
327
|
+
// Validate humanAlias: 1-50 chars, [a-zA-Z0-9_-]+
|
|
328
|
+
if (eff.agentHumanAlias) {
|
|
329
|
+
if (eff.agentHumanAlias.length <= 50 && VTAI_HUMAN_ALIAS_RE.test(eff.agentHumanAlias)) {
|
|
330
|
+
regOpts.humanAlias = eff.agentHumanAlias;
|
|
331
|
+
}
|
|
332
|
+
else {
|
|
333
|
+
api.logger.warn(`[VT-Sentinel] Invalid agentHumanAlias in config — skipping`);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
// Validate contactEmail: max 100 chars, email format
|
|
337
|
+
if (eff.agentContactEmail) {
|
|
338
|
+
if (eff.agentContactEmail.length <= 100 && VTAI_EMAIL_RE.test(eff.agentContactEmail)) {
|
|
339
|
+
regOpts.contactEmail = eff.agentContactEmail;
|
|
340
|
+
}
|
|
341
|
+
else {
|
|
342
|
+
api.logger.warn(`[VT-Sentinel] Invalid agentContactEmail in config — skipping`);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
318
345
|
if (eff.agentMetadataMode === 'enhanced') {
|
|
319
|
-
|
|
346
|
+
const bio = eff.agentBio || buildEnhancedBio(eff);
|
|
347
|
+
// Validate: 1-200 chars
|
|
348
|
+
regOpts.defineYourSelf = bio.length <= 200 ? bio : bio.slice(0, 200);
|
|
320
349
|
}
|
|
321
350
|
return regOpts;
|
|
322
351
|
}
|
|
@@ -1212,6 +1241,14 @@ function vtSentinelPlugin(api) {
|
|
|
1212
1241
|
if (currentCreds) {
|
|
1213
1242
|
const backupPath = (0, vt_api_1.getAgentCredentialsPath)() + '.bak';
|
|
1214
1243
|
fs.writeFileSync(backupPath, JSON.stringify(currentCreds, null, 2), { mode: 0o600 });
|
|
1244
|
+
// Windows: POSIX mode bits ignored on NTFS — restrict via ACL
|
|
1245
|
+
if (process.platform === 'win32') {
|
|
1246
|
+
try {
|
|
1247
|
+
const { execSync } = require('child_process');
|
|
1248
|
+
execSync(`icacls "${backupPath}" /inheritance:r /grant:r "%USERNAME%:(F)"`, { stdio: 'ignore' });
|
|
1249
|
+
}
|
|
1250
|
+
catch { /* best effort */ }
|
|
1251
|
+
}
|
|
1215
1252
|
}
|
|
1216
1253
|
const newCreds = await (0, vt_api_1.registerAgent)(buildRegistrationOpts());
|
|
1217
1254
|
(0, vt_api_1.saveAgentCredentials)(newCreds);
|
package/package.json
CHANGED