autotel-audit 0.2.0 → 0.3.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/dist/index.d.cts CHANGED
@@ -1,15 +1,27 @@
1
- import { RequestLogger } from 'autotel';
2
- import { SecuritySeverity } from 'autotel/security-schema';
3
- export { SecuritySeverity } from 'autotel/security-schema';
1
+ import { RequestLogger } from "autotel";
2
+ import { SecuritySeverity } from "autotel/security-schema";
4
3
 
4
+ //#region src/context.d.ts
5
5
  interface AuditContext {
6
- traceId: string;
7
- spanId: string;
8
- correlationId: string;
9
- setAttribute(key: string, value: string | number | boolean): void;
10
- setAttributes(attrs: Record<string, string | number | boolean | string[] | number[] | boolean[]>): void;
6
+ traceId: string;
7
+ spanId: string;
8
+ correlationId: string;
9
+ setAttribute(key: string, value: string | number | boolean): void;
10
+ setAttributes(attrs: Record<string, string | number | boolean | string[] | number[] | boolean[]>): void;
11
11
  }
12
-
12
+ /**
13
+ * How instrumentation should behave when no trace context is available.
14
+ *
15
+ * - `throw` — fail fast (original behaviour). Use when telemetry is mandatory.
16
+ * - `warn` — run the wrapped handler un-audited and log one warning per action (default).
17
+ * - `skip` — run the wrapped handler un-audited, silently.
18
+ *
19
+ * Telemetry is observability: a missing context should never crash the business
20
+ * logic it wraps, so the default is best-effort (`warn`).
21
+ */
22
+ type OnMissingContext = 'throw' | 'warn' | 'skip';
23
+ //#endregion
24
+ //#region src/security.d.ts
13
25
  /**
14
26
  * Security event categories, aligned with OWASP A09:2025
15
27
  * (Security Logging & Alerting Failures) and ASVS V7.
@@ -22,40 +34,46 @@ type SecurityOutcome = 'success' | 'failure' | 'denied' | 'blocked' | 'error';
22
34
  */
23
35
  type SuggestedSecurityEventName = 'auth.login.success' | 'auth.login.failed' | 'auth.mfa.failed' | 'auth.session.revoked' | 'auth.password.reset' | 'auth.account.locked' | 'access.denied' | 'access.role.changed' | 'access.permission.changed' | 'access.tenant.violation' | 'admin.action' | 'config.changed' | 'secret.accessed' | 'secret.rotation.failed' | 'api_key.created' | 'api_key.revoked' | 'rate_limit.exceeded' | 'validation.failed' | 'webhook.signature.failed' | 'dependency.scan.failed' | 'llm.prompt_injection.detected' | 'llm.tool_call.denied' | 'llm.output.blocked';
24
36
  interface SecurityEventMetadata {
25
- /** Stable, dot-separated event name, e.g. `auth.login.failed`. */
26
- name: SuggestedSecurityEventName | (string & {});
27
- category: SecurityEventCategory;
28
- outcome: SecurityOutcome;
29
- /** Defaults to `info`. */
30
- severity?: SecuritySeverity;
31
- /** Stable identifier of the actor — an id or a `hashIdentifier()` digest, never raw PII. */
32
- actorId?: string;
33
- targetType?: string;
34
- targetId?: string;
35
- tenantId?: string;
36
- /** Short machine-readable reason, e.g. `invalid_password`. */
37
- reason?: string;
38
- [key: string]: unknown;
37
+ /** Stable, dot-separated event name, e.g. `auth.login.failed`. */
38
+ name: SuggestedSecurityEventName | (string & {});
39
+ category: SecurityEventCategory;
40
+ outcome: SecurityOutcome;
41
+ /** Defaults to `info`. */
42
+ severity?: SecuritySeverity;
43
+ /** Stable identifier of the actor — an id or a `hashIdentifier()` digest, never raw PII. */
44
+ actorId?: string;
45
+ targetType?: string;
46
+ targetId?: string;
47
+ tenantId?: string;
48
+ /** Short machine-readable reason, e.g. `invalid_password`. */
49
+ reason?: string;
50
+ [key: string]: unknown;
39
51
  }
40
52
  interface SecurityEventOptions {
41
- ctx?: AuditContext;
42
- /**
43
- * Security events are exempt from tail sampling by default —
44
- * an attack you sampled away is an attack you cannot investigate.
45
- * Pass `false` to opt out (e.g. very high-volume info events).
46
- */
47
- forceKeep?: boolean;
48
- emitNow?: boolean;
49
- logger?: RequestLogger;
50
- /**
51
- * Also increment the `autotel.security.events` counter
52
- * (attributes: event, category, outcome, severity) so security teams
53
- * can alert on rates without log-based alerting. Default true.
54
- *
55
- * Cardinality note: the event name is a counter attribute — keep names
56
- * to a stable catalogue, never interpolate user input into them.
57
- */
58
- metrics?: boolean;
53
+ ctx?: AuditContext;
54
+ /**
55
+ * Security events are exempt from tail sampling by default —
56
+ * an attack you sampled away is an attack you cannot investigate.
57
+ * Pass `false` to opt out (e.g. very high-volume info events).
58
+ */
59
+ forceKeep?: boolean;
60
+ emitNow?: boolean;
61
+ logger?: RequestLogger;
62
+ /**
63
+ * Also increment the `autotel.security.events` counter
64
+ * (attributes: event, category, outcome, severity) so security teams
65
+ * can alert on rates without log-based alerting. Default true.
66
+ *
67
+ * Cardinality note: the event name is a counter attribute — keep names
68
+ * to a stable catalogue, never interpolate user input into them.
69
+ */
70
+ metrics?: boolean;
71
+ /**
72
+ * Behaviour when no trace context can be resolved. Defaults to `warn`
73
+ * (best-effort: record nothing, warn once). A dropped security event is still
74
+ * better than a crashed request — but the warning makes the gap visible.
75
+ */
76
+ onMissingContext?: OnMissingContext;
59
77
  }
60
78
  type WithSecurityOptions = SecurityEventOptions;
61
79
  /**
@@ -93,10 +111,10 @@ declare function securityEvent(metadata: SecurityEventMetadata, options?: Securi
93
111
  */
94
112
  declare function withSecurity<T>(metadata: SecurityEventMetadata, fn: (ctx: AuditContext, logger: RequestLogger) => T | Promise<T>, options?: WithSecurityOptions): Promise<T>;
95
113
  interface HashIdentifierOptions {
96
- /** Optional salt; use one stable per-deployment salt to defeat rainbow lookups. */
97
- salt?: string;
98
- /** Digest length in hex chars (default 16). */
99
- length?: number;
114
+ /** Optional salt; use one stable per-deployment salt to defeat rainbow lookups. */
115
+ salt?: string;
116
+ /** Digest length in hex chars (default 16). */
117
+ length?: number;
100
118
  }
101
119
  /**
102
120
  * Stable one-way digest for correlating PII-bearing identifiers
@@ -105,7 +123,8 @@ interface HashIdentifierOptions {
105
123
  * NOT for secrets — never log secrets in any form, hashed or not.
106
124
  */
107
125
  declare function hashIdentifier(value: string, options?: HashIdentifierOptions): string;
108
-
126
+ //#endregion
127
+ //#region src/security-signals.d.ts
109
128
  /**
110
129
  * Zero-code security signal derivation from spans you already have.
111
130
  *
@@ -132,112 +151,110 @@ declare function hashIdentifier(value: string, options?: HashIdentifierOptions):
132
151
  */
133
152
  type AttributeValue = string | number | boolean | Array<null | undefined | string> | Array<null | undefined | number> | Array<null | undefined | boolean>;
134
153
  interface MutableSpanLike {
135
- attributes: Record<string, AttributeValue | undefined>;
136
- setAttribute(key: string, value: AttributeValue): unknown;
154
+ attributes: Record<string, AttributeValue | undefined>;
155
+ setAttribute(key: string, value: AttributeValue): unknown;
137
156
  }
138
157
  interface ReadableSpanLike {
139
- attributes: Record<string, AttributeValue | undefined>;
158
+ attributes: Record<string, AttributeValue | undefined>;
140
159
  }
141
160
  interface SecuritySignalProcessor {
142
- onStart(span: MutableSpanLike, parentContext?: unknown): void;
143
- onEnd(span: ReadableSpanLike): void;
144
- shutdown(): Promise<void>;
145
- forceFlush(): Promise<void>;
161
+ onStart(span: MutableSpanLike, parentContext?: unknown): void;
162
+ onEnd(span: ReadableSpanLike): void;
163
+ shutdown(): Promise<void>;
164
+ forceFlush(): Promise<void>;
146
165
  }
147
166
  interface SuspiciousRequestSignal {
148
- signal: 'suspicious_request';
149
- /** Which pattern matched, e.g. `path_traversal`. */
150
- pattern: string;
151
- /** The matched request path/URL (as found on the span). */
152
- target: string;
167
+ signal: 'suspicious_request';
168
+ /** Which pattern matched, e.g. `path_traversal`. */
169
+ pattern: string;
170
+ /** The matched request path/URL (as found on the span). */
171
+ target: string;
153
172
  }
154
173
  interface AuthFailureBurstSignal {
155
- signal: 'auth_failure_burst';
156
- /** Value of the configured key attribute (e.g. client address). */
157
- key: string;
158
- /** Denied responses observed inside the window. */
159
- count: number;
160
- windowMs: number;
161
- status: number;
174
+ signal: 'auth_failure_burst';
175
+ /** Value of the configured key attribute (e.g. client address). */
176
+ key: string;
177
+ /** Denied responses observed inside the window. */
178
+ count: number;
179
+ windowMs: number;
180
+ status: number;
162
181
  }
163
182
  interface LlmExcessiveTokensSignal {
164
- signal: 'llm_excessive_tokens';
165
- /** Total tokens consumed by the single LLM call. */
166
- tokens: number;
167
- maxTokens: number;
168
- model?: string;
183
+ signal: 'llm_excessive_tokens';
184
+ /** Total tokens consumed by the single LLM call. */
185
+ tokens: number;
186
+ maxTokens: number;
187
+ model?: string;
169
188
  }
170
189
  interface LlmTokenBudgetSignal {
171
- signal: 'llm_token_budget_exceeded';
172
- /** Value of the configured key attribute (e.g. end-user id). */
173
- key: string;
174
- /** Tokens consumed inside the window. */
175
- tokens: number;
176
- budget: number;
177
- windowMs: number;
190
+ signal: 'llm_token_budget_exceeded';
191
+ /** Value of the configured key attribute (e.g. end-user id). */
192
+ key: string;
193
+ /** Tokens consumed inside the window. */
194
+ tokens: number;
195
+ budget: number;
196
+ windowMs: number;
178
197
  }
179
198
  type SecuritySignal = SuspiciousRequestSignal | AuthFailureBurstSignal | LlmExcessiveTokensSignal | LlmTokenBudgetSignal;
180
199
  interface BurstOptions {
181
- /** HTTP statuses counted toward a burst. Default `[401, 403]`. */
182
- statuses?: number[];
183
- /** Denied responses within the window that trigger a signal. Default 10. */
184
- threshold?: number;
185
- /** Sliding window size in milliseconds. Default 60_000. */
186
- windowMs?: number;
187
- /**
188
- * Span attribute identifying the client. Default `client.address`
189
- * (falls back to `http.client_ip`).
190
- */
191
- keyAttribute?: string;
192
- /** Max distinct clients tracked (oldest evicted). Default 10_000. */
193
- maxKeys?: number;
200
+ /** HTTP statuses counted toward a burst. Default `[401, 403]`. */
201
+ statuses?: number[];
202
+ /** Denied responses within the window that trigger a signal. Default 10. */
203
+ threshold?: number;
204
+ /** Sliding window size in milliseconds. Default 60_000. */
205
+ windowMs?: number;
206
+ /**
207
+ * Span attribute identifying the client. Default `client.address`
208
+ * (falls back to `http.client_ip`).
209
+ */
210
+ keyAttribute?: string;
211
+ /** Max distinct clients tracked (oldest evicted). Default 10_000. */
212
+ maxKeys?: number;
194
213
  }
195
214
  interface LlmSignalOptions {
215
+ /**
216
+ * Single-call token ceiling (`gen_ai.usage.total_tokens`, or input+output).
217
+ * Default 100_000. Pass `false` to disable the per-call check.
218
+ */
219
+ maxTokensPerCall?: number | false;
220
+ /**
221
+ * Sliding-window token budget per key — catches slow-drip abuse that
222
+ * stays under the per-call ceiling (OWASP LLM10: Unbounded Consumption).
223
+ * Off unless configured.
224
+ */
225
+ tokenBudget?: {
226
+ budget: number; /** Window size in milliseconds. Default 300_000 (5 min). */
227
+ windowMs?: number;
196
228
  /**
197
- * Single-call token ceiling (`gen_ai.usage.total_tokens`, or input+output).
198
- * Default 100_000. Pass `false` to disable the per-call check.
199
- */
200
- maxTokensPerCall?: number | false;
201
- /**
202
- * Sliding-window token budget per key — catches slow-drip abuse that
203
- * stays under the per-call ceiling (OWASP LLM10: Unbounded Consumption).
204
- * Off unless configured.
229
+ * Span attribute identifying the consumer. Default `enduser.id`
230
+ * (falls back to `client.address`).
205
231
  */
206
- tokenBudget?: {
207
- budget: number;
208
- /** Window size in milliseconds. Default 300_000 (5 min). */
209
- windowMs?: number;
210
- /**
211
- * Span attribute identifying the consumer. Default `enduser.id`
212
- * (falls back to `client.address`).
213
- */
214
- keyAttribute?: string;
215
- /** Max distinct keys tracked (oldest evicted). Default 10_000. */
216
- maxKeys?: number;
217
- };
232
+ keyAttribute?: string; /** Max distinct keys tracked (oldest evicted). Default 10_000. */
233
+ maxKeys?: number;
234
+ };
218
235
  }
219
236
  interface SecuritySignalProcessorOptions {
220
- /** Flag suspicious request paths on span start. Default true. */
221
- detectSuspiciousRequests?: boolean;
222
- /** Additional name → pattern pairs checked against the request target. */
223
- extraPatterns?: Record<string, RegExp>;
224
- /** Force-keep flagged spans through tail sampling. Default true. */
225
- forceKeepSuspicious?: boolean;
226
- /** HTTP statuses counted as denied. Default `[401, 403, 429]`. */
227
- deniedStatuses?: number[];
228
- /** Burst detection over denied responses. Pass `false` to disable. */
229
- burst?: BurstOptions | false;
230
- /**
231
- * LLM consumption signals from `gen_ai.*` spans (OWASP LLM10).
232
- * Enabled with the per-call ceiling by default; pass `false` to disable.
233
- */
234
- llm?: LlmSignalOptions | false;
235
- /** Emit `autotel.security.*` metrics. Default true. */
236
- metrics?: boolean;
237
- /** Called whenever a signal fires. Keep it fast and non-throwing. */
238
- onSignal?: (signal: SecuritySignal) => void;
239
- /** Clock override for tests. */
240
- now?: () => number;
237
+ /** Flag suspicious request paths on span start. Default true. */
238
+ detectSuspiciousRequests?: boolean;
239
+ /** Additional name → pattern pairs checked against the request target. */
240
+ extraPatterns?: Record<string, RegExp>;
241
+ /** Force-keep flagged spans through tail sampling. Default true. */
242
+ forceKeepSuspicious?: boolean;
243
+ /** HTTP statuses counted as denied. Default `[401, 403, 429]`. */
244
+ deniedStatuses?: number[];
245
+ /** Burst detection over denied responses. Pass `false` to disable. */
246
+ burst?: BurstOptions | false;
247
+ /**
248
+ * LLM consumption signals from `gen_ai.*` spans (OWASP LLM10).
249
+ * Enabled with the per-call ceiling by default; pass `false` to disable.
250
+ */
251
+ llm?: LlmSignalOptions | false;
252
+ /** Emit `autotel.security.*` metrics. Default true. */
253
+ metrics?: boolean;
254
+ /** Called whenever a signal fires. Keep it fast and non-throwing. */
255
+ onSignal?: (signal: SecuritySignal) => void;
256
+ /** Clock override for tests. */
257
+ now?: () => number;
241
258
  }
242
259
  /**
243
260
  * Conservative request-target patterns. Tuned for scanner/probe traffic —
@@ -245,7 +262,8 @@ interface SecuritySignalProcessorOptions {
245
262
  */
246
263
  declare const SUSPICIOUS_REQUEST_PATTERNS: Record<string, RegExp>;
247
264
  declare function createSecuritySignalProcessor(options?: SecuritySignalProcessorOptions): SecuritySignalProcessor;
248
-
265
+ //#endregion
266
+ //#region src/security-heartbeat.d.ts
249
267
  /**
250
268
  * Security-telemetry heartbeat.
251
269
  *
@@ -266,32 +284,39 @@ declare function createSecuritySignalProcessor(options?: SecuritySignalProcessor
266
284
  * ```
267
285
  */
268
286
  interface SecurityHeartbeatOptions {
269
- /** Beat interval in milliseconds. Default 60_000. */
270
- intervalMs?: number;
271
- /** Extra counter attributes (keep cardinality low — labels, not data). */
272
- attributes?: Record<string, string | number | boolean>;
287
+ /** Beat interval in milliseconds. Default 60_000. */
288
+ intervalMs?: number;
289
+ /** Extra counter attributes (keep cardinality low — labels, not data). */
290
+ attributes?: Record<string, string | number | boolean>;
273
291
  }
274
292
  interface SecurityHeartbeat {
275
- stop(): void;
293
+ stop(): void;
276
294
  }
277
295
  declare function startSecurityHeartbeat(options?: SecurityHeartbeatOptions): SecurityHeartbeat;
278
-
296
+ //#endregion
297
+ //#region src/index.d.ts
279
298
  interface AuditMetadata {
280
- action: string;
281
- resource?: string;
282
- actorId?: string;
283
- category?: string;
284
- outcome?: 'success' | 'failure' | (string & {});
285
- [key: string]: unknown;
299
+ action: string;
300
+ resource?: string;
301
+ actorId?: string;
302
+ category?: string;
303
+ outcome?: 'success' | 'failure' | (string & {});
304
+ [key: string]: unknown;
286
305
  }
287
306
  interface WithAuditOptions {
288
- ctx?: AuditContext;
289
- emitNow?: boolean;
290
- forceKeep?: boolean;
291
- logger?: RequestLogger;
307
+ ctx?: AuditContext;
308
+ emitNow?: boolean;
309
+ forceKeep?: boolean;
310
+ logger?: RequestLogger;
311
+ /**
312
+ * Behaviour when no trace context can be resolved. Defaults to `warn`
313
+ * (best-effort: run un-audited, warn once). See {@link OnMissingContext}.
314
+ */
315
+ onMissingContext?: OnMissingContext;
292
316
  }
293
317
  declare function forceKeepAuditEvent(ctx?: AuditContext): void;
294
318
  declare function setAuditAttributes(metadata: AuditMetadata, ctx?: AuditContext): void;
295
319
  declare function withAudit<T>(metadata: AuditMetadata, fn: (ctx: AuditContext, logger: RequestLogger) => T | Promise<T>, options?: WithAuditOptions): Promise<T>;
296
-
297
- export { type AuditContext, type AuditMetadata, type AuthFailureBurstSignal, type BurstOptions, type HashIdentifierOptions, type LlmExcessiveTokensSignal, type LlmSignalOptions, type LlmTokenBudgetSignal, SUSPICIOUS_REQUEST_PATTERNS, type SecurityEventCategory, type SecurityEventMetadata, type SecurityEventOptions, type SecurityHeartbeat, type SecurityHeartbeatOptions, type SecurityOutcome, type SecuritySignal, type SecuritySignalProcessor, type SecuritySignalProcessorOptions, type SuggestedSecurityEventName, type SuspiciousRequestSignal, type WithAuditOptions, type WithSecurityOptions, createSecuritySignalProcessor, forceKeepAuditEvent, hashIdentifier, securityEvent, setAuditAttributes, startSecurityHeartbeat, withAudit, withSecurity };
320
+ //#endregion
321
+ export { type AuditContext, AuditMetadata, AuthFailureBurstSignal, BurstOptions, HashIdentifierOptions, LlmExcessiveTokensSignal, LlmSignalOptions, LlmTokenBudgetSignal, type OnMissingContext, SUSPICIOUS_REQUEST_PATTERNS, SecurityEventCategory, SecurityEventMetadata, SecurityEventOptions, SecurityHeartbeat, SecurityHeartbeatOptions, SecurityOutcome, type SecuritySeverity, SecuritySignal, SecuritySignalProcessor, SecuritySignalProcessorOptions, SuggestedSecurityEventName, SuspiciousRequestSignal, WithAuditOptions, WithSecurityOptions, createSecuritySignalProcessor, forceKeepAuditEvent, hashIdentifier, securityEvent, setAuditAttributes, startSecurityHeartbeat, withAudit, withSecurity };
322
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/context.ts","../src/security.ts","../src/security-signals.ts","../src/security-heartbeat.ts","../src/index.ts"],"mappings":"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"}