@drakon-systems/shieldcortex-realtime 4.29.0 → 4.30.0
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/cloud-sync.ts +14 -2
- package/dist/cloud-sync.js +13 -2
- package/dist/index.js +6 -1
- package/dist/intercept-ingest.js +6 -1
- package/dist/openclaw.plugin.json +1 -1
- package/index.ts +7 -1
- package/intercept-ingest.ts +7 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
package/cloud-sync.ts
CHANGED
|
@@ -3,12 +3,24 @@
|
|
|
3
3
|
// Network egress for SC threat events. See CHANGELOG.md v4.12.8 / v4.12.9.
|
|
4
4
|
|
|
5
5
|
type CloudSyncConfig = {
|
|
6
|
+
cloudEnabled?: boolean;
|
|
6
7
|
cloudApiKey?: string;
|
|
7
8
|
cloudBaseUrl?: string;
|
|
8
9
|
};
|
|
9
10
|
|
|
10
11
|
export function cloudSync(threat: Record<string, unknown>, cfg: CloudSyncConfig): void {
|
|
11
|
-
|
|
12
|
+
// Consent gate: require cloud explicitly enabled AND an API key — matching every
|
|
13
|
+
// other egress sender (intercept-ingest.ts, src/cloud/*). Previously this checked
|
|
14
|
+
// the key alone, so events could leave the machine with a key present even when
|
|
15
|
+
// cloud sync was "off" (ClawScan finding: external scanning without a local-only
|
|
16
|
+
// default).
|
|
17
|
+
if (!cfg.cloudEnabled || !cfg.cloudApiKey) return;
|
|
18
|
+
// Privacy: never transmit raw LLM input. Strip any input content/preview snippet —
|
|
19
|
+
// forward threat METADATA only (ClawScan finding: previews may contain credentials
|
|
20
|
+
// or confidential data). The local audit log keeps fuller detail for triage.
|
|
21
|
+
const metadata: Record<string, unknown> = { ...threat };
|
|
22
|
+
delete metadata.content;
|
|
23
|
+
delete metadata.preview;
|
|
12
24
|
const url = `${cfg.cloudBaseUrl || 'https://api.shieldcortex.ai'}/v1/threats`;
|
|
13
25
|
fetch(url, {
|
|
14
26
|
method: 'POST',
|
|
@@ -16,7 +28,7 @@ export function cloudSync(threat: Record<string, unknown>, cfg: CloudSyncConfig)
|
|
|
16
28
|
'Content-Type': 'application/json',
|
|
17
29
|
Authorization: `Bearer ${cfg.cloudApiKey}`,
|
|
18
30
|
},
|
|
19
|
-
body: JSON.stringify(
|
|
31
|
+
body: JSON.stringify(metadata),
|
|
20
32
|
signal: AbortSignal.timeout(5000),
|
|
21
33
|
}).catch(() => {
|
|
22
34
|
// Fire-and-forget — never block on cloud sync failure
|
package/dist/cloud-sync.js
CHANGED
|
@@ -2,8 +2,19 @@
|
|
|
2
2
|
//
|
|
3
3
|
// Network egress for SC threat events. See CHANGELOG.md v4.12.8 / v4.12.9.
|
|
4
4
|
export function cloudSync(threat, cfg) {
|
|
5
|
-
|
|
5
|
+
// Consent gate: require cloud explicitly enabled AND an API key — matching every
|
|
6
|
+
// other egress sender (intercept-ingest.ts, src/cloud/*). Previously this checked
|
|
7
|
+
// the key alone, so events could leave the machine with a key present even when
|
|
8
|
+
// cloud sync was "off" (ClawScan finding: external scanning without a local-only
|
|
9
|
+
// default).
|
|
10
|
+
if (!cfg.cloudEnabled || !cfg.cloudApiKey)
|
|
6
11
|
return;
|
|
12
|
+
// Privacy: never transmit raw LLM input. Strip any input content/preview snippet —
|
|
13
|
+
// forward threat METADATA only (ClawScan finding: previews may contain credentials
|
|
14
|
+
// or confidential data). The local audit log keeps fuller detail for triage.
|
|
15
|
+
const metadata = { ...threat };
|
|
16
|
+
delete metadata.content;
|
|
17
|
+
delete metadata.preview;
|
|
7
18
|
const url = `${cfg.cloudBaseUrl || 'https://api.shieldcortex.ai'}/v1/threats`;
|
|
8
19
|
fetch(url, {
|
|
9
20
|
method: 'POST',
|
|
@@ -11,7 +22,7 @@ export function cloudSync(threat, cfg) {
|
|
|
11
22
|
'Content-Type': 'application/json',
|
|
12
23
|
Authorization: `Bearer ${cfg.cloudApiKey}`,
|
|
13
24
|
},
|
|
14
|
-
body: JSON.stringify(
|
|
25
|
+
body: JSON.stringify(metadata),
|
|
15
26
|
signal: AbortSignal.timeout(5000),
|
|
16
27
|
}).catch(() => {
|
|
17
28
|
// Fire-and-forget — never block on cloud sync failure
|
package/dist/index.js
CHANGED
|
@@ -195,6 +195,9 @@ function normaliseConfig(raw) {
|
|
|
195
195
|
if (typeof value.cloudBaseUrl === "string" && value.cloudBaseUrl.trim()) {
|
|
196
196
|
config.cloudBaseUrl = value.cloudBaseUrl.trim();
|
|
197
197
|
}
|
|
198
|
+
if (typeof value.cloudEnabled === "boolean") {
|
|
199
|
+
config.cloudEnabled = value.cloudEnabled;
|
|
200
|
+
}
|
|
198
201
|
if (typeof value.binaryPath === "string" && value.binaryPath.trim()) {
|
|
199
202
|
config.binaryPath = value.binaryPath.trim();
|
|
200
203
|
}
|
|
@@ -494,7 +497,9 @@ function handleLlmInput(event, ctx) {
|
|
|
494
497
|
};
|
|
495
498
|
auditLog(entry);
|
|
496
499
|
loadConfig()
|
|
497
|
-
|
|
500
|
+
// Pass the local entry as-is; cloudSync strips the input preview/content
|
|
501
|
+
// before transmit (metadata-only egress). No raw LLM input leaves here.
|
|
502
|
+
.then(cfg => cloudSync(entry, cfg))
|
|
498
503
|
.catch(() => { });
|
|
499
504
|
}
|
|
500
505
|
}
|
package/dist/intercept-ingest.js
CHANGED
|
@@ -2,6 +2,11 @@ export function syncInterceptEvent(event, config) {
|
|
|
2
2
|
if (!config.cloudEnabled || !config.cloudApiKey)
|
|
3
3
|
return;
|
|
4
4
|
const url = `${config.cloudBaseUrl}/v1/audit/ingest`;
|
|
5
|
+
// Privacy: forward audit METADATA only — strip the content preview so raw memory
|
|
6
|
+
// text never leaves the machine (ClawScan finding: previews may contain credentials
|
|
7
|
+
// or confidential data). The local audit JSONL retains the preview for triage.
|
|
8
|
+
const metadata = { ...event };
|
|
9
|
+
delete metadata.preview;
|
|
5
10
|
fetch(url, {
|
|
6
11
|
method: 'POST',
|
|
7
12
|
headers: {
|
|
@@ -9,7 +14,7 @@ export function syncInterceptEvent(event, config) {
|
|
|
9
14
|
Authorization: `Bearer ${config.cloudApiKey}`,
|
|
10
15
|
},
|
|
11
16
|
body: JSON.stringify({
|
|
12
|
-
events: [{ ...
|
|
17
|
+
events: [{ ...metadata, source: 'openclaw-interceptor' }],
|
|
13
18
|
}),
|
|
14
19
|
signal: AbortSignal.timeout(5_000),
|
|
15
20
|
}).catch(() => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "shieldcortex-realtime",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.30.0",
|
|
4
4
|
"name": "ShieldCortex Real-time Scanner",
|
|
5
5
|
"description": "Real-time defence scanning on LLM input, memory extraction on LLM output, and active tool call interception with approval gating.",
|
|
6
6
|
"kind": null,
|
package/index.ts
CHANGED
|
@@ -143,6 +143,7 @@ type PluginApi = {
|
|
|
143
143
|
// ==================== CONFIG ====================
|
|
144
144
|
|
|
145
145
|
interface SCConfig {
|
|
146
|
+
cloudEnabled?: boolean;
|
|
146
147
|
cloudApiKey?: string;
|
|
147
148
|
cloudBaseUrl?: string;
|
|
148
149
|
binaryPath?: string;
|
|
@@ -250,6 +251,9 @@ function normaliseConfig(raw: unknown): SCConfig {
|
|
|
250
251
|
if (typeof value.cloudBaseUrl === "string" && value.cloudBaseUrl.trim()) {
|
|
251
252
|
config.cloudBaseUrl = value.cloudBaseUrl.trim();
|
|
252
253
|
}
|
|
254
|
+
if (typeof value.cloudEnabled === "boolean") {
|
|
255
|
+
config.cloudEnabled = value.cloudEnabled;
|
|
256
|
+
}
|
|
253
257
|
if (typeof value.binaryPath === "string" && value.binaryPath.trim()) {
|
|
254
258
|
config.binaryPath = value.binaryPath.trim();
|
|
255
259
|
}
|
|
@@ -594,7 +598,9 @@ function handleLlmInput(event: LlmInputEvent, ctx: AgentCtx): void {
|
|
|
594
598
|
};
|
|
595
599
|
auditLog(entry);
|
|
596
600
|
loadConfig()
|
|
597
|
-
|
|
601
|
+
// Pass the local entry as-is; cloudSync strips the input preview/content
|
|
602
|
+
// before transmit (metadata-only egress). No raw LLM input leaves here.
|
|
603
|
+
.then(cfg => cloudSync(entry, cfg))
|
|
598
604
|
.catch(() => {});
|
|
599
605
|
}
|
|
600
606
|
}
|
package/intercept-ingest.ts
CHANGED
|
@@ -12,6 +12,12 @@ export function syncInterceptEvent(event: InterceptAuditEntry, config: CloudConf
|
|
|
12
12
|
|
|
13
13
|
const url = `${config.cloudBaseUrl}/v1/audit/ingest`;
|
|
14
14
|
|
|
15
|
+
// Privacy: forward audit METADATA only — strip the content preview so raw memory
|
|
16
|
+
// text never leaves the machine (ClawScan finding: previews may contain credentials
|
|
17
|
+
// or confidential data). The local audit JSONL retains the preview for triage.
|
|
18
|
+
const metadata: Record<string, unknown> = { ...event };
|
|
19
|
+
delete metadata.preview;
|
|
20
|
+
|
|
15
21
|
fetch(url, {
|
|
16
22
|
method: 'POST',
|
|
17
23
|
headers: {
|
|
@@ -19,7 +25,7 @@ export function syncInterceptEvent(event: InterceptAuditEntry, config: CloudConf
|
|
|
19
25
|
Authorization: `Bearer ${config.cloudApiKey}`,
|
|
20
26
|
},
|
|
21
27
|
body: JSON.stringify({
|
|
22
|
-
events: [{ ...
|
|
28
|
+
events: [{ ...metadata, source: 'openclaw-interceptor' }],
|
|
23
29
|
}),
|
|
24
30
|
signal: AbortSignal.timeout(5_000),
|
|
25
31
|
}).catch(() => {
|
package/openclaw.plugin.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "shieldcortex-realtime",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.30.0",
|
|
4
4
|
"name": "ShieldCortex Real-time Scanner",
|
|
5
5
|
"description": "Real-time defence scanning on LLM input, memory extraction on LLM output, and active tool call interception with approval gating.",
|
|
6
6
|
"kind": null,
|
package/package.json
CHANGED