autotel
Version:
Write Once, Observe Anywhere
199 lines (195 loc) • 6.9 kB
TypeScript
import { SpanProcessor, Span, ReadableSpan } from '@opentelemetry/sdk-trace-base';
import { AttributeValue, Context } from '@opentelemetry/api';
/**
* Attribute Redacting Processor
*
* Automatically redacts PII and sensitive data from span attributes before export.
* This is critical for compliance (GDPR, PCI-DSS, HIPAA) and data security.
*
* @example Basic usage with preset
* ```typescript
* init({
* service: 'my-app',
* attributeRedactor: 'default'
* })
* ```
*
* @example Custom patterns
* ```typescript
* init({
* service: 'my-app',
* attributeRedactor: {
* keyPatterns: [/password/i, /secret/i],
* valuePatterns: [
* { name: 'customerId', pattern: /CUST-\d{8}/g, replacement: 'CUST-***' }
* ]
* }
* })
* ```
*/
/**
* Custom redactor function type
*/
type AttributeRedactorFn = (key: string, value: AttributeValue) => AttributeValue;
/**
* Built-in redactor preset names
*/
type AttributeRedactorPreset = 'default' | 'strict' | 'pci-dss';
/**
* Masker function type - receives the matched string and returns a masked version
*/
type MaskFn = (match: string) => string;
/**
* Value pattern configuration
*/
interface ValuePatternConfig {
/** Name for debugging/logging */
name: string;
/** Regex pattern to match in values */
pattern: RegExp;
/** Custom replacement (default: uses global replacement) */
replacement?: string;
/** Mask function for smart partial masking (overrides replacement) */
mask?: MaskFn;
}
/**
* Built-in PII pattern names
*/
type BuiltinPatternName = keyof typeof builtinPatterns;
/**
* Attribute redactor configuration
*/
interface AttributeRedactorConfig {
/** Patterns to match against attribute keys (redacts entire value if key matches) */
keyPatterns?: RegExp[];
/** Patterns to match against attribute values (redacts matched portion) */
valuePatterns?: ValuePatternConfig[];
/** Dot-notation paths to redact (e.g. 'user.password', 'payment.card') */
paths?: string[];
/** Built-in PII patterns to enable. `true` enables all, `false` disables all, array selects specific ones. */
builtins?: boolean | BuiltinPatternName[];
/** Custom RegExp patterns for string-level redaction */
patterns?: RegExp[];
/** Default replacement string (default: '[REDACTED]') */
replacement?: string;
/** Custom redactor function for full control */
redactor?: AttributeRedactorFn;
}
/**
* Processor options
*/
interface AttributeRedactingProcessorOptions {
redactor: AttributeRedactorConfig | AttributeRedactorPreset;
}
/**
* Built-in patterns for detecting sensitive data
*/
declare const REDACTOR_PATTERNS: {
readonly email: RegExp;
readonly phone: RegExp;
readonly ssn: RegExp;
readonly creditCard: RegExp;
readonly bearerToken: RegExp;
readonly apiKeyInValue: RegExp;
readonly jwt: RegExp;
readonly sensitiveKey: RegExp;
};
/**
* Built-in PII detection patterns with smart masking.
* Each builtin preserves just enough signal for debugging while scrubbing PII.
*/
declare const builtinPatterns: {
/** Credit card numbers → ****1111 (PCI DSS: last 4 allowed) */
readonly creditCard: {
readonly pattern: RegExp;
readonly mask: (m: string) => string;
};
/** Email addresses → a***@***.com */
readonly email: {
readonly pattern: RegExp;
readonly mask: (m: string) => string;
};
/** IPv4 addresses → ***.***.***.100 (last octet only) */
readonly ipv4: {
readonly pattern: RegExp;
readonly mask: (m: string) => string;
};
/** International phone numbers → +33******78 (country code + last 2 digits) */
readonly phone: {
readonly pattern: RegExp;
readonly mask: (m: string) => string;
};
/** JWT tokens → eyJ***.*** */
readonly jwt: {
readonly pattern: RegExp;
readonly mask: () => string;
};
/** Bearer tokens → Bearer *** */
readonly bearer: {
readonly pattern: RegExp;
readonly mask: () => string;
};
/** IBAN → FR76****189 (country + check digits + last 3) */
readonly iban: {
readonly pattern: RegExp;
readonly mask: (m: string) => string;
};
};
/**
* Built-in redactor presets
*/
declare const REDACTOR_PRESETS: Record<AttributeRedactorPreset, AttributeRedactorConfig>;
/**
* Normalize redactor config that may have been deserialized from JSON/YAML.
* Converts regex-like values back to RegExp instances.
*/
declare function normalizeAttributeRedactorConfig(raw: AttributeRedactorConfig | AttributeRedactorPreset | unknown): AttributeRedactorConfig | AttributeRedactorPreset | undefined;
/**
* Create a proxy wrapper around ReadableSpan with redacted attributes
*
* Since ReadableSpan.attributes is readonly, we use a Proxy to intercept
* attribute access and return the redacted version.
*/
declare function createRedactedSpan(span: ReadableSpan, redactor: AttributeRedactorFn): ReadableSpan;
/**
* Create an attribute redactor function from a config or preset.
*
* This is useful when you need to apply the same redaction logic
* outside of the span processor pipeline (e.g., for canonical log lines).
*
* @example
* ```typescript
* const redactor = createAttributeRedactor('default');
* const redactedValue = redactor('user.password', 'secret123');
* // redactedValue === '[REDACTED]'
* ```
*/
declare function createAttributeRedactor(config: AttributeRedactorConfig | AttributeRedactorPreset): AttributeRedactorFn;
/**
* Span processor that redacts sensitive data from span attributes.
*
* Redaction happens in onEnd() when all attributes are finalized.
* Uses a Proxy wrapper to intercept attribute access since ReadableSpan
* attributes are readonly.
*
* Common use cases:
* - PII compliance (GDPR, CCPA)
* - PCI-DSS compliance for payment data
* - Preventing secrets from leaking to observability backends
*/
declare class AttributeRedactingProcessor implements SpanProcessor {
private readonly wrappedProcessor;
private readonly redactor;
constructor(wrappedProcessor: SpanProcessor, options: AttributeRedactingProcessorOptions);
/**
* Pass through onStart unchanged - attributes aren't finalized yet
*/
onStart(span: Span, parentContext: Context): void;
/**
* Redact attributes and forward to wrapped processor
*/
onEnd(span: ReadableSpan): void;
forceFlush(): Promise<void>;
shutdown(): Promise<void>;
}
export { AttributeRedactingProcessor, type AttributeRedactingProcessorOptions, type AttributeRedactorConfig, type AttributeRedactorFn, type AttributeRedactorPreset, type BuiltinPatternName, type MaskFn, REDACTOR_PATTERNS, REDACTOR_PRESETS, type ValuePatternConfig, builtinPatterns, createAttributeRedactor, createRedactedSpan, normalizeAttributeRedactorConfig };