@zudojs/observability 1.2.0 → 1.2.2
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 +21 -3
- package/dist/redaction/index.d.ts +2 -1
- package/dist/redaction/index.js +2 -1
- package/dist/redaction/redaction.core.d.ts +0 -2
- package/dist/redaction/redaction.core.js +7 -29
- package/dist/redaction/redaction.defaults.d.ts +18 -0
- package/dist/redaction/redaction.defaults.js +33 -0
- package/dist/types/config.types.d.ts +10 -3
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -86,7 +86,9 @@ Redaction is **on by default**, as it is in `@zudojs/logger`: with no
|
|
|
86
86
|
(`DEFAULT_LOGGER_SECRET_FIELDS` — password, passphrase, secret, token, jwt,
|
|
87
87
|
bearer, auth, authorization, cookie, session, sid, credential, api key,
|
|
88
88
|
private key, client secret, card number, cvv, ssn, pin, otp and more) is
|
|
89
|
-
redacted here too
|
|
89
|
+
redacted here too. `DEFAULT_SENSITIVE_FIELDS` is that effective default list:
|
|
90
|
+
the logger's `DEFAULT_LOGGER_SECRET_FIELDS` plus a few spellings of its own
|
|
91
|
+
(`apikey`, `access_token`, `cardnumber`, …).
|
|
90
92
|
Pass a config to change the rules, or `redaction: false` to turn it off.
|
|
91
93
|
Before 1.2 redaction was off unless configured, so a `password` field was
|
|
92
94
|
exported in the clear.
|
|
@@ -100,8 +102,8 @@ redacted the same way one written to a log field is.
|
|
|
100
102
|
const obs = createObservability({
|
|
101
103
|
serviceName: "api",
|
|
102
104
|
redaction: {
|
|
103
|
-
//
|
|
104
|
-
fields: ["
|
|
105
|
+
// `fields` adds to the defaults; they stay in force.
|
|
106
|
+
fields: ["nationalId", "taxNumber"],
|
|
105
107
|
patterns: [/^x-.*-secret$/i],
|
|
106
108
|
// "contains" (the default) matches on word boundaries: "userPassword"
|
|
107
109
|
// and "x-api-key" match, "shippingAddress" and "authorId" do not.
|
|
@@ -117,6 +119,22 @@ obs.logger.info("login", {
|
|
|
117
119
|
});
|
|
118
120
|
```
|
|
119
121
|
|
|
122
|
+
`fields` **extends** the defaults (since 1.2.1): the default names and the
|
|
123
|
+
logger's matcher stay in force, so a field list can only add redaction —
|
|
124
|
+
`fields: ["nationalId"]` and `fields: [...DEFAULT_SENSITIVE_FIELDS, "nationalId"]`
|
|
125
|
+
mean the same thing. In 1.2.0 a list replaced the defaults, and because
|
|
126
|
+
`DEFAULT_SENSITIVE_FIELDS` then lacked `jwt`, `sid`, `pwd`, `passphrase` and
|
|
127
|
+
`bearer`, spreading it redacted less than the default. To use your list alone,
|
|
128
|
+
opt out explicitly:
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
createObservability({
|
|
132
|
+
serviceName: "api",
|
|
133
|
+
// Only `ssn` is redacted — no default names, no logger matcher.
|
|
134
|
+
redaction: { fields: ["ssn"], replaceDefaults: true },
|
|
135
|
+
});
|
|
136
|
+
```
|
|
137
|
+
|
|
120
138
|
Traversal handles the shapes secrets actually arrive in: arrays, nested
|
|
121
139
|
objects, instances of your own classes (a DTO carrying a `password` field is
|
|
122
140
|
redacted and keeps its prototype), and cyclic graphs (a request object in a log
|
|
@@ -3,5 +3,6 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Sensitive field redaction for logs and traces.
|
|
5
5
|
*/
|
|
6
|
-
export { createRedactor, createStructureRedactor, redactObject, redactValue, isSensitiveField,
|
|
6
|
+
export { createRedactor, createStructureRedactor, redactObject, redactValue, isSensitiveField, CIRCULAR_MARKER, MAX_DEPTH_MARKER, } from "./redaction.core.js";
|
|
7
|
+
export { DEFAULT_SENSITIVE_FIELDS } from "./redaction.defaults.js";
|
|
7
8
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/redaction/index.js
CHANGED
|
@@ -3,5 +3,6 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Sensitive field redaction for logs and traces.
|
|
5
5
|
*/
|
|
6
|
-
export { createRedactor, createStructureRedactor, redactObject, redactValue, isSensitiveField,
|
|
6
|
+
export { createRedactor, createStructureRedactor, redactObject, redactValue, isSensitiveField, CIRCULAR_MARKER, MAX_DEPTH_MARKER, } from "./redaction.core.js";
|
|
7
|
+
export { DEFAULT_SENSITIVE_FIELDS } from "./redaction.defaults.js";
|
|
7
8
|
//# sourceMappingURL=index.js.map
|
|
@@ -17,8 +17,6 @@
|
|
|
17
17
|
* `x-api-key` are caught, not just the exact names in the list.
|
|
18
18
|
*/
|
|
19
19
|
import type { RedactionConfig } from "../types.js";
|
|
20
|
-
/** Default sensitive field names, matched case-insensitively. */
|
|
21
|
-
export declare const DEFAULT_SENSITIVE_FIELDS: readonly string[];
|
|
22
20
|
/** Marker used in place of a structure that was too deep or already seen. */
|
|
23
21
|
export declare const CIRCULAR_MARKER = "[CIRCULAR]";
|
|
24
22
|
export declare const MAX_DEPTH_MARKER = "[MAX_DEPTH]";
|
|
@@ -17,39 +17,13 @@
|
|
|
17
17
|
* `x-api-key` are caught, not just the exact names in the list.
|
|
18
18
|
*/
|
|
19
19
|
import { createDefaultSecretFieldMatcher } from "@zudojs/logger";
|
|
20
|
+
import { DEFAULT_SENSITIVE_FIELDS } from "./redaction.defaults.js";
|
|
20
21
|
/**
|
|
21
22
|
* @zudojs/logger's default secret-name matcher. The default rules here
|
|
22
23
|
* include it, so a field the logger redacts is never exported in the clear
|
|
23
24
|
* by this package.
|
|
24
25
|
*/
|
|
25
26
|
const isLoggerSecretField = createDefaultSecretFieldMatcher();
|
|
26
|
-
/** Default sensitive field names, matched case-insensitively. */
|
|
27
|
-
export const DEFAULT_SENSITIVE_FIELDS = [
|
|
28
|
-
"password",
|
|
29
|
-
"passwd",
|
|
30
|
-
"secret",
|
|
31
|
-
"token",
|
|
32
|
-
"authorization",
|
|
33
|
-
"auth",
|
|
34
|
-
"cookie",
|
|
35
|
-
"session",
|
|
36
|
-
"credential",
|
|
37
|
-
"api_key",
|
|
38
|
-
"apikey",
|
|
39
|
-
"access_token",
|
|
40
|
-
"refresh_token",
|
|
41
|
-
"private_key",
|
|
42
|
-
"client_secret",
|
|
43
|
-
"credit_card",
|
|
44
|
-
"creditcard",
|
|
45
|
-
"card_number",
|
|
46
|
-
"cardnumber",
|
|
47
|
-
"cvv",
|
|
48
|
-
"ssn",
|
|
49
|
-
"social_security",
|
|
50
|
-
"pin",
|
|
51
|
-
"otp",
|
|
52
|
-
];
|
|
53
27
|
const DEFAULT_REPLACEMENT = "[REDACTED]";
|
|
54
28
|
const DEFAULT_MAX_DEPTH = 8;
|
|
55
29
|
/** Marker used in place of a structure that was too deep or already seen. */
|
|
@@ -94,12 +68,16 @@ function wordJoins(key) {
|
|
|
94
68
|
return joins;
|
|
95
69
|
}
|
|
96
70
|
function compile(config) {
|
|
97
|
-
const
|
|
71
|
+
const configured = config?.fields;
|
|
72
|
+
const replaceDefaults = configured !== undefined && config?.replaceDefaults === true;
|
|
73
|
+
const fields = (replaceDefaults
|
|
74
|
+
? configured
|
|
75
|
+
: [...DEFAULT_SENSITIVE_FIELDS, ...(configured ?? [])]).map((field) => field.toLowerCase());
|
|
98
76
|
const patterns = config?.patterns ?? [];
|
|
99
77
|
const matchMode = config?.matchMode ?? "contains";
|
|
100
78
|
const exact = new Set(fields);
|
|
101
79
|
const normalizedFields = new Set(fields.map((field) => field.replace(/[^a-z0-9]/g, "")).filter(Boolean));
|
|
102
|
-
const withLoggerDefaults =
|
|
80
|
+
const withLoggerDefaults = !replaceDefaults && matchMode === "contains";
|
|
103
81
|
const isSensitive = (key) => {
|
|
104
82
|
const lower = key.toLowerCase();
|
|
105
83
|
if (exact.has(lower))
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @zudojs/observability — Default redaction field list
|
|
3
|
+
*
|
|
4
|
+
* One list, built from @zudojs/logger's rather than copied from it, so the
|
|
5
|
+
* documented "extend the defaults" pattern
|
|
6
|
+
* (`fields: [...DEFAULT_SENSITIVE_FIELDS, "nationalId"]`) can never cover
|
|
7
|
+
* fewer names than the default rules do.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Default sensitive field names, matched case-insensitively.
|
|
11
|
+
*
|
|
12
|
+
* Every entry of @zudojs/logger's `DEFAULT_LOGGER_SECRET_FIELDS` (password,
|
|
13
|
+
* passphrase, pwd, secret, token, jwt, bearer, auth, cookie, session, sid,
|
|
14
|
+
* credential, api key, card number, cvv, ssn, pin, otp, …) plus the
|
|
15
|
+
* spellings in {@link OBSERVABILITY_EXTRA_FIELDS}.
|
|
16
|
+
*/
|
|
17
|
+
export declare const DEFAULT_SENSITIVE_FIELDS: readonly string[];
|
|
18
|
+
//# sourceMappingURL=redaction.defaults.d.ts.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @zudojs/observability — Default redaction field list
|
|
3
|
+
*
|
|
4
|
+
* One list, built from @zudojs/logger's rather than copied from it, so the
|
|
5
|
+
* documented "extend the defaults" pattern
|
|
6
|
+
* (`fields: [...DEFAULT_SENSITIVE_FIELDS, "nationalId"]`) can never cover
|
|
7
|
+
* fewer names than the default rules do.
|
|
8
|
+
*/
|
|
9
|
+
import { DEFAULT_LOGGER_SECRET_FIELDS } from "@zudojs/logger";
|
|
10
|
+
/**
|
|
11
|
+
* Spellings this package matched before it adopted the logger's list. In
|
|
12
|
+
* `"contains"` mode they are already covered by a logger entry; they are kept
|
|
13
|
+
* so `"exact"` mode (`apikey` vs `api_key`) does not lose them.
|
|
14
|
+
*/
|
|
15
|
+
const OBSERVABILITY_EXTRA_FIELDS = [
|
|
16
|
+
"apikey",
|
|
17
|
+
"access_token",
|
|
18
|
+
"refresh_token",
|
|
19
|
+
"creditcard",
|
|
20
|
+
"cardnumber",
|
|
21
|
+
];
|
|
22
|
+
/**
|
|
23
|
+
* Default sensitive field names, matched case-insensitively.
|
|
24
|
+
*
|
|
25
|
+
* Every entry of @zudojs/logger's `DEFAULT_LOGGER_SECRET_FIELDS` (password,
|
|
26
|
+
* passphrase, pwd, secret, token, jwt, bearer, auth, cookie, session, sid,
|
|
27
|
+
* credential, api key, card number, cvv, ssn, pin, otp, …) plus the
|
|
28
|
+
* spellings in {@link OBSERVABILITY_EXTRA_FIELDS}.
|
|
29
|
+
*/
|
|
30
|
+
export const DEFAULT_SENSITIVE_FIELDS = Object.freeze([
|
|
31
|
+
...new Set([...DEFAULT_LOGGER_SECRET_FIELDS, ...OBSERVABILITY_EXTRA_FIELDS]),
|
|
32
|
+
]);
|
|
33
|
+
//# sourceMappingURL=redaction.defaults.js.map
|
|
@@ -50,11 +50,18 @@ export type RedactionMatchMode = "exact" | "contains";
|
|
|
50
50
|
/** Configuration for redacting sensitive fields from logs and traces. */
|
|
51
51
|
export interface RedactionConfig {
|
|
52
52
|
/**
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
53
|
+
* Extra field names to redact (case-insensitive), added to the defaults:
|
|
54
|
+
* `DEFAULT_SENSITIVE_FIELDS` and @zudojs/logger's default matcher stay in
|
|
55
|
+
* force, so a list can only ever add redaction. Set
|
|
56
|
+
* {@link RedactionConfig.replaceDefaults} to use this list alone.
|
|
56
57
|
*/
|
|
57
58
|
readonly fields?: readonly string[];
|
|
59
|
+
/**
|
|
60
|
+
* `true` makes {@link RedactionConfig.fields} replace the default names and
|
|
61
|
+
* the logger's matcher instead of extending them — the pre-1.2.1 meaning
|
|
62
|
+
* of `fields`. Ignored when `fields` is not set. Default: `false`.
|
|
63
|
+
*/
|
|
64
|
+
readonly replaceDefaults?: boolean;
|
|
58
65
|
/**
|
|
59
66
|
* Additional patterns tested against the field name. Useful for
|
|
60
67
|
* conventions a name list cannot express, such as `/^x-.*-token$/i`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zudojs/observability",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.2",
|
|
4
4
|
"description": "Structured logging, metrics, tracing, context propagation, and exporters for Zudojs applications.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -26,8 +26,8 @@
|
|
|
26
26
|
"!dist/.tsbuildinfo"
|
|
27
27
|
],
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@zudojs/errors": "1.3.
|
|
30
|
-
"@zudojs/logger": "1.4.
|
|
29
|
+
"@zudojs/errors": "1.3.1",
|
|
30
|
+
"@zudojs/logger": "1.4.2"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"typescript": "7.0.2",
|