securenow 8.8.0 → 8.10.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/NPM_README.md +30 -0
- package/README.md +14 -0
- package/SKILL-API.md +23 -0
- package/SKILL-CLI.md +21 -3
- package/TELEMETRY-SQL.md +98 -0
- package/cli/security.js +170 -0
- package/cli/telemetry.js +199 -0
- package/cli.js +45 -5
- package/mcp/catalog.js +2233 -2187
- package/package.json +36 -28
- package/telemetry-schema.d.ts +16 -0
- package/telemetry-schema.js +3 -0
- package/telemetry-schema.json +188 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "securenow",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.10.0",
|
|
4
4
|
"description": "OpenTelemetry instrumentation for Node.js, Next.js, and Nuxt - Send traces and logs to any OTLP-compatible backend",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "register.js",
|
|
@@ -50,10 +50,14 @@
|
|
|
50
50
|
"types": "./tracing.d.ts",
|
|
51
51
|
"default": "./tracing.js"
|
|
52
52
|
},
|
|
53
|
-
"./events": {
|
|
54
|
-
"types": "./events.d.ts",
|
|
55
|
-
"default": "./events.js"
|
|
56
|
-
},
|
|
53
|
+
"./events": {
|
|
54
|
+
"types": "./events.d.ts",
|
|
55
|
+
"default": "./events.js"
|
|
56
|
+
},
|
|
57
|
+
"./telemetry-schema": {
|
|
58
|
+
"types": "./telemetry-schema.d.ts",
|
|
59
|
+
"default": "./telemetry-schema.js"
|
|
60
|
+
},
|
|
57
61
|
"./sessions": {
|
|
58
62
|
"types": "./sessions.d.ts",
|
|
59
63
|
"default": "./sessions.js"
|
|
@@ -123,8 +127,11 @@
|
|
|
123
127
|
"register.d.ts",
|
|
124
128
|
"tracing.js",
|
|
125
129
|
"tracing.d.ts",
|
|
126
|
-
"events.js",
|
|
127
|
-
"events.d.ts",
|
|
130
|
+
"events.js",
|
|
131
|
+
"events.d.ts",
|
|
132
|
+
"telemetry-schema.js",
|
|
133
|
+
"telemetry-schema.d.ts",
|
|
134
|
+
"telemetry-schema.json",
|
|
128
135
|
"sessions.js",
|
|
129
136
|
"sessions.d.ts",
|
|
130
137
|
"console-instrumentation.js",
|
|
@@ -159,34 +166,35 @@
|
|
|
159
166
|
"web-vite.mjs",
|
|
160
167
|
"app-config.js",
|
|
161
168
|
"README.md",
|
|
162
|
-
"NPM_README.md",
|
|
169
|
+
"NPM_README.md",
|
|
170
|
+
"TELEMETRY-SQL.md",
|
|
163
171
|
"SKILL-CLI.md",
|
|
164
172
|
"SKILL-API.md"
|
|
165
173
|
],
|
|
166
174
|
"dependencies": {
|
|
167
175
|
"@opentelemetry/api": ">=1.9.0 <1.10.0",
|
|
168
|
-
"@opentelemetry/api-logs": "0.
|
|
169
|
-
"@opentelemetry/auto-instrumentations-node": "0.
|
|
170
|
-
"@opentelemetry/core": "2.
|
|
171
|
-
"@opentelemetry/exporter-logs-otlp-http": "0.
|
|
172
|
-
"@opentelemetry/exporter-trace-otlp-http": "0.
|
|
173
|
-
"@opentelemetry/instrumentation": "0.
|
|
174
|
-
"@opentelemetry/instrumentation-document-load": "0.
|
|
175
|
-
"@opentelemetry/instrumentation-fetch": "0.
|
|
176
|
-
"@opentelemetry/instrumentation-http": "0.
|
|
177
|
-
"@opentelemetry/instrumentation-mongodb": "0.
|
|
178
|
-
"@opentelemetry/instrumentation-user-interaction": "0.
|
|
179
|
-
"@opentelemetry/instrumentation-xml-http-request": "0.
|
|
180
|
-
"@opentelemetry/resources": "2.
|
|
181
|
-
"@opentelemetry/sdk-logs": "0.
|
|
182
|
-
"@opentelemetry/sdk-metrics": "2.
|
|
183
|
-
"@opentelemetry/sdk-node": "0.
|
|
184
|
-
"@opentelemetry/sdk-trace-base": "2.
|
|
185
|
-
"@opentelemetry/sdk-trace-web": "2.
|
|
186
|
-
"@opentelemetry/semantic-conventions": "1.
|
|
176
|
+
"@opentelemetry/api-logs": "0.220.0",
|
|
177
|
+
"@opentelemetry/auto-instrumentations-node": "0.78.0",
|
|
178
|
+
"@opentelemetry/core": "2.9.0",
|
|
179
|
+
"@opentelemetry/exporter-logs-otlp-http": "0.220.0",
|
|
180
|
+
"@opentelemetry/exporter-trace-otlp-http": "0.220.0",
|
|
181
|
+
"@opentelemetry/instrumentation": "0.220.0",
|
|
182
|
+
"@opentelemetry/instrumentation-document-load": "0.65.0",
|
|
183
|
+
"@opentelemetry/instrumentation-fetch": "0.220.0",
|
|
184
|
+
"@opentelemetry/instrumentation-http": "0.220.0",
|
|
185
|
+
"@opentelemetry/instrumentation-mongodb": "0.73.0",
|
|
186
|
+
"@opentelemetry/instrumentation-user-interaction": "0.64.0",
|
|
187
|
+
"@opentelemetry/instrumentation-xml-http-request": "0.220.0",
|
|
188
|
+
"@opentelemetry/resources": "2.9.0",
|
|
189
|
+
"@opentelemetry/sdk-logs": "0.220.0",
|
|
190
|
+
"@opentelemetry/sdk-metrics": "2.9.0",
|
|
191
|
+
"@opentelemetry/sdk-node": "0.220.0",
|
|
192
|
+
"@opentelemetry/sdk-trace-base": "2.9.0",
|
|
193
|
+
"@opentelemetry/sdk-trace-web": "2.9.0",
|
|
194
|
+
"@opentelemetry/semantic-conventions": "1.43.0"
|
|
187
195
|
},
|
|
188
196
|
"optionalDependencies": {
|
|
189
|
-
"@vercel/otel": "2.1.
|
|
197
|
+
"@vercel/otel": "2.1.3"
|
|
190
198
|
},
|
|
191
199
|
"sideEffects": true,
|
|
192
200
|
"license": "ISC"
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface SecureNowTelemetrySchema {
|
|
2
|
+
contract: string;
|
|
3
|
+
schemaVersion: string;
|
|
4
|
+
dialect: 'ClickHouse';
|
|
5
|
+
purpose: string;
|
|
6
|
+
ruleContract: Record<string, unknown>;
|
|
7
|
+
tables: Record<string, unknown>;
|
|
8
|
+
clientIp: Record<string, unknown>;
|
|
9
|
+
customEvents: Record<string, unknown>;
|
|
10
|
+
automaticTraceFields: Record<string, string[]>;
|
|
11
|
+
templates: Record<string, string>;
|
|
12
|
+
authoringWorkflow: string[];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
declare const schema: SecureNowTelemetrySchema;
|
|
16
|
+
export = schema;
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
{
|
|
2
|
+
"contract": "securenow.telemetry.alert-sql",
|
|
3
|
+
"schemaVersion": "1.0.0",
|
|
4
|
+
"dialect": "ClickHouse",
|
|
5
|
+
"purpose": "Canonical local contract for agents and humans authoring SecureNow alert rules.",
|
|
6
|
+
"ruleContract": {
|
|
7
|
+
"tenantPlaceholder": "__USER_APP_KEYS__",
|
|
8
|
+
"requiredResultColumns": [
|
|
9
|
+
{
|
|
10
|
+
"name": "ip",
|
|
11
|
+
"type": "String",
|
|
12
|
+
"reason": "Per-IP grouping and IP-based remediation use this column. Keep empty IPs out of the final result."
|
|
13
|
+
}
|
|
14
|
+
],
|
|
15
|
+
"requirements": [
|
|
16
|
+
"Query only documented telemetry tables and fields.",
|
|
17
|
+
"Keep __USER_APP_KEYS__ in every customer-scoped query.",
|
|
18
|
+
"Use the tenant expression documented for the selected table.",
|
|
19
|
+
"Return an ip column and exclude empty IP values for IP-remediation rules.",
|
|
20
|
+
"Bound every query with a time window.",
|
|
21
|
+
"Validate candidate SQL before creating or updating a rule.",
|
|
22
|
+
"Treat fields absent from live field discovery as unverified until instrumentation emits them."
|
|
23
|
+
]
|
|
24
|
+
},
|
|
25
|
+
"tables": {
|
|
26
|
+
"logs": {
|
|
27
|
+
"name": "signoz_logs.distributed_logs_v2",
|
|
28
|
+
"purpose": "OpenTelemetry logs and SecureNow custom security events.",
|
|
29
|
+
"timestamp": {
|
|
30
|
+
"column": "timestamp",
|
|
31
|
+
"type": "UInt64",
|
|
32
|
+
"unit": "nanoseconds",
|
|
33
|
+
"timeFilterExample": "timestamp >= toUnixTimestamp64Nano(now64() - INTERVAL 15 MINUTE)"
|
|
34
|
+
},
|
|
35
|
+
"tenantExpression": "resources_string['service.name'] IN (__USER_APP_KEYS__)",
|
|
36
|
+
"columns": {
|
|
37
|
+
"timestamp": "UInt64 nanoseconds",
|
|
38
|
+
"observed_timestamp": "UInt64 nanoseconds",
|
|
39
|
+
"id": "String",
|
|
40
|
+
"trace_id": "String",
|
|
41
|
+
"span_id": "String",
|
|
42
|
+
"severity_text": "LowCardinality(String)",
|
|
43
|
+
"severity_number": "UInt8",
|
|
44
|
+
"body": "String",
|
|
45
|
+
"attributes_string": "Map(String, String)",
|
|
46
|
+
"attributes_number": "Map(String, Float64)",
|
|
47
|
+
"attributes_bool": "Map(String, Bool)",
|
|
48
|
+
"resources_string": "Map(String, String)",
|
|
49
|
+
"scope_name": "String",
|
|
50
|
+
"scope_version": "String"
|
|
51
|
+
},
|
|
52
|
+
"mapAccess": {
|
|
53
|
+
"string": "attributes_string['field.name']",
|
|
54
|
+
"number": "attributes_number['field.name']",
|
|
55
|
+
"boolean": "attributes_bool['field.name']",
|
|
56
|
+
"resource": "resources_string['field.name']"
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
"traces": {
|
|
60
|
+
"name": "signoz_traces.distributed_signoz_index_v3",
|
|
61
|
+
"purpose": "OpenTelemetry spans including automatically captured HTTP request telemetry.",
|
|
62
|
+
"timestamp": {
|
|
63
|
+
"column": "timestamp",
|
|
64
|
+
"type": "DateTime64(9)",
|
|
65
|
+
"unit": "nanoseconds precision",
|
|
66
|
+
"timeFilterExample": "timestamp >= now64(9) - INTERVAL 15 MINUTE"
|
|
67
|
+
},
|
|
68
|
+
"tenantExpression": "`resource_string_service$$name` IN (__USER_APP_KEYS__)",
|
|
69
|
+
"columns": {
|
|
70
|
+
"timestamp": "DateTime64(9)",
|
|
71
|
+
"trace_id": "FixedString(32)",
|
|
72
|
+
"span_id": "String",
|
|
73
|
+
"parent_span_id": "String",
|
|
74
|
+
"name": "LowCardinality(String)",
|
|
75
|
+
"kind": "Int8 (1 internal, 2 server, 3 client, 4 producer, 5 consumer)",
|
|
76
|
+
"duration_nano": "UInt64",
|
|
77
|
+
"status_code": "Int16",
|
|
78
|
+
"status_message": "String",
|
|
79
|
+
"attributes_string": "Map(String, String)",
|
|
80
|
+
"attributes_number": "Map(String, Float64)",
|
|
81
|
+
"attributes_bool": "Map(String, Bool)",
|
|
82
|
+
"resources_string": "Map(String, String)",
|
|
83
|
+
"response_status_code": "LowCardinality(String)",
|
|
84
|
+
"http_url": "LowCardinality(String)",
|
|
85
|
+
"http_method": "LowCardinality(String)",
|
|
86
|
+
"http_host": "LowCardinality(String)",
|
|
87
|
+
"has_error": "Bool",
|
|
88
|
+
"resource_string_service$$name": "LowCardinality(String)",
|
|
89
|
+
"attribute_string_http$$route": "LowCardinality(String)"
|
|
90
|
+
},
|
|
91
|
+
"mapAccess": {
|
|
92
|
+
"string": "attributes_string['field.name']",
|
|
93
|
+
"number": "attributes_number['field.name']",
|
|
94
|
+
"boolean": "attributes_bool['field.name']",
|
|
95
|
+
"resource": "resources_string['field.name']"
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
"clientIp": {
|
|
100
|
+
"preferredField": "http.client_ip",
|
|
101
|
+
"traceExpression": "coalesce(nullIf(attributes_string['http.client_ip'], ''), nullIf(attributes_string['net.peer.ip'], ''), nullIf(attributes_string['network.peer.address'], ''), nullIf(attributes_string['client.address'], ''), nullIf(attributes_string['net.sock.peer.addr'], ''))",
|
|
102
|
+
"eventExpression": "attributes_string['http.client_ip']",
|
|
103
|
+
"trustNote": "Confirm trusted-proxy configuration before using forwarded IPs for blocking."
|
|
104
|
+
},
|
|
105
|
+
"customEvents": {
|
|
106
|
+
"sdkImport": "securenow/events",
|
|
107
|
+
"signature": "track(type: string, props?: TrackProps): void",
|
|
108
|
+
"storageTable": "logs",
|
|
109
|
+
"propertyMapping": {
|
|
110
|
+
"type": "attributes_string['event.type']",
|
|
111
|
+
"userId": "attributes_string['enduser.id']",
|
|
112
|
+
"sessionId": "attributes_string['session.id']",
|
|
113
|
+
"ip": "attributes_string['http.client_ip']",
|
|
114
|
+
"userAgent": "attributes_string['http.user_agent']",
|
|
115
|
+
"severity": "severity_text",
|
|
116
|
+
"attributes.string": "attributes_string['<custom-key>']",
|
|
117
|
+
"attributes.number": "attributes_number['<custom-key>']",
|
|
118
|
+
"attributes.boolean": "attributes_bool['<custom-key>']"
|
|
119
|
+
},
|
|
120
|
+
"recommendedAuthenticationEvents": [
|
|
121
|
+
"auth.login.failure",
|
|
122
|
+
"auth.login.success",
|
|
123
|
+
"auth.otp.send.requested",
|
|
124
|
+
"auth.otp.send.result",
|
|
125
|
+
"auth.otp.verify.failure",
|
|
126
|
+
"auth.otp.verify.success",
|
|
127
|
+
"auth.password_reset.requested",
|
|
128
|
+
"auth.password_reset.completed",
|
|
129
|
+
"auth.mfa.challenge.failure",
|
|
130
|
+
"auth.mfa.challenge.success",
|
|
131
|
+
"auth.session.revoked"
|
|
132
|
+
]
|
|
133
|
+
},
|
|
134
|
+
"automaticTraceFields": {
|
|
135
|
+
"http": [
|
|
136
|
+
"http.method",
|
|
137
|
+
"http.route",
|
|
138
|
+
"http.target",
|
|
139
|
+
"http.url",
|
|
140
|
+
"http.status_code",
|
|
141
|
+
"http.host",
|
|
142
|
+
"http.scheme",
|
|
143
|
+
"http.user_agent"
|
|
144
|
+
],
|
|
145
|
+
"clientAndProxy": [
|
|
146
|
+
"http.client_ip",
|
|
147
|
+
"http.client_ip.source",
|
|
148
|
+
"http.socket_ip",
|
|
149
|
+
"http.forwarded_for",
|
|
150
|
+
"http.real_ip",
|
|
151
|
+
"http.cf.connecting_ip",
|
|
152
|
+
"http.proxy.trusted"
|
|
153
|
+
],
|
|
154
|
+
"securityPresenceOnly": [
|
|
155
|
+
"http.security.auth_present",
|
|
156
|
+
"http.security.cookies_present",
|
|
157
|
+
"http.security.csrf_token_present"
|
|
158
|
+
],
|
|
159
|
+
"optionalBodyCapture": [
|
|
160
|
+
"http.request.body",
|
|
161
|
+
"http.request.body.type",
|
|
162
|
+
"http.request.body.size",
|
|
163
|
+
"http.request.body.parse_error"
|
|
164
|
+
],
|
|
165
|
+
"resources": [
|
|
166
|
+
"service.name",
|
|
167
|
+
"service.instance.id",
|
|
168
|
+
"service.version",
|
|
169
|
+
"deployment.environment",
|
|
170
|
+
"telemetry.sdk.name",
|
|
171
|
+
"telemetry.sdk.language",
|
|
172
|
+
"telemetry.sdk.version"
|
|
173
|
+
]
|
|
174
|
+
},
|
|
175
|
+
"templates": {
|
|
176
|
+
"traceBurstByIp": "WITH coalesce(nullIf(attributes_string['http.client_ip'], ''), nullIf(attributes_string['net.peer.ip'], ''), nullIf(attributes_string['network.peer.address'], ''), nullIf(attributes_string['client.address'], ''), nullIf(attributes_string['net.sock.peer.addr'], '')) AS client_ip\nSELECT client_ip AS ip, count() AS hits\nFROM signoz_traces.distributed_signoz_index_v3\nWHERE `resource_string_service$$name` IN (__USER_APP_KEYS__)\n AND timestamp >= now64(9) - INTERVAL 15 MINUTE\n AND attributes_string['http.target'] = '/replace-with-real-route'\nGROUP BY ip\nHAVING ip != '' AND hits >= 20",
|
|
177
|
+
"eventFailuresByIp": "SELECT attributes_string['http.client_ip'] AS ip, count() AS failures\nFROM signoz_logs.distributed_logs_v2\nWHERE resources_string['service.name'] IN (__USER_APP_KEYS__)\n AND timestamp >= toUnixTimestamp64Nano(now64() - INTERVAL 15 MINUTE)\n AND attributes_string['event.type'] = 'replace.with.verified.event'\nGROUP BY ip\nHAVING ip != '' AND failures >= 10"
|
|
178
|
+
},
|
|
179
|
+
"authoringWorkflow": [
|
|
180
|
+
"npx securenow telemetry schema --json",
|
|
181
|
+
"npx securenow telemetry fields --app <key> --env production --since 24h --json",
|
|
182
|
+
"npx securenow alerts rules --json",
|
|
183
|
+
"npx securenow alerts rules validate --sql @rule.sql --app <key>",
|
|
184
|
+
"npx securenow alerts rules create --name <name> --sql @rule.sql --apps <key>",
|
|
185
|
+
"npx securenow alerts rules test <rule-id> --mode dry_run --wait",
|
|
186
|
+
"npx securenow alerts rules promote <rule-id>"
|
|
187
|
+
]
|
|
188
|
+
}
|