@upx-us/shield 0.2.16-beta → 0.3.5
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/README.md +178 -53
- package/dist/index.d.ts +13 -15
- package/dist/index.js +593 -245
- package/dist/src/config.d.ts +1 -15
- package/dist/src/config.js +3 -39
- package/dist/src/counters.d.ts +14 -0
- package/dist/src/counters.js +96 -0
- package/dist/src/events/base.d.ts +0 -25
- package/dist/src/events/base.js +0 -15
- package/dist/src/events/browser/enrich.js +1 -1
- package/dist/src/events/exec/enrich.js +0 -2
- package/dist/src/events/exec/redactions.d.ts +0 -1
- package/dist/src/events/exec/redactions.js +0 -1
- package/dist/src/events/file/enrich.js +0 -3
- package/dist/src/events/generic/index.d.ts +0 -1
- package/dist/src/events/generic/index.js +0 -1
- package/dist/src/events/index.d.ts +0 -13
- package/dist/src/events/index.js +1 -13
- package/dist/src/events/message/validations.js +0 -3
- package/dist/src/events/sessions-spawn/enrich.js +0 -1
- package/dist/src/events/sessions-spawn/event.d.ts +0 -1
- package/dist/src/events/tool-result/enrich.js +0 -1
- package/dist/src/events/tool-result/redactions.js +0 -1
- package/dist/src/events/web/enrich.d.ts +0 -4
- package/dist/src/events/web/enrich.js +6 -14
- package/dist/src/events/web/redactions.js +1 -3
- package/dist/src/fetcher.d.ts +1 -0
- package/dist/src/fetcher.js +28 -19
- package/dist/src/index.js +51 -16
- package/dist/src/log.d.ts +0 -26
- package/dist/src/log.js +1 -27
- package/dist/src/redactor/base.d.ts +0 -23
- package/dist/src/redactor/base.js +0 -7
- package/dist/src/redactor/index.d.ts +0 -15
- package/dist/src/redactor/index.js +8 -27
- package/dist/src/redactor/strategies/command.js +0 -3
- package/dist/src/redactor/strategies/hostname.js +0 -1
- package/dist/src/redactor/strategies/index.d.ts +0 -5
- package/dist/src/redactor/strategies/index.js +0 -5
- package/dist/src/redactor/strategies/path.js +3 -3
- package/dist/src/redactor/strategies/secret-key.js +33 -9
- package/dist/src/redactor/vault.d.ts +0 -19
- package/dist/src/redactor/vault.js +7 -35
- package/dist/src/sender.d.ts +12 -20
- package/dist/src/sender.js +40 -36
- package/dist/src/setup.d.ts +11 -9
- package/dist/src/setup.js +33 -32
- package/dist/src/transformer.d.ts +1 -12
- package/dist/src/transformer.js +73 -48
- package/dist/src/validator.d.ts +0 -11
- package/dist/src/validator.js +19 -25
- package/dist/src/version.js +1 -2
- package/openclaw.plugin.json +10 -2
- package/package.json +8 -3
- package/dist/src/host-collector.d.ts +0 -1
- package/dist/src/host-collector.js +0 -200
- package/skills/shield/SKILL.md +0 -38
package/dist/src/config.d.ts
CHANGED
|
@@ -15,24 +15,10 @@ export interface Config {
|
|
|
15
15
|
redactionEnabled: boolean;
|
|
16
16
|
credentials: ShieldCredentials;
|
|
17
17
|
}
|
|
18
|
-
/** Canonical config location — shared by setup, bridge, and plugin entry. */
|
|
19
18
|
export declare const SHIELD_CONFIG_PATH: string;
|
|
20
|
-
/**
|
|
21
|
-
* Inject config file values into process.env so the standalone bridge
|
|
22
|
-
* (sender, fetcher, etc.) can read credentials via env vars.
|
|
23
|
-
* Values already set in the environment take precedence (allows override).
|
|
24
|
-
*/
|
|
25
19
|
export declare function injectConfigEnv(): void;
|
|
26
|
-
/**
|
|
27
|
-
* Load credentials from config.env file and environment variables.
|
|
28
|
-
* Supports new env var names with backward compat for the old names.
|
|
29
|
-
*/
|
|
30
20
|
export declare function loadCredentials(): ShieldCredentials;
|
|
31
|
-
|
|
32
|
-
* Build credentials from a plugin config object (openclaw.json).
|
|
33
|
-
* Falls back to config.env / env vars for any missing values.
|
|
34
|
-
*/
|
|
35
|
-
export declare function loadCredentialsFromPluginConfig(pluginConfig: Record<string, unknown>): ShieldCredentials;
|
|
21
|
+
export declare function loadCredentialsFromPluginConfig(_pluginConfig: Record<string, unknown>): ShieldCredentials;
|
|
36
22
|
export interface ConfigOverrides {
|
|
37
23
|
credentials?: ShieldCredentials;
|
|
38
24
|
dryRun?: boolean;
|
package/dist/src/config.js
CHANGED
|
@@ -42,7 +42,6 @@ const os_1 = require("os");
|
|
|
42
42
|
const path_1 = require("path");
|
|
43
43
|
const fs_1 = require("fs");
|
|
44
44
|
const log = __importStar(require("./log"));
|
|
45
|
-
/** Default OpenClaw agents directory */
|
|
46
45
|
const OPENCLAW_AGENTS_DIR = (0, path_1.join)((0, os_1.homedir)(), '.openclaw/agents');
|
|
47
46
|
function safeParseInt(value, fallback) {
|
|
48
47
|
if (!value)
|
|
@@ -50,13 +49,6 @@ function safeParseInt(value, fallback) {
|
|
|
50
49
|
const parsed = parseInt(value, 10);
|
|
51
50
|
return isNaN(parsed) ? fallback : parsed;
|
|
52
51
|
}
|
|
53
|
-
function optString(val) {
|
|
54
|
-
return val != null ? String(val) : '';
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Auto-discover all agent session directories.
|
|
58
|
-
* Scans ~/.openclaw/agents/{agent}/sessions for directories that exist.
|
|
59
|
-
*/
|
|
60
52
|
function discoverSessionDirs() {
|
|
61
53
|
const dirs = [];
|
|
62
54
|
if (!(0, fs_1.existsSync)(OPENCLAW_AGENTS_DIR))
|
|
@@ -74,15 +66,7 @@ function discoverSessionDirs() {
|
|
|
74
66
|
}
|
|
75
67
|
return dirs;
|
|
76
68
|
}
|
|
77
|
-
/** Canonical config location — shared by setup, bridge, and plugin entry. */
|
|
78
69
|
exports.SHIELD_CONFIG_PATH = (0, path_1.join)((0, os_1.homedir)(), '.openclaw', 'shield', 'config.env');
|
|
79
|
-
/**
|
|
80
|
-
* Load config file if it exists (~/.openclaw/shield/config.env).
|
|
81
|
-
* Parses KEY=VALUE lines into a flat record. Lines starting with # are ignored.
|
|
82
|
-
*
|
|
83
|
-
* The path can be overridden by SHIELD_CONFIG_PATH env var — used in tests
|
|
84
|
-
* to isolate from real credentials on the developer machine.
|
|
85
|
-
*/
|
|
86
70
|
function loadConfigFile() {
|
|
87
71
|
const configPath = process.env.SHIELD_CONFIG_PATH || exports.SHIELD_CONFIG_PATH;
|
|
88
72
|
if (!(0, fs_1.existsSync)(configPath))
|
|
@@ -103,14 +87,9 @@ function loadConfigFile() {
|
|
|
103
87
|
}
|
|
104
88
|
return result;
|
|
105
89
|
}
|
|
106
|
-
catch {
|
|
90
|
+
catch { }
|
|
107
91
|
return {};
|
|
108
92
|
}
|
|
109
|
-
/**
|
|
110
|
-
* Inject config file values into process.env so the standalone bridge
|
|
111
|
-
* (sender, fetcher, etc.) can read credentials via env vars.
|
|
112
|
-
* Values already set in the environment take precedence (allows override).
|
|
113
|
-
*/
|
|
114
93
|
function injectConfigEnv() {
|
|
115
94
|
const file = loadConfigFile();
|
|
116
95
|
for (const [key, val] of Object.entries(file)) {
|
|
@@ -118,10 +97,6 @@ function injectConfigEnv() {
|
|
|
118
97
|
process.env[key] = val;
|
|
119
98
|
}
|
|
120
99
|
}
|
|
121
|
-
/**
|
|
122
|
-
* Load credentials from config.env file and environment variables.
|
|
123
|
-
* Supports new env var names with backward compat for the old names.
|
|
124
|
-
*/
|
|
125
100
|
function loadCredentials() {
|
|
126
101
|
const file = loadConfigFile();
|
|
127
102
|
function resolve(newName, oldName) {
|
|
@@ -138,19 +113,8 @@ function loadCredentials() {
|
|
|
138
113
|
shieldEnv: process.env.SHIELD_ENV || file.SHIELD_ENV || '',
|
|
139
114
|
};
|
|
140
115
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
* Falls back to config.env / env vars for any missing values.
|
|
144
|
-
*/
|
|
145
|
-
function loadCredentialsFromPluginConfig(pluginConfig) {
|
|
146
|
-
const fileCreds = loadCredentials();
|
|
147
|
-
return {
|
|
148
|
-
apiUrl: optString(pluginConfig.apiUrl) || fileCreds.apiUrl,
|
|
149
|
-
hmacSecret: optString(pluginConfig.registrationKey) || fileCreds.hmacSecret,
|
|
150
|
-
instanceId: optString(pluginConfig.instanceId) || fileCreds.instanceId,
|
|
151
|
-
// shieldEnv is internal — not exposed in plugin config (customers only see PROD)
|
|
152
|
-
shieldEnv: fileCreds.shieldEnv,
|
|
153
|
-
};
|
|
116
|
+
function loadCredentialsFromPluginConfig(_pluginConfig) {
|
|
117
|
+
return loadCredentials();
|
|
154
118
|
}
|
|
155
119
|
function loadConfig(overrides) {
|
|
156
120
|
if (!overrides?.credentials) {
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare function recordEventType(eventType: string): void;
|
|
2
|
+
export declare function getEventTypeCounts(): Array<{
|
|
3
|
+
type: string;
|
|
4
|
+
count: number;
|
|
5
|
+
}>;
|
|
6
|
+
export declare function getTotalEventCount(): number;
|
|
7
|
+
export declare function recordRedaction(category: string): void;
|
|
8
|
+
export declare function getRedactionCounts(): Array<{
|
|
9
|
+
category: string;
|
|
10
|
+
count: number;
|
|
11
|
+
}>;
|
|
12
|
+
export declare function getTotalRedactionCount(): number;
|
|
13
|
+
export declare function formatStats(): string;
|
|
14
|
+
export declare function _resetCountersForTesting(): void;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.recordEventType = recordEventType;
|
|
4
|
+
exports.getEventTypeCounts = getEventTypeCounts;
|
|
5
|
+
exports.getTotalEventCount = getTotalEventCount;
|
|
6
|
+
exports.recordRedaction = recordRedaction;
|
|
7
|
+
exports.getRedactionCounts = getRedactionCounts;
|
|
8
|
+
exports.getTotalRedactionCount = getTotalRedactionCount;
|
|
9
|
+
exports.formatStats = formatStats;
|
|
10
|
+
exports._resetCountersForTesting = _resetCountersForTesting;
|
|
11
|
+
const eventTypeCounts = new Map();
|
|
12
|
+
let sessionStartedAt = Date.now();
|
|
13
|
+
function recordEventType(eventType) {
|
|
14
|
+
if (!eventType)
|
|
15
|
+
return;
|
|
16
|
+
eventTypeCounts.set(eventType, (eventTypeCounts.get(eventType) ?? 0) + 1);
|
|
17
|
+
}
|
|
18
|
+
function getEventTypeCounts() {
|
|
19
|
+
return Array.from(eventTypeCounts.entries())
|
|
20
|
+
.map(([type, count]) => ({ type, count }))
|
|
21
|
+
.sort((a, b) => b.count - a.count);
|
|
22
|
+
}
|
|
23
|
+
function getTotalEventCount() {
|
|
24
|
+
let total = 0;
|
|
25
|
+
for (const v of eventTypeCounts.values())
|
|
26
|
+
total += v;
|
|
27
|
+
return total;
|
|
28
|
+
}
|
|
29
|
+
const redactionCounts = new Map();
|
|
30
|
+
function recordRedaction(category) {
|
|
31
|
+
if (!category)
|
|
32
|
+
return;
|
|
33
|
+
redactionCounts.set(category, (redactionCounts.get(category) ?? 0) + 1);
|
|
34
|
+
}
|
|
35
|
+
function getRedactionCounts() {
|
|
36
|
+
return Array.from(redactionCounts.entries())
|
|
37
|
+
.map(([category, count]) => ({ category, count }))
|
|
38
|
+
.sort((a, b) => b.count - a.count);
|
|
39
|
+
}
|
|
40
|
+
function getTotalRedactionCount() {
|
|
41
|
+
let total = 0;
|
|
42
|
+
for (const v of redactionCounts.values())
|
|
43
|
+
total += v;
|
|
44
|
+
return total;
|
|
45
|
+
}
|
|
46
|
+
const BAR_CHARS = '████████████████████';
|
|
47
|
+
const BAR_MAX_WIDTH = 8;
|
|
48
|
+
function bar(count, max) {
|
|
49
|
+
if (max === 0)
|
|
50
|
+
return '';
|
|
51
|
+
const filled = Math.max(1, Math.round((count / max) * BAR_MAX_WIDTH));
|
|
52
|
+
return BAR_CHARS.slice(0, filled);
|
|
53
|
+
}
|
|
54
|
+
function formatStats() {
|
|
55
|
+
const totalEvents = getTotalEventCount();
|
|
56
|
+
const eventRows = getEventTypeCounts();
|
|
57
|
+
const maxEventCount = eventRows[0]?.count ?? 0;
|
|
58
|
+
const totalRedactions = getTotalRedactionCount();
|
|
59
|
+
const redactionRows = getRedactionCounts();
|
|
60
|
+
const uptimeSec = Math.round((Date.now() - sessionStartedAt) / 1000);
|
|
61
|
+
const uptimeLabel = uptimeSec < 60
|
|
62
|
+
? `${uptimeSec}s`
|
|
63
|
+
: uptimeSec < 3600
|
|
64
|
+
? `${Math.floor(uptimeSec / 60)}m`
|
|
65
|
+
: `${(uptimeSec / 3600).toFixed(1)}h`;
|
|
66
|
+
const lines = [];
|
|
67
|
+
lines.push(`🛡️ Shield Stats (session uptime: ${uptimeLabel})`);
|
|
68
|
+
lines.push('');
|
|
69
|
+
lines.push(`📊 Events transmitted: ${totalEvents}`);
|
|
70
|
+
if (eventRows.length === 0) {
|
|
71
|
+
lines.push(' (no events yet)');
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
for (const { type, count } of eventRows) {
|
|
75
|
+
const b = bar(count, maxEventCount);
|
|
76
|
+
lines.push(` ${type.padEnd(20)} ${b.padEnd(BAR_MAX_WIDTH + 1)} ${count}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
lines.push('');
|
|
80
|
+
lines.push(`🔒 Redactions applied: ${totalRedactions}`);
|
|
81
|
+
if (redactionRows.length === 0) {
|
|
82
|
+
lines.push(' (none)');
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
for (const { category, count } of redactionRows) {
|
|
86
|
+
lines.push(` ${category.padEnd(20)} ${count}`);
|
|
87
|
+
}
|
|
88
|
+
lines.push(' (values never stored or transmitted)');
|
|
89
|
+
}
|
|
90
|
+
return lines.join('\n');
|
|
91
|
+
}
|
|
92
|
+
function _resetCountersForTesting() {
|
|
93
|
+
eventTypeCounts.clear();
|
|
94
|
+
redactionCounts.clear();
|
|
95
|
+
sessionStartedAt = Date.now();
|
|
96
|
+
}
|
|
@@ -1,14 +1,7 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* base.ts — Core types, composable blocks, and generic engine for the Shield event model.
|
|
3
|
-
*
|
|
4
|
-
* All event types extend BaseEvent. The engine composes base rules with type-specific rules.
|
|
5
|
-
* Individual event types never redeclare base-level concerns.
|
|
6
|
-
*/
|
|
7
1
|
export interface BaseEvent {
|
|
8
2
|
timestamp: string;
|
|
9
3
|
event_type: 'TOOL_CALL' | 'TOOL_RESULT';
|
|
10
4
|
tool_name: string;
|
|
11
|
-
/** Discriminator — lets the parser know the shape of each event */
|
|
12
5
|
tool_category: string;
|
|
13
6
|
session_id: string;
|
|
14
7
|
model?: string;
|
|
@@ -22,7 +15,6 @@ export interface BaseEvent {
|
|
|
22
15
|
};
|
|
23
16
|
tool_metadata?: Record<string, string | null>;
|
|
24
17
|
}
|
|
25
|
-
/** Attach to any event type when network context is relevant (SSH, HTTP, etc.) */
|
|
26
18
|
export interface NetworkBlock {
|
|
27
19
|
network: {
|
|
28
20
|
session_id: string;
|
|
@@ -30,11 +22,6 @@ export interface NetworkBlock {
|
|
|
30
22
|
direction: string;
|
|
31
23
|
};
|
|
32
24
|
}
|
|
33
|
-
/**
|
|
34
|
-
* Attach to any event type when a security-relevant finding is detected.
|
|
35
|
-
* NOTE: `target` is NOT a composable block — each event type owns its `target` shape
|
|
36
|
-
* to avoid property collisions across types.
|
|
37
|
-
*/
|
|
38
25
|
export interface SecurityResultBlock {
|
|
39
26
|
security_result: {
|
|
40
27
|
severity: string;
|
|
@@ -42,10 +29,8 @@ export interface SecurityResultBlock {
|
|
|
42
29
|
category: string;
|
|
43
30
|
};
|
|
44
31
|
}
|
|
45
|
-
/** Dot-notation path to a field in an event, plus the redaction strategy to apply */
|
|
46
32
|
export interface FieldRedaction {
|
|
47
33
|
path: string;
|
|
48
|
-
/** Strategy key — must match a registered RedactionStrategy in src/redactor/strategies/ */
|
|
49
34
|
strategy: string;
|
|
50
35
|
}
|
|
51
36
|
export interface ValidationResult {
|
|
@@ -53,13 +38,11 @@ export interface ValidationResult {
|
|
|
53
38
|
field?: string;
|
|
54
39
|
error?: string;
|
|
55
40
|
}
|
|
56
|
-
/** Raw tool call from the JSONL session file */
|
|
57
41
|
export interface RawToolCall {
|
|
58
42
|
name: string;
|
|
59
43
|
id?: string;
|
|
60
44
|
arguments: Record<string, any>;
|
|
61
45
|
}
|
|
62
|
-
/** Context passed to every enrich() function */
|
|
63
46
|
export interface EnrichmentContext {
|
|
64
47
|
sessionId: string;
|
|
65
48
|
agentId: string;
|
|
@@ -86,10 +69,8 @@ export interface SourceInfo {
|
|
|
86
69
|
transport: string;
|
|
87
70
|
};
|
|
88
71
|
}
|
|
89
|
-
/** Schema descriptor — one per event type */
|
|
90
72
|
export interface EventSchema<T extends BaseEvent = BaseEvent> {
|
|
91
73
|
category: string;
|
|
92
|
-
/** Pure, fast matcher. First match wins. GenericSchema must be last. */
|
|
93
74
|
match: (tool: RawToolCall) => boolean;
|
|
94
75
|
enrich: (tool: RawToolCall, context: EnrichmentContext) => T;
|
|
95
76
|
redactions: FieldRedaction[];
|
|
@@ -98,13 +79,7 @@ export interface EventSchema<T extends BaseEvent = BaseEvent> {
|
|
|
98
79
|
export declare const baseValidations: {
|
|
99
80
|
validate(event: BaseEvent): ValidationResult;
|
|
100
81
|
};
|
|
101
|
-
/** Applied to every event, regardless of type */
|
|
102
82
|
export declare const baseRedactions: FieldRedaction[];
|
|
103
|
-
/**
|
|
104
|
-
* Run base validations first, then type-specific validations.
|
|
105
|
-
* Returns the first failure encountered.
|
|
106
|
-
*/
|
|
107
83
|
export declare function validateEvent(event: BaseEvent, schema: EventSchema): ValidationResult;
|
|
108
|
-
/** Convert all values in a metadata object to strings (Chronicle CBN can't extract booleans/integers) */
|
|
109
84
|
export declare function stringifyMetadata(meta: Record<string, any>): Record<string, string | null>;
|
|
110
85
|
export declare function truncate(s: string, max?: number): string;
|
package/dist/src/events/base.js
CHANGED
|
@@ -1,16 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* base.ts — Core types, composable blocks, and generic engine for the Shield event model.
|
|
4
|
-
*
|
|
5
|
-
* All event types extend BaseEvent. The engine composes base rules with type-specific rules.
|
|
6
|
-
* Individual event types never redeclare base-level concerns.
|
|
7
|
-
*/
|
|
8
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
3
|
exports.baseRedactions = exports.baseValidations = void 0;
|
|
10
4
|
exports.validateEvent = validateEvent;
|
|
11
5
|
exports.stringifyMetadata = stringifyMetadata;
|
|
12
6
|
exports.truncate = truncate;
|
|
13
|
-
// ─── Base Validations ─────────────────────────────────────────────────────────
|
|
14
7
|
exports.baseValidations = {
|
|
15
8
|
validate(event) {
|
|
16
9
|
if (!event.timestamp)
|
|
@@ -26,24 +19,16 @@ exports.baseValidations = {
|
|
|
26
19
|
return { valid: true };
|
|
27
20
|
},
|
|
28
21
|
};
|
|
29
|
-
// ─── Base Redactions ──────────────────────────────────────────────────────────
|
|
30
|
-
/** Applied to every event, regardless of type */
|
|
31
22
|
exports.baseRedactions = [
|
|
32
23
|
{ path: 'principal.hostname', strategy: 'hostname' },
|
|
33
24
|
{ path: 'principal.user', strategy: 'username' },
|
|
34
25
|
];
|
|
35
|
-
// ─── Generic Engine ───────────────────────────────────────────────────────────
|
|
36
|
-
/**
|
|
37
|
-
* Run base validations first, then type-specific validations.
|
|
38
|
-
* Returns the first failure encountered.
|
|
39
|
-
*/
|
|
40
26
|
function validateEvent(event, schema) {
|
|
41
27
|
const baseResult = exports.baseValidations.validate(event);
|
|
42
28
|
if (!baseResult.valid)
|
|
43
29
|
return baseResult;
|
|
44
30
|
return schema.validate(event);
|
|
45
31
|
}
|
|
46
|
-
/** Convert all values in a metadata object to strings (Chronicle CBN can't extract booleans/integers) */
|
|
47
32
|
function stringifyMetadata(meta) {
|
|
48
33
|
const result = {};
|
|
49
34
|
for (const [k, v] of Object.entries(meta)) {
|
|
@@ -14,7 +14,6 @@ function enrich(tool, ctx) {
|
|
|
14
14
|
cmd_has_sudo: /\bsudo\b/.test(cmd),
|
|
15
15
|
cmd_has_pipe: /\|/.test(cmd),
|
|
16
16
|
};
|
|
17
|
-
// Process scope escape detection (kill/pkill/killall)
|
|
18
17
|
if (/^(kill|pkill|killall)$/.test(rootCmd)) {
|
|
19
18
|
const pidMatch = cmd.match(/\bkill\s+(?:-\d+\s+)?(\d+)/);
|
|
20
19
|
if (pidMatch) {
|
|
@@ -42,7 +41,6 @@ function enrich(tool, ctx) {
|
|
|
42
41
|
target: { command_line: (0, base_1.truncate)(cmd) },
|
|
43
42
|
tool_metadata: (0, base_1.stringifyMetadata)(meta),
|
|
44
43
|
};
|
|
45
|
-
// SSH / SCP / rsync detection
|
|
46
44
|
if (/^(ssh|scp|rsync)\b/.test(rootCmd)) {
|
|
47
45
|
const stripped = cmd.replace(/\s-[ipoFlJWbDeLRw]\s+\S+/g, ' ').replace(/\s-[^\s]+/g, ' ');
|
|
48
46
|
const parts = stripped.trim().split(/\s+/).slice(1);
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.redactions = void 0;
|
|
4
|
-
/** Exec-specific redaction rules. Base redactions (principal.hostname, principal.user) are applied automatically. */
|
|
5
4
|
exports.redactions = [
|
|
6
5
|
{ path: 'command', strategy: 'command' },
|
|
7
6
|
{ path: 'command', strategy: 'secret-key' },
|
|
@@ -9,9 +9,6 @@ function enrich(tool, ctx) {
|
|
|
9
9
|
const ext = (0, path_1.extname)(fp) || null;
|
|
10
10
|
const isSystem = /^\/(etc|usr|var|sys|proc)(\/|$)/.test(fp);
|
|
11
11
|
const configExts = ['.json', '.yaml', '.yml', '.toml', '.env', '.conf', '.cfg', '.ini'];
|
|
12
|
-
// Note: extname('.env') returns '' in Node (dotfiles treated as no extension).
|
|
13
|
-
// file_is_config uses extension-based detection only. Dotfile detection is a known
|
|
14
|
-
// limitation (issue #6) — tracked for a future dedicated dotfile enrichment rule.
|
|
15
12
|
const isMemoryFile = /\/(MEMORY\.md|memory\/.*\.md)$/.test(fp);
|
|
16
13
|
const toolName = tool.name;
|
|
17
14
|
const meta = {
|
|
@@ -4,7 +4,6 @@ exports.GenericSchema = void 0;
|
|
|
4
4
|
const enrich_1 = require("./enrich");
|
|
5
5
|
const redactions_1 = require("./redactions");
|
|
6
6
|
const validations_1 = require("./validations");
|
|
7
|
-
/** Fallback schema — always matches. MUST be last in the registry. */
|
|
8
7
|
exports.GenericSchema = {
|
|
9
8
|
category: 'generic',
|
|
10
9
|
match: (_tool) => true,
|
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* src/events/index.ts — Shield Event Registry
|
|
3
|
-
*
|
|
4
|
-
* Imports all schemas and builds the ordered lookup array.
|
|
5
|
-
* GenericSchema is always last — it matches everything and acts as the fallback.
|
|
6
|
-
* First match wins; schemas are evaluated in order.
|
|
7
|
-
*/
|
|
8
1
|
import { EventSchema } from './base';
|
|
9
2
|
export type { ExecEvent } from './exec';
|
|
10
3
|
export type { FileEvent } from './file';
|
|
@@ -30,11 +23,5 @@ import type { GatewayEvent } from './gateway';
|
|
|
30
23
|
import type { HostTelemetryEvent } from './host-telemetry';
|
|
31
24
|
import type { ToolResultEvent } from './tool-result';
|
|
32
25
|
import type { GenericEvent } from './generic';
|
|
33
|
-
/** Discriminated union of all Shield event types */
|
|
34
26
|
export type ShieldEvent = ExecEvent | FileEvent | WebEvent | BrowserEvent | MessageEvent | SessionsSpawnEvent | CronEvent | GatewayEvent | HostTelemetryEvent | ToolResultEvent | GenericEvent;
|
|
35
|
-
/**
|
|
36
|
-
* Ordered registry of all event schemas.
|
|
37
|
-
* GenericSchema MUST remain last.
|
|
38
|
-
* eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
39
|
-
*/
|
|
40
27
|
export declare const schemas: EventSchema<any>[];
|
package/dist/src/events/index.js
CHANGED
|
@@ -1,11 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* src/events/index.ts — Shield Event Registry
|
|
4
|
-
*
|
|
5
|
-
* Imports all schemas and builds the ordered lookup array.
|
|
6
|
-
* GenericSchema is always last — it matches everything and acts as the fallback.
|
|
7
|
-
* First match wins; schemas are evaluated in order.
|
|
8
|
-
*/
|
|
9
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
3
|
exports.schemas = exports.buildToolResult = void 0;
|
|
11
4
|
const exec_1 = require("./exec");
|
|
@@ -20,11 +13,6 @@ const host_telemetry_1 = require("./host-telemetry");
|
|
|
20
13
|
const generic_1 = require("./generic");
|
|
21
14
|
var tool_result_1 = require("./tool-result");
|
|
22
15
|
Object.defineProperty(exports, "buildToolResult", { enumerable: true, get: function () { return tool_result_1.buildToolResult; } });
|
|
23
|
-
/**
|
|
24
|
-
* Ordered registry of all event schemas.
|
|
25
|
-
* GenericSchema MUST remain last.
|
|
26
|
-
* eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
27
|
-
*/
|
|
28
16
|
exports.schemas = [
|
|
29
17
|
exec_1.ExecSchema,
|
|
30
18
|
file_1.FileSchema,
|
|
@@ -35,5 +23,5 @@ exports.schemas = [
|
|
|
35
23
|
cron_1.CronSchema,
|
|
36
24
|
gateway_1.GatewaySchema,
|
|
37
25
|
host_telemetry_1.HostTelemetrySchema,
|
|
38
|
-
generic_1.GenericSchema,
|
|
26
|
+
generic_1.GenericSchema,
|
|
39
27
|
];
|
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.validate = validate;
|
|
4
|
-
// MessageEvent has no required type-specific fields beyond BaseEvent.
|
|
5
|
-
// Base validations (timestamp, session_id, tool_name, principal.hostname) run
|
|
6
|
-
// automatically before this function — no additional checks needed here.
|
|
7
4
|
function validate(_event) { return { valid: true }; }
|
|
@@ -33,7 +33,6 @@ function enrich(tool, ctx) {
|
|
|
33
33
|
user: ctx.agentId,
|
|
34
34
|
},
|
|
35
35
|
arguments_summary: (0, base_1.truncate)(task),
|
|
36
|
-
// target.command_line required by parser for PROCESS_LAUNCH mapping
|
|
37
36
|
target: { command_line: (0, base_1.truncate)(task) },
|
|
38
37
|
tool_metadata: (0, base_1.stringifyMetadata)(meta),
|
|
39
38
|
};
|
|
@@ -2,7 +2,6 @@ import { BaseEvent } from '../base';
|
|
|
2
2
|
export interface SessionsSpawnEvent extends BaseEvent {
|
|
3
3
|
tool_category: 'sessions_spawn';
|
|
4
4
|
arguments_summary?: string;
|
|
5
|
-
/** target.command_line = task description — required by parser for PROCESS_LAUNCH mapping */
|
|
6
5
|
target?: {
|
|
7
6
|
command_line?: string;
|
|
8
7
|
};
|
|
@@ -15,7 +15,6 @@ function buildToolResult(raw, ctx) {
|
|
|
15
15
|
result_size_bytes: String(resultText.length),
|
|
16
16
|
result_is_large: resultText.length > 50000,
|
|
17
17
|
};
|
|
18
|
-
// ANSI injection detection
|
|
19
18
|
const ansiMatches = resultText.match(/\x1b\[[0-9;]*[a-zA-Z]|\x1b\]|\x07|\x1b\(B/g);
|
|
20
19
|
if (ansiMatches && ansiMatches.length > 0) {
|
|
21
20
|
meta['ansi_content_detected'] = 'true';
|
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
import { RawToolCall, EnrichmentContext } from '../base';
|
|
2
2
|
import { WebEvent } from './event';
|
|
3
|
-
/**
|
|
4
|
-
* Returns true for loopback, RFC 1918, link-local, and cloud metadata endpoints.
|
|
5
|
-
* 169.254.169.254 is the AWS/GCP/Azure instance metadata endpoint — a critical IoC.
|
|
6
|
-
*/
|
|
7
3
|
export declare function isInternalUrl(u: URL): boolean;
|
|
8
4
|
export declare function enrich(tool: RawToolCall, ctx: EnrichmentContext): WebEvent;
|
|
@@ -3,32 +3,25 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.isInternalUrl = isInternalUrl;
|
|
4
4
|
exports.enrich = enrich;
|
|
5
5
|
const base_1 = require("../base");
|
|
6
|
-
/**
|
|
7
|
-
* Returns true for loopback, RFC 1918, link-local, and cloud metadata endpoints.
|
|
8
|
-
* 169.254.169.254 is the AWS/GCP/Azure instance metadata endpoint — a critical IoC.
|
|
9
|
-
*/
|
|
10
6
|
function isInternalUrl(u) {
|
|
11
|
-
// Node.js URL parser wraps IPv6 in brackets: [::1] — strip them for comparison
|
|
12
7
|
const h = u.hostname;
|
|
13
8
|
const bare = h.startsWith('[') && h.endsWith(']') ? h.slice(1, -1) : h;
|
|
14
9
|
if (bare === 'localhost' || bare === '127.0.0.1' || bare === '::1')
|
|
15
10
|
return true;
|
|
16
11
|
if (/^169\.254\./.test(bare))
|
|
17
|
-
return true;
|
|
12
|
+
return true;
|
|
18
13
|
if (/^10\./.test(bare))
|
|
19
|
-
return true;
|
|
14
|
+
return true;
|
|
20
15
|
if (/^192\.168\./.test(bare))
|
|
21
|
-
return true;
|
|
16
|
+
return true;
|
|
22
17
|
if (/^172\.(1[6-9]|2\d|3[01])\./.test(bare))
|
|
23
|
-
return true;
|
|
18
|
+
return true;
|
|
24
19
|
if (/\.(local|internal|localhost)$/.test(bare))
|
|
25
|
-
return true;
|
|
20
|
+
return true;
|
|
26
21
|
return false;
|
|
27
22
|
}
|
|
28
23
|
function enrich(tool, ctx) {
|
|
29
24
|
const args = tool.arguments;
|
|
30
|
-
// web_search args have `query` but no `url` — synthesise a canonical search URL
|
|
31
|
-
// so the parser gets a valid target hostname for NETWORK_HTTP mapping
|
|
32
25
|
const rawUrl = args.url || args.targetUrl || '';
|
|
33
26
|
const url = rawUrl || (tool.name === 'web_search' && args.query
|
|
34
27
|
? `https://search.brave.com/search?q=${encodeURIComponent(String(args.query).slice(0, 200))}`
|
|
@@ -61,7 +54,6 @@ function enrich(tool, ctx) {
|
|
|
61
54
|
const u = new URL(url);
|
|
62
55
|
event.target.hostname = u.hostname;
|
|
63
56
|
event.target.url_domain = u.hostname;
|
|
64
|
-
// Reflect actual protocol (HTTP vs HTTPS) in the network block
|
|
65
57
|
if (event.network) {
|
|
66
58
|
event.network.protocol = u.protocol === 'http:' ? 'HTTP' : 'HTTPS';
|
|
67
59
|
}
|
|
@@ -73,6 +65,6 @@ function enrich(tool, ctx) {
|
|
|
73
65
|
url_is_internal: isInternalUrl(u),
|
|
74
66
|
});
|
|
75
67
|
}
|
|
76
|
-
catch {
|
|
68
|
+
catch { }
|
|
77
69
|
return event;
|
|
78
70
|
}
|
package/dist/src/fetcher.d.ts
CHANGED
|
@@ -8,5 +8,6 @@ export interface RawEntry {
|
|
|
8
8
|
_sessionId: string;
|
|
9
9
|
_agentId: string;
|
|
10
10
|
}
|
|
11
|
+
export declare const MAX_ENTRIES_PER_POLL = 5000;
|
|
11
12
|
export declare function fetchNewEntries(config: Config): Promise<RawEntry[]>;
|
|
12
13
|
export declare function commitCursors(config: Config, _entries: RawEntry[]): void;
|