@foam-ai/node 0.1.0-alpha.10 → 0.1.0-alpha.11
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 +16 -9
- package/dist/before-send.d.ts +11 -0
- package/dist/before-send.js +7 -2
- package/dist/constants.d.ts +1 -1
- package/dist/constants.js +1 -1
- package/dist/exporters.d.ts +2 -1
- package/dist/exporters.js +43 -14
- package/dist/ingest.d.ts +1 -1
- package/dist/ingest.js +2 -2
- package/dist/init.js +3 -1
- package/dist/redaction-keys.d.ts +1 -0
- package/dist/redaction-keys.js +60 -1
- package/dist/redaction.js +18 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -181,7 +181,9 @@ init({
|
|
|
181
181
|
```
|
|
182
182
|
|
|
183
183
|
`beforeSend` can edit or drop spans and logs before Foam exports them. Return
|
|
184
|
-
the event to send it or `null` to drop it.
|
|
184
|
+
the event to send it or `null` to drop it. Span events carry `name`,
|
|
185
|
+
`attributes`, `events` (span events, e.g. recorded exceptions), and `links`;
|
|
186
|
+
log events carry `body`, `severityText`, and `attributes`.
|
|
185
187
|
|
|
186
188
|
```js
|
|
187
189
|
init({
|
|
@@ -259,10 +261,10 @@ const loggerProvider = new LoggerProvider({
|
|
|
259
261
|
logs.setGlobalLoggerProvider(loggerProvider);
|
|
260
262
|
```
|
|
261
263
|
|
|
262
|
-
|
|
263
|
-
`
|
|
264
|
+
All ingest helpers accept the same `redact` option as `init()`; the span and
|
|
265
|
+
log helpers also accept `beforeSend`.
|
|
264
266
|
|
|
265
|
-
### `createFoamIngestMetricReader(name, environment, token)`
|
|
267
|
+
### `createFoamIngestMetricReader(name, environment, token, options?)`
|
|
266
268
|
|
|
267
269
|
The helper returns a metric reader but does not attach it to the application's
|
|
268
270
|
provider. Include it in the `readers` option when constructing `MeterProvider`.
|
|
@@ -572,11 +574,16 @@ export wherever `getState().signals.traces` points.
|
|
|
572
574
|
## Redaction
|
|
573
575
|
|
|
574
576
|
Foam always masks common credentials in captured request and response data,
|
|
575
|
-
URLs, and exported span and log fields.
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
577
|
+
URLs, and exported span and log fields. The built-in floor matches both exact
|
|
578
|
+
well-known names and any key containing a sensitive term (`legacy_api_key_2`,
|
|
579
|
+
`stripeToken`), so credential-bearing keys do not need to be enumerated. Add
|
|
580
|
+
application-specific keys with the `redact` option shown under `init(options)`;
|
|
581
|
+
customer keys match exactly after normalization.
|
|
582
|
+
|
|
583
|
+
Redaction applies to everything Foam exports — span, span event, and link
|
|
584
|
+
attributes, log bodies and attributes, metric data-point attributes, and
|
|
585
|
+
resource attributes — including the ingest helpers. It does not modify
|
|
586
|
+
telemetry sent through other exporters.
|
|
580
587
|
|
|
581
588
|
## Loggers
|
|
582
589
|
|
package/dist/before-send.d.ts
CHANGED
|
@@ -1,7 +1,18 @@
|
|
|
1
|
+
export interface BeforeSendSpanEventEntry {
|
|
2
|
+
name: string;
|
|
3
|
+
attributes?: Record<string, unknown>;
|
|
4
|
+
time?: unknown;
|
|
5
|
+
}
|
|
6
|
+
export interface BeforeSendSpanLink {
|
|
7
|
+
context: Record<string, unknown>;
|
|
8
|
+
attributes?: Record<string, unknown>;
|
|
9
|
+
}
|
|
1
10
|
interface BeforeSendSpanEvent {
|
|
2
11
|
readonly type: "span";
|
|
3
12
|
name: string;
|
|
4
13
|
attributes: Record<string, unknown>;
|
|
14
|
+
events: BeforeSendSpanEventEntry[];
|
|
15
|
+
links: BeforeSendSpanLink[];
|
|
5
16
|
}
|
|
6
17
|
interface BeforeSendLogEvent {
|
|
7
18
|
readonly type: "log";
|
package/dist/before-send.js
CHANGED
|
@@ -17,8 +17,13 @@ function isEvent(value, expectedType) {
|
|
|
17
17
|
if (!isRecord(value) || value.type !== expectedType || !isRecord(value.attributes)) {
|
|
18
18
|
return false;
|
|
19
19
|
}
|
|
20
|
-
if (expectedType === "span")
|
|
21
|
-
return typeof value.name === "string"
|
|
20
|
+
if (expectedType === "span") {
|
|
21
|
+
return (typeof value.name === "string" &&
|
|
22
|
+
Array.isArray(value.events) &&
|
|
23
|
+
value.events.every((entry) => isRecord(entry) && typeof entry.name === "string") &&
|
|
24
|
+
Array.isArray(value.links) &&
|
|
25
|
+
value.links.every((entry) => isRecord(entry) && isRecord(entry.context)));
|
|
26
|
+
}
|
|
22
27
|
return value.severityText === undefined || typeof value.severityText === "string";
|
|
23
28
|
}
|
|
24
29
|
function invokeBeforeSend(hook, event) {
|
package/dist/constants.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export declare const FOAM_INGEST_HOST: string;
|
|
|
4
4
|
export declare const ATTR_FOAM_INGEST_HOST = "foam.ingest.host";
|
|
5
5
|
export declare const FOAM_IDENTIFIER_NAME = "[foam-otel]";
|
|
6
6
|
export declare const FOAM_DISTRO_NAME = "@foam-ai/node";
|
|
7
|
-
export declare const FOAM_DISTRO_VERSION = "0.1.0-alpha.
|
|
7
|
+
export declare const FOAM_DISTRO_VERSION = "0.1.0-alpha.11";
|
|
8
8
|
export declare const FOAM_OTLP_TRACES_PATH = "/v1/traces";
|
|
9
9
|
export declare const FOAM_OTLP_LOGS_PATH = "/v1/logs";
|
|
10
10
|
export declare const FOAM_OTLP_METRICS_PATH = "/v1/metrics";
|
package/dist/constants.js
CHANGED
|
@@ -7,7 +7,7 @@ exports.FOAM_INGEST_HOST = new URL(exports.FOAM_ENDPOINT).hostname;
|
|
|
7
7
|
exports.ATTR_FOAM_INGEST_HOST = "foam.ingest.host";
|
|
8
8
|
exports.FOAM_IDENTIFIER_NAME = "[foam-otel]";
|
|
9
9
|
exports.FOAM_DISTRO_NAME = "@foam-ai/node";
|
|
10
|
-
exports.FOAM_DISTRO_VERSION = "0.1.0-alpha.
|
|
10
|
+
exports.FOAM_DISTRO_VERSION = "0.1.0-alpha.11";
|
|
11
11
|
exports.FOAM_OTLP_TRACES_PATH = "/v1/traces";
|
|
12
12
|
exports.FOAM_OTLP_LOGS_PATH = "/v1/logs";
|
|
13
13
|
exports.FOAM_OTLP_METRICS_PATH = "/v1/metrics";
|
package/dist/exporters.d.ts
CHANGED
|
@@ -27,7 +27,8 @@ export declare class FoamLogExporter extends OTLPLogExporter {
|
|
|
27
27
|
}
|
|
28
28
|
export declare class FoamMetricExporter extends OTLPMetricExporter {
|
|
29
29
|
private readonly stamp?;
|
|
30
|
-
|
|
30
|
+
private readonly options;
|
|
31
|
+
constructor(token: string, stamp?: Stamp, options?: FoamExporterOptions);
|
|
31
32
|
export(resourceMetrics: ResourceMetrics, callback: (result: ExportResult) => void): void;
|
|
32
33
|
}
|
|
33
34
|
export {};
|
package/dist/exporters.js
CHANGED
|
@@ -13,7 +13,15 @@ const redaction_js_1 = require("./redaction.js");
|
|
|
13
13
|
function redactionConfig(options) {
|
|
14
14
|
return options.redaction ?? (0, redaction_js_1.getActiveRedactionConfig)();
|
|
15
15
|
}
|
|
16
|
-
|
|
16
|
+
// Snapshotting attributes here is safe: every SDK processor (batch/simple
|
|
17
|
+
// span, batch log, periodic metric reader) awaits the resource's
|
|
18
|
+
// waitForAsyncAttributes() before calling the exporter, so detector
|
|
19
|
+
// promises are already resolved.
|
|
20
|
+
function redactedResource(resource, overlay, config) {
|
|
21
|
+
const merged = overlay ? resource.merge(overlay) : resource;
|
|
22
|
+
return (0, resources_1.resourceFromAttributes)((0, redaction_js_1.redactAttributesCopy)(merged.attributes, config), { schemaUrl: merged.schemaUrl });
|
|
23
|
+
}
|
|
24
|
+
function copySpan(span, name, attributes, events, links, resource) {
|
|
17
25
|
return {
|
|
18
26
|
name,
|
|
19
27
|
kind: span.kind,
|
|
@@ -27,7 +35,7 @@ function copySpan(span, name, attributes, events, links, overlay) {
|
|
|
27
35
|
events,
|
|
28
36
|
duration: span.duration,
|
|
29
37
|
ended: span.ended,
|
|
30
|
-
resource
|
|
38
|
+
resource,
|
|
31
39
|
instrumentationScope: span.instrumentationScope,
|
|
32
40
|
droppedAttributesCount: span.droppedAttributesCount,
|
|
33
41
|
droppedEventsCount: span.droppedEventsCount,
|
|
@@ -52,33 +60,44 @@ class FoamTraceExporter extends exporter_trace_otlp_http_1.OTLPTraceExporter {
|
|
|
52
60
|
for (const span of spans) {
|
|
53
61
|
let name = span.name;
|
|
54
62
|
let sourceAttributes = span.attributes;
|
|
63
|
+
let sourceEvents = span.events ?? [];
|
|
64
|
+
let sourceLinks = span.links ?? [];
|
|
55
65
|
if (this.options.beforeSend) {
|
|
56
66
|
const result = (0, before_send_js_1.invokeBeforeSend)(this.options.beforeSend, {
|
|
57
67
|
type: "span",
|
|
58
68
|
name,
|
|
59
69
|
attributes: sourceAttributes,
|
|
70
|
+
events: sourceEvents,
|
|
71
|
+
links: sourceLinks,
|
|
60
72
|
});
|
|
61
73
|
if (result === null)
|
|
62
74
|
continue;
|
|
63
75
|
if (result?.type === "span") {
|
|
64
76
|
name = result.name;
|
|
65
77
|
sourceAttributes = result.attributes;
|
|
78
|
+
// Hook-added events may omit time; default it to the span start so
|
|
79
|
+
// OTLP serialization stays valid.
|
|
80
|
+
sourceEvents = result.events.map((entry) => ({
|
|
81
|
+
time: span.startTime,
|
|
82
|
+
...entry,
|
|
83
|
+
}));
|
|
84
|
+
sourceLinks = result.links;
|
|
66
85
|
}
|
|
67
86
|
}
|
|
68
87
|
const attributes = (0, redaction_js_1.redactAttributesCopy)(sourceAttributes, config);
|
|
69
|
-
const events =
|
|
88
|
+
const events = sourceEvents.map((event) => event.attributes
|
|
70
89
|
? {
|
|
71
90
|
...event,
|
|
72
91
|
attributes: (0, redaction_js_1.redactAttributesCopy)(event.attributes, config),
|
|
73
92
|
}
|
|
74
93
|
: event);
|
|
75
|
-
const links =
|
|
94
|
+
const links = sourceLinks.map((link) => link.attributes
|
|
76
95
|
? {
|
|
77
96
|
...link,
|
|
78
97
|
attributes: (0, redaction_js_1.redactAttributesCopy)(link.attributes, config),
|
|
79
98
|
}
|
|
80
99
|
: link);
|
|
81
|
-
output.push(copySpan(span, name, attributes, events, links, overlay));
|
|
100
|
+
output.push(copySpan(span, name, attributes, events, links, redactedResource(span.resource, overlay, config)));
|
|
82
101
|
}
|
|
83
102
|
if (output.length === 0) {
|
|
84
103
|
callback({ code: core_1.ExportResultCode.SUCCESS });
|
|
@@ -88,7 +107,7 @@ class FoamTraceExporter extends exporter_trace_otlp_http_1.OTLPTraceExporter {
|
|
|
88
107
|
}
|
|
89
108
|
}
|
|
90
109
|
exports.FoamTraceExporter = FoamTraceExporter;
|
|
91
|
-
function copyLog(record, body, severityText, attributes,
|
|
110
|
+
function copyLog(record, body, severityText, attributes, resource) {
|
|
92
111
|
return {
|
|
93
112
|
hrTime: record.hrTime,
|
|
94
113
|
hrTimeObserved: record.hrTimeObserved,
|
|
@@ -97,7 +116,7 @@ function copyLog(record, body, severityText, attributes, overlay) {
|
|
|
97
116
|
severityNumber: record.severityNumber,
|
|
98
117
|
body,
|
|
99
118
|
eventName: record.eventName,
|
|
100
|
-
resource
|
|
119
|
+
resource,
|
|
101
120
|
instrumentationScope: record.instrumentationScope,
|
|
102
121
|
attributes,
|
|
103
122
|
droppedAttributesCount: record.droppedAttributesCount,
|
|
@@ -146,7 +165,7 @@ class FoamLogExporter extends exporter_logs_otlp_http_1.OTLPLogExporter {
|
|
|
146
165
|
}
|
|
147
166
|
const body = redactBody(sourceBody, config);
|
|
148
167
|
const attributes = (0, redaction_js_1.redactAttributesCopy)(sourceAttributes, config);
|
|
149
|
-
output.push(copyLog(record, body, severityText, attributes, overlay));
|
|
168
|
+
output.push(copyLog(record, body, severityText, attributes, redactedResource(record.resource, overlay, config)));
|
|
150
169
|
}
|
|
151
170
|
if (output.length === 0) {
|
|
152
171
|
callback({ code: core_1.ExportResultCode.SUCCESS });
|
|
@@ -158,21 +177,31 @@ class FoamLogExporter extends exporter_logs_otlp_http_1.OTLPLogExporter {
|
|
|
158
177
|
exports.FoamLogExporter = FoamLogExporter;
|
|
159
178
|
class FoamMetricExporter extends exporter_metrics_otlp_http_1.OTLPMetricExporter {
|
|
160
179
|
stamp;
|
|
161
|
-
|
|
180
|
+
options;
|
|
181
|
+
constructor(token, stamp, options = {}) {
|
|
162
182
|
super({
|
|
163
183
|
url: `${endpoint_js_1.endpoint}${constants_js_1.FOAM_OTLP_METRICS_PATH}`,
|
|
164
184
|
headers: { Authorization: `Bearer ${token}` },
|
|
165
185
|
});
|
|
166
186
|
this.stamp = stamp;
|
|
187
|
+
this.options = options;
|
|
167
188
|
}
|
|
168
189
|
export(resourceMetrics, callback) {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
return;
|
|
172
|
-
}
|
|
190
|
+
const config = redactionConfig(this.options);
|
|
191
|
+
const overlay = this.stamp ? (0, resources_1.resourceFromAttributes)(this.stamp) : undefined;
|
|
173
192
|
super.export({
|
|
174
193
|
...resourceMetrics,
|
|
175
|
-
resource: resourceMetrics.resource
|
|
194
|
+
resource: redactedResource(resourceMetrics.resource, overlay, config),
|
|
195
|
+
scopeMetrics: resourceMetrics.scopeMetrics.map((scope) => ({
|
|
196
|
+
...scope,
|
|
197
|
+
metrics: scope.metrics.map((metric) => ({
|
|
198
|
+
...metric,
|
|
199
|
+
dataPoints: metric.dataPoints.map((point) => ({
|
|
200
|
+
...point,
|
|
201
|
+
attributes: (0, redaction_js_1.redactAttributesCopy)(point.attributes, config),
|
|
202
|
+
})),
|
|
203
|
+
})),
|
|
204
|
+
})),
|
|
176
205
|
}, callback);
|
|
177
206
|
}
|
|
178
207
|
}
|
package/dist/ingest.d.ts
CHANGED
|
@@ -9,4 +9,4 @@ export interface FoamIngestOptions {
|
|
|
9
9
|
}
|
|
10
10
|
export declare function createFoamIngestSpanProcessor(name: string, environment: string, token: string, options?: FoamIngestOptions): SpanProcessor;
|
|
11
11
|
export declare function createFoamIngestLogRecordProcessor(name: string, environment: string, token: string, options?: FoamIngestOptions): LogRecordProcessor;
|
|
12
|
-
export declare function createFoamIngestMetricReader(name: string, environment: string, token: string): PeriodicExportingMetricReader;
|
|
12
|
+
export declare function createFoamIngestMetricReader(name: string, environment: string, token: string, options?: FoamIngestOptions): PeriodicExportingMetricReader;
|
package/dist/ingest.js
CHANGED
|
@@ -60,10 +60,10 @@ function createFoamIngestLogRecordProcessor(name, environment, token, options =
|
|
|
60
60
|
reportIngestSignal(state_js_1.Signals.logs, name, environment, token);
|
|
61
61
|
return processor;
|
|
62
62
|
}
|
|
63
|
-
function createFoamIngestMetricReader(name, environment, token) {
|
|
63
|
+
function createFoamIngestMetricReader(name, environment, token, options = {}) {
|
|
64
64
|
const { stamp } = prepareStamp(name, environment, token);
|
|
65
65
|
const reader = new sdk_metrics_1.PeriodicExportingMetricReader({
|
|
66
|
-
exporter: new exporters_js_1.FoamMetricExporter(token, stamp),
|
|
66
|
+
exporter: new exporters_js_1.FoamMetricExporter(token, stamp, prepareOptions(options)),
|
|
67
67
|
});
|
|
68
68
|
reportIngestSignal(state_js_1.Signals.metrics, name, environment, token);
|
|
69
69
|
return reader;
|
package/dist/init.js
CHANGED
|
@@ -107,7 +107,9 @@ function init(options) {
|
|
|
107
107
|
resource,
|
|
108
108
|
readers: [
|
|
109
109
|
new sdk_metrics_1.PeriodicExportingMetricReader({
|
|
110
|
-
exporter: new exporters_js_1.FoamMetricExporter(options.token
|
|
110
|
+
exporter: new exporters_js_1.FoamMetricExporter(options.token, undefined, {
|
|
111
|
+
redaction: redactionConfig,
|
|
112
|
+
}),
|
|
111
113
|
}),
|
|
112
114
|
...(options.additionalMetricReaders ?? []),
|
|
113
115
|
],
|
package/dist/redaction-keys.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export declare const SENSITIVE_KEYS: readonly ["admin_password", "basic_auth_password", "confirm_password", "connection_password", "current_password", "database_password", "db_pass", "db_password", "ftp_password", "http_password", "keystore_password", "master_password", "mail_password", "mysql_pwd", "new_password", "old_password", "pass", "passcode", "passphrase", "passwd", "password", "password_confirmation", "postgres_password", "pwd", "redis_password", "root_password", "smtp_password", "user_password", "access_token_secret", "activation_token", "access_token", "api_token", "assertion", "auth", "auth_token", "authentication_token", "authorization", "authorization_code", "bearer", "bearer_token", "bot_token", "ci_job_token", "client_assertion", "client_secret", "credential", "credentials", "deploy_token", "email_verification_token", "id_token", "identity_token", "invite_token", "jwt", "jwt_token", "magic_link_token", "oauth_token", "oauth2_token", "oauth_token_secret", "password_reset_token", "personal_access_token", "registration_token", "request_token", "refresh_token", "reset_token", "saml_assertion", "saml_response", "secret_token", "security_token", "service_token", "sso_token", "token", "unsubscribe_token", "verification_token", "access_key", "access_key_id", "api_key", "api_secret", "amqp_url", "apikey", "app_key", "app_secret", "application_key", "application_secret", "aws_access_key_id", "aws_secret_access_key", "consumer_key", "consumer_secret", "broker_url", "connection_string", "connection_uri", "credential_blob", "decryption_key", "database_url", "database_connection_string", "db_url", "dsn", "encryption_key", "gcp_service_account_key", "google_application_credentials", "key", "key_password", "key_store_password", "keystore", "license_key", "mnemonic", "mongodb_uri", "kube_config", "kubeconfig", "pem", "private_key", "privatekey", "proxy_authorization", "redis_url", "redis_uri", "rabbitmq_url", "secret", "secret_access_key", "secret_key", "seed_phrase", "service_account_json", "service_account_key", "shared_secret", "signature", "signing_key", "signing_secret", "ssh_private_key", "smtp_url", "tls_private_key", "wallet_private_key", "wallet_seed", "webhook_secret", "www_authenticate", "_csrf", "_csrf_token", "_session", "_xsrf", "aiohttp_session", "anti_forgery_token", "backup_code", "backup_codes", "connect.sid", "cookie", "csrf", "csrf_token", "csrftoken", "django_session", "hotp", "laravel_session", "mfa", "mfa_code", "otp", "phpsessid", "pin", "recovery_code", "recovery_codes", "remember_token", "session", "session_id", "session_key", "session_token", "sessionid", "set_cookie", "setcookie", "sid", "symfony", "totp", "user_session", "x_csrf_token", "x_csrftoken", "x_xsrf_token", "xsrf", "xsrf_token", "account_number", "bank_account", "card", "card_number", "credit_card", "credit_card_number", "cvc", "cvv", "date_of_birth", "dob", "driver_license", "drivers_license", "iban", "ip_address", "national_id", "passport_number", "remote_addr", "routing_number", "sort_code", "ssn", "tax_id", "x_forwarded_for", "x_real_ip", "algolia_admin_api_key", "anthropic_api_key", "artifactory_api_key", "airtable_api_key", "azure_api_key", "buildkite_agent_token", "circle_token", "cohere_api_key", "cloudflare_api_token", "consul_http_token", "datadog_api_key", "datadog_app_key", "discord_bot_token", "docker_password", "docker_config_json", "digitalocean_token", "firebase_service_account", "gemini_api_key", "github_token", "gitlab_token", "google_api_key", "groq_api_key", "honeycomb_api_key", "huggingface_token", "heroku_api_key", "jfrog_access_token", "linear_api_key", "mapbox_access_token", "new_relic_license_key", "nomad_token", "notion_token", "npm_token", "openai_api_key", "pagerduty_routing_key", "pypi_token", "sentry_auth_token", "sentry_dsn", "sendgrid_api_key", "shopify_access_token", "shopify_api_secret", "slack_app_token", "slack_bot_token", "slack_signing_secret", "stripe_secret_key", "stripe_webhook_secret", "supabase_service_role_key", "telegram_bot_token", "terraform_cloud_token", "twilio_auth_token", "vault_token", "vercel_oidc_token", "x_api_key", "x_auth_token"];
|
|
2
|
+
export declare const SENSITIVE_KEY_SEGMENTS: readonly ["apikey", "assertion", "auth", "bearer", "cookie", "cookies", "credential", "credentials", "csrf", "cvc", "cvv", "dsn", "hotp", "iban", "jwt", "mfa", "mnemonic", "otp", "passcode", "passphrase", "passport", "passwd", "password", "passwords", "pin", "pwd", "secret", "secrets", "session", "signature", "ssn", "token", "totp", "xsrf", "access_key", "account_number", "api_key", "app_key", "application_key", "card_number", "connection_string", "decryption_key", "encryption_key", "license_key", "master_key", "private_key", "routing_number", "secret_key", "seed_phrase", "service_account", "signing_key", "ssh_key"];
|
|
2
3
|
export declare const SENSITIVE_HTTP_HEADERS: readonly ["authentication_info", "authorization", "cf_access_authenticated_user_email", "cf_access_jwt_assertion", "cookie", "grpcgateway_authorization", "impersonate_group", "impersonate_user", "jenkins_crumb", "job_token", "ocp_apim_subscription_key", "private_token", "proxy_authenticate", "proxy_authentication_info", "proxy_authorization", "set_cookie", "stripe_signature", "www_authenticate", "x_access_token", "x_algolia_api_key", "x_amz_credential", "x_amz_security_token", "x_amz_signature", "x_amzn_oidc_accesstoken", "x_amzn_oidc_data", "x_amzn_oidc_identity", "x_api_key", "x_asana_request_token", "x_aws_ec2_metadata_token", "x_auth_request_access_token", "x_auth_request_email", "x_auth_request_groups", "x_auth_request_preferred_username", "x_auth_request_user", "x_auth_token", "x_box_signature_primary", "x_box_signature_secondary", "x_cf_access_jwt_assertion", "x_csrf_token", "x_circle_token", "x_consul_token", "x_credential_identifier", "x_datadog_api_key", "x_discord_signature_ed25519", "x_docusign_signature_1", "x_dropbox_signature", "x_elastic_client_authentication", "x_firebase_appcheck", "x_forwarded_access_token", "x_forwarded_email", "x_forwarded_for", "x_forwarded_user", "x_functions_key", "x_github_token", "x_gitlab_token", "x_goog_api_key", "x_goog_firebase_installations_auth", "x_goog_iap_jwt_assertion", "x_hub_signature", "x_hub_signature_256", "x_honeycomb_api_key", "x_honeycomb_team", "x_intercom_hmac", "x_jwt_assertion", "x_linear_signature", "x_mailgun_signature", "x_master_key", "x_meili_api_key", "x_ms_client_principal", "x_ms_token_aad_access_token", "x_ms_token_aad_id_token", "x_ms_token_aad_refresh_token", "x_nf_client_connection_ip", "x_nomad_token", "x_npm_token", "x_original_authorization", "x_real_ip", "x_remote_email", "x_remote_groups", "x_remote_user", "x_pagerduty_signature", "x_parse_rest_api_key", "x_sendgrid_event_webhook_signature", "x_session_token", "x_shopify_hmac_sha256", "x_signature", "x_signature_ed25519", "x_slack_signature", "x_sonarqube_passcode", "x_squarespace_hmacsha256_signature", "x_twilio_signature", "x_typesense_api_key", "x_userinfo", "x_vault_token", "x_vercel_oidc_token", "x_webhook_signature", "x_webhook_secret", "x_wix_webhook_signature", "x_xsrf_token", "x_zendesk_webhook_signature"];
|
|
3
4
|
export declare const SENSITIVE_QUERY_KEYS: readonly ["access_token", "api_key", "api_secret", "api_token", "apikey", "assertion", "auth", "auth_token", "authorization", "authorization_code", "bearer_token", "client_assertion", "client_secret", "code", "code_verifier", "credential", "hmac", "id_token", "invite_token", "jwt", "key", "magic_link_token", "oauth_token_secret", "otp", "password_reset_token", "password", "policy", "pin", "refresh_token", "reset_token", "saml_response", "secret", "secret_key", "session", "session_id", "session_token", "sig", "signature", "token", "token_secret", "unsubscribe_token", "verification_token", "x_amz_credential", "x_amz_security_token", "x_amz_signature", "x_goog_credential", "x_goog_signature"];
|
package/dist/redaction-keys.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SENSITIVE_QUERY_KEYS = exports.SENSITIVE_HTTP_HEADERS = exports.SENSITIVE_KEYS = void 0;
|
|
3
|
+
exports.SENSITIVE_QUERY_KEYS = exports.SENSITIVE_HTTP_HEADERS = exports.SENSITIVE_KEY_SEGMENTS = exports.SENSITIVE_KEYS = void 0;
|
|
4
4
|
const PASSWORD_KEYS = [
|
|
5
5
|
"admin_password",
|
|
6
6
|
"basic_auth_password",
|
|
@@ -268,6 +268,65 @@ exports.SENSITIVE_KEYS = [
|
|
|
268
268
|
...PERSONAL_AND_FINANCIAL_KEYS,
|
|
269
269
|
...PROVIDER_KEYS,
|
|
270
270
|
];
|
|
271
|
+
// Matched as whole underscore-separated segments of the normalized key, so
|
|
272
|
+
// any name *containing* one of these is caught without enumerating every
|
|
273
|
+
// variant: "legacy_api_key_2" matches "api_key", "stripeToken" matches
|
|
274
|
+
// "token", while "tokenizer" and "secretary" match nothing. Terms that would
|
|
275
|
+
// over-match as bare segments (e.g. "key", "code") appear only in compounds.
|
|
276
|
+
exports.SENSITIVE_KEY_SEGMENTS = [
|
|
277
|
+
"apikey",
|
|
278
|
+
"assertion",
|
|
279
|
+
"auth",
|
|
280
|
+
"bearer",
|
|
281
|
+
"cookie",
|
|
282
|
+
"cookies",
|
|
283
|
+
"credential",
|
|
284
|
+
"credentials",
|
|
285
|
+
"csrf",
|
|
286
|
+
"cvc",
|
|
287
|
+
"cvv",
|
|
288
|
+
"dsn",
|
|
289
|
+
"hotp",
|
|
290
|
+
"iban",
|
|
291
|
+
"jwt",
|
|
292
|
+
"mfa",
|
|
293
|
+
"mnemonic",
|
|
294
|
+
"otp",
|
|
295
|
+
"passcode",
|
|
296
|
+
"passphrase",
|
|
297
|
+
"passport",
|
|
298
|
+
"passwd",
|
|
299
|
+
"password",
|
|
300
|
+
"passwords",
|
|
301
|
+
"pin",
|
|
302
|
+
"pwd",
|
|
303
|
+
"secret",
|
|
304
|
+
"secrets",
|
|
305
|
+
"session",
|
|
306
|
+
"signature",
|
|
307
|
+
"ssn",
|
|
308
|
+
"token",
|
|
309
|
+
"totp",
|
|
310
|
+
"xsrf",
|
|
311
|
+
"access_key",
|
|
312
|
+
"account_number",
|
|
313
|
+
"api_key",
|
|
314
|
+
"app_key",
|
|
315
|
+
"application_key",
|
|
316
|
+
"card_number",
|
|
317
|
+
"connection_string",
|
|
318
|
+
"decryption_key",
|
|
319
|
+
"encryption_key",
|
|
320
|
+
"license_key",
|
|
321
|
+
"master_key",
|
|
322
|
+
"private_key",
|
|
323
|
+
"routing_number",
|
|
324
|
+
"secret_key",
|
|
325
|
+
"seed_phrase",
|
|
326
|
+
"service_account",
|
|
327
|
+
"signing_key",
|
|
328
|
+
"ssh_key",
|
|
329
|
+
];
|
|
271
330
|
exports.SENSITIVE_HTTP_HEADERS = [
|
|
272
331
|
"authentication_info",
|
|
273
332
|
"authorization",
|
package/dist/redaction.js
CHANGED
|
@@ -21,9 +21,10 @@ const EMPTY_CONFIG = {
|
|
|
21
21
|
secretKeys: new Set(),
|
|
22
22
|
piiKeys: new Set(),
|
|
23
23
|
};
|
|
24
|
-
|
|
25
|
-
const
|
|
26
|
-
const
|
|
24
|
+
// Lists are normalized like lookups so entries such as "connect.sid" match.
|
|
25
|
+
const FLOOR_KEYS = new Set(redaction_keys_js_1.SENSITIVE_KEYS.map(normalizeKey));
|
|
26
|
+
const HTTP_HEADERS = new Set(redaction_keys_js_1.SENSITIVE_HTTP_HEADERS.map(normalizeKey));
|
|
27
|
+
const QUERY_KEYS = new Set(redaction_keys_js_1.SENSITIVE_QUERY_KEYS.map(normalizeKey));
|
|
27
28
|
const HEADER_PREFIXES = ["http.request.header.", "http.response.header."];
|
|
28
29
|
const BARE_QUERY_KEYS = new Set(["url.query"]);
|
|
29
30
|
const BODY_KEYS = new Set([
|
|
@@ -44,22 +45,32 @@ function normalizeKey(key) {
|
|
|
44
45
|
.trim()
|
|
45
46
|
.replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2")
|
|
46
47
|
.replace(/([a-z0-9])([A-Z])/g, "$1_$2")
|
|
47
|
-
.replace(
|
|
48
|
+
.replace(/[-.]/g, "_")
|
|
48
49
|
.toLowerCase();
|
|
49
50
|
}
|
|
51
|
+
const FLOOR_SEGMENTS = redaction_keys_js_1.SENSITIVE_KEY_SEGMENTS.map((segment) => `_${segment}_`);
|
|
52
|
+
// Underscore padding makes containment whole-segment: "_my_api_key_2_"
|
|
53
|
+
// contains "_api_key_", while "_monkey_" and "_authorized_" contain nothing.
|
|
54
|
+
function hasFloorSegment(normalized) {
|
|
55
|
+
const padded = `_${normalized}_`;
|
|
56
|
+
return FLOOR_SEGMENTS.some((segment) => padded.includes(segment));
|
|
57
|
+
}
|
|
58
|
+
function isFloorName(normalized) {
|
|
59
|
+
return FLOOR_KEYS.has(normalized) || hasFloorSegment(normalized);
|
|
60
|
+
}
|
|
50
61
|
function isFloorKey(key) {
|
|
51
|
-
return
|
|
62
|
+
return isFloorName(normalizeKey(key));
|
|
52
63
|
}
|
|
53
64
|
function isSensitiveHeader(key) {
|
|
54
65
|
return HTTP_HEADERS.has(normalizeKey(key));
|
|
55
66
|
}
|
|
56
67
|
function isSensitiveQueryKey(key) {
|
|
57
68
|
const normalized = normalizeKey(key);
|
|
58
|
-
return
|
|
69
|
+
return isFloorName(normalized) || QUERY_KEYS.has(normalized);
|
|
59
70
|
}
|
|
60
71
|
function keyMatch(key, config = activeConfig) {
|
|
61
72
|
const normalized = normalizeKey(key);
|
|
62
|
-
if (
|
|
73
|
+
if (isFloorName(normalized))
|
|
63
74
|
return "floor";
|
|
64
75
|
if (config.piiKeys.has(normalized))
|
|
65
76
|
return "pii";
|