@smthrs/journal 1.0.0-rc.7 → 1.0.0-rc.8
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 +3 -1
- package/dist/cjs/Redaction.d.ts.map +1 -1
- package/dist/cjs/Redaction.js +26 -2
- package/dist/cjs/Redaction.js.map +2 -2
- package/dist/esm/Redaction.d.ts.map +1 -1
- package/dist/esm/Redaction.js +32 -5
- package/dist/esm/Redaction.js.map +1 -1
- package/docs/README.md +3 -1
- package/docs/concepts/redaction.md +9 -5
- package/docs/installation.md +5 -1
- package/docs/quickstart.md +6 -3
- package/package.json +4 -4
- package/src/Redaction.ts +32 -5
|
@@ -31,13 +31,14 @@ not a substring test, so `tokenizer`, `secretary`, `monkey`, and
|
|
|
31
31
|
`idempotencyKey` stay intact. Redacting them would destroy data in a permanent
|
|
32
32
|
row without protecting anything, and `idempotencyKey` in particular is the
|
|
33
33
|
durable identity an effect boundary replays on. Token counters are kept too: a
|
|
34
|
-
non-negative safe integer under
|
|
35
|
-
`
|
|
36
|
-
|
|
34
|
+
non-negative safe integer under any name ending in a plural `tokens`
|
|
35
|
+
(`inputTokens`, `cacheWriteTokens`, `max_tokens`) or under `inputToken`,
|
|
36
|
+
`outputToken`, `cachedInputToken`, `reasoningToken`, or `totalToken` is
|
|
37
|
+
accounting, not bearer material. A bare `token` is redacted even when numeric.
|
|
37
38
|
|
|
38
39
|
**Textual.** `Redaction.defaultRules` scans inside any string for credential
|
|
39
|
-
shapes seen in real bug reports: provider keys, bearer tokens, GitHub,
|
|
40
|
-
Slack, and Google credentials, URL passwords, Basic authorization, bare JWTs,
|
|
40
|
+
shapes seen in real bug reports: provider keys, bearer tokens, GitHub, GitLab, npm,
|
|
41
|
+
AWS, Slack (tokens and webhook URLs), and Google credentials, URL passwords, Basic authorization, bare JWTs,
|
|
41
42
|
PEM private-key blocks, INI/YAML credential assignments such as
|
|
42
43
|
`SECRET = value` and `password: value`, credential flags such as
|
|
43
44
|
`--password value`, cookie and session assignments, and embedded JSON
|
|
@@ -63,6 +64,9 @@ and a count under a plural `tokens` name (`max_tokens: 4096`) is kept.
|
|
|
63
64
|
A credential name that is a URL's user
|
|
64
65
|
(`https://x-access-token:…@github.com/acme/app.git`) takes only the password
|
|
65
66
|
before `@`, so the host and path a failed clone is diagnosed by are kept.
|
|
67
|
+
A URL password runs to the last `@` before the host, as a URL parser reads it,
|
|
68
|
+
so `redis://:pa:ss@cache` and `mysql://root:p@ss@db` lose the whole password,
|
|
69
|
+
and a URL with no password (`ssh://git@host`) is unchanged.
|
|
66
70
|
|
|
67
71
|
In a journal row a bare value is one token, and a string or container the text
|
|
68
72
|
never closes stops at the end of its line: a stray backtick in an agent's
|
package/docs/installation.md
CHANGED
|
@@ -7,7 +7,11 @@ sidebar:
|
|
|
7
7
|
|
|
8
8
|
## Install the package
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
```bash
|
|
11
|
+
npm install @smthrs/journal@next effect
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
The `next` tag carries the 1.0 release candidates.
|
|
11
15
|
|
|
12
16
|
The package requires Node.js 26.4.0 or later and ships as both ESM and
|
|
13
17
|
CommonJS with TypeScript declarations. Its only runtime dependencies are
|
package/docs/quickstart.md
CHANGED
|
@@ -17,10 +17,13 @@ redacted.
|
|
|
17
17
|
|
|
18
18
|
- Node.js 26.4.0 or later, where the built-in SQLite module lives.
|
|
19
19
|
- An ESM package (`"type": "module"`, because the program ends in a top-level
|
|
20
|
-
`await`) with the journal, the database it writes through,
|
|
21
|
-
installed. See [Installation](./installation.md) for the
|
|
20
|
+
`await`) with the journal, the database it writes through, its Node SQLite
|
|
21
|
+
driver, and `effect` installed. See [Installation](./installation.md) for the
|
|
22
|
+
`effect` range.
|
|
22
23
|
|
|
23
|
-
|
|
24
|
+
```bash
|
|
25
|
+
npm install @smthrs/journal@next @smthrs/database@next @effect/sql-sqlite-node effect
|
|
26
|
+
```
|
|
24
27
|
|
|
25
28
|
## Compose the layer
|
|
26
29
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@smthrs/journal",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0.0-rc.
|
|
4
|
+
"version": "1.0.0-rc.8",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"smthrs": {
|
|
7
7
|
"group": "engine"
|
|
@@ -226,14 +226,14 @@
|
|
|
226
226
|
"tag": "next"
|
|
227
227
|
},
|
|
228
228
|
"dependencies": {
|
|
229
|
-
"@smthrs/database": "1.0.0-rc.
|
|
229
|
+
"@smthrs/database": "1.0.0-rc.8"
|
|
230
230
|
},
|
|
231
231
|
"devDependencies": {
|
|
232
232
|
"@effect/language-service": "0.87.2",
|
|
233
233
|
"@effect/sql-sqlite-node": "4.0.4",
|
|
234
234
|
"@effect/vitest": "4.0.4",
|
|
235
235
|
"@eslint/js": "9.39.5",
|
|
236
|
-
"@smthrs/flow": "1.0.0-rc.
|
|
236
|
+
"@smthrs/flow": "1.0.0-rc.8",
|
|
237
237
|
"@types/node": "26.4.1",
|
|
238
238
|
"@vitest/coverage-v8": "5.0.0",
|
|
239
239
|
"dprint": "0.57.1",
|
|
@@ -254,7 +254,7 @@
|
|
|
254
254
|
"effect": "^4.0.4"
|
|
255
255
|
},
|
|
256
256
|
"scripts": {
|
|
257
|
-
"lint": "eslint src --max-warnings=0 && dprint check",
|
|
257
|
+
"lint": "eslint src examples --max-warnings=0 && dprint check",
|
|
258
258
|
"format": "dprint fmt",
|
|
259
259
|
"build": "node scripts/build.mjs",
|
|
260
260
|
"check": "tsc -b tsconfig.json && tsc -p tsconfig.test.json --noEmit",
|
package/src/Redaction.ts
CHANGED
|
@@ -779,7 +779,14 @@ export const defaultRules: ReadonlyArray<Rule> = [
|
|
|
779
779
|
// of `aaaaaaaa-` cost 11 seconds, on the path every journal write and every
|
|
780
780
|
// log line takes. A scheme longer than 30 characters is not one this net is
|
|
781
781
|
// for, and the cap makes each start position cost a constant.
|
|
782
|
-
|
|
782
|
+
//
|
|
783
|
+
// The username may be empty (`redis://:password@host`), and the password
|
|
784
|
+
// runs to the LAST `@` before the authority ends, as a URL parser reads
|
|
785
|
+
// it: RFC 3986 allows `:` in a password and a raw `@` is common in
|
|
786
|
+
// connection strings. Stopping at the first `:` or `@` left the tail of
|
|
787
|
+
// such a password in the row. Quotes and backslashes end the scan so a
|
|
788
|
+
// URL inside JSON text never swallows the next string.
|
|
789
|
+
pattern: /\b([a-z][a-z0-9+.-]{0,30}:\/\/[^\s:@/]*):(?!\[REDACTED\]@)[^\s/?#"'`\\]*@/gi,
|
|
783
790
|
replace: "$1:[REDACTED]@"
|
|
784
791
|
},
|
|
785
792
|
{
|
|
@@ -836,6 +843,23 @@ export const defaultRules: ReadonlyArray<Rule> = [
|
|
|
836
843
|
pattern: /\bAIza[0-9A-Za-z_-]{35,}(?![0-9A-Za-z_-])/g,
|
|
837
844
|
replace: "[REDACTED]"
|
|
838
845
|
},
|
|
846
|
+
{
|
|
847
|
+
id: "gitlab-token",
|
|
848
|
+
pattern: /\bglpat-[A-Za-z0-9_-]{20,}(?![A-Za-z0-9_-])/g,
|
|
849
|
+
replace: "[REDACTED]"
|
|
850
|
+
},
|
|
851
|
+
{
|
|
852
|
+
id: "npm-token",
|
|
853
|
+
pattern: /\bnpm_[A-Za-z0-9]{36}(?![A-Za-z0-9])/g,
|
|
854
|
+
replace: "[REDACTED]"
|
|
855
|
+
},
|
|
856
|
+
{
|
|
857
|
+
// The webhook path is the whole credential: anyone holding it can post
|
|
858
|
+
// to the channel. The host stays so a failed delivery is still readable.
|
|
859
|
+
id: "slack-webhook",
|
|
860
|
+
pattern: /(\bhooks\.slack\.com\/services\/)T[A-Z0-9]+\/B[A-Z0-9]+\/[A-Za-z0-9]+/g,
|
|
861
|
+
replace: "$1[REDACTED]"
|
|
862
|
+
},
|
|
839
863
|
{
|
|
840
864
|
id: "assignment",
|
|
841
865
|
// A credential name, `:`, `=` or `=>`, and its whole value: quoted at any
|
|
@@ -1056,13 +1080,16 @@ const tokenCounterKeys: ReadonlySet<string> = new Set([
|
|
|
1056
1080
|
])
|
|
1057
1081
|
|
|
1058
1082
|
/**
|
|
1059
|
-
*
|
|
1060
|
-
*
|
|
1061
|
-
*
|
|
1083
|
+
* Any name ending in a plural `tokens` holds a count too, the rule the textual
|
|
1084
|
+
* pass applies in {@link namesCredential}: `Envelope.budget.tokens` is the
|
|
1085
|
+
* run's token ceiling, and `usage.cacheWriteTokens`, `maxTokens`, and
|
|
1086
|
+
* `contextWindowTokens` are accounting; redacting them erased every journaled
|
|
1087
|
+
* budget and cache-write count (#3846). A bare singular `token` stays bearer
|
|
1088
|
+
* material even when it is numeric.
|
|
1062
1089
|
*/
|
|
1063
1090
|
const isTokenCount = (key: string, value: unknown): boolean =>
|
|
1064
1091
|
typeof value === "number" && Number.isSafeInteger(value) && value >= 0 &&
|
|
1065
|
-
(tokenCounterKeys.has(canonicalKey(key)) ||
|
|
1092
|
+
(tokenCounterKeys.has(canonicalKey(key)) || /tokens$/i.test(key))
|
|
1066
1093
|
|
|
1067
1094
|
/**
|
|
1068
1095
|
* Whether a field name names a credential.
|