@cendor/acttrace 0.2.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/LICENSE +201 -0
- package/README.md +79 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/detectors.d.ts +69 -0
- package/dist/detectors.d.ts.map +1 -0
- package/dist/detectors.js +378 -0
- package/dist/detectors.js.map +1 -0
- package/dist/guard.d.ts +36 -0
- package/dist/guard.d.ts.map +1 -0
- package/dist/guard.js +124 -0
- package/dist/guard.js.map +1 -0
- package/dist/hash.d.ts +7 -0
- package/dist/hash.d.ts.map +1 -0
- package/dist/hash.js +32 -0
- package/dist/hash.js.map +1 -0
- package/dist/index.d.ts +145 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +741 -0
- package/dist/index.js.map +1 -0
- package/dist/ner.d.ts +16 -0
- package/dist/ner.d.ts.map +1 -0
- package/dist/ner.js +21 -0
- package/dist/ner.js.map +1 -0
- package/dist/packs.d.ts +31 -0
- package/dist/packs.d.ts.map +1 -0
- package/dist/packs.js +113 -0
- package/dist/packs.js.map +1 -0
- package/dist/policy.d.ts +58 -0
- package/dist/policy.d.ts.map +1 -0
- package/dist/policy.js +119 -0
- package/dist/policy.js.map +1 -0
- package/dist/pyjson.d.ts +33 -0
- package/dist/pyjson.d.ts.map +1 -0
- package/dist/pyjson.js +250 -0
- package/dist/pyjson.js.map +1 -0
- package/dist/storage.d.ts +17 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +71 -0
- package/dist/storage.js.map +1 -0
- package/package.json +46 -0
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Offline, deterministic sensitive-data detectors for `@cendor/acttrace` — the TS port of
|
|
3
|
+
* `cendor.acttrace.detectors`.
|
|
4
|
+
*
|
|
5
|
+
* A {@link Detector} is a labelled regex plus an optional checksum/format **validator** that gates
|
|
6
|
+
* loose matches (Luhn for cards, mod-97 for IBANs, Verhoeff for Aadhaar, ABA for US routing numbers,
|
|
7
|
+
* range checks for SSNs). {@link DETECTORS} is the single source of truth for both scanning and
|
|
8
|
+
* redaction, so the built-in `default_redactor` is rebuilt from it and the original six categories
|
|
9
|
+
* still scrub byte-for-byte.
|
|
10
|
+
*
|
|
11
|
+
* Everything here is **local-first**: regex + arithmetic, no network, no model, no account. The
|
|
12
|
+
* registry is ordered original-six-first (`email` → `bearer_token`) so redaction application order —
|
|
13
|
+
* and therefore output — is unchanged for pre-existing payloads.
|
|
14
|
+
*
|
|
15
|
+
* Regex porting notes (vs Python `re`): the `u` flag is intentionally OFF so `\d`/`\w`/`\b` keep
|
|
16
|
+
* ASCII semantics; `i` mirrors `re.IGNORECASE`; `g` is used for finditer/scan and replace.
|
|
17
|
+
*/
|
|
18
|
+
/** What a scrubbed span is replaced with. Kept identical to the original redactor's token. */
|
|
19
|
+
export const REDACTED = '<redacted>';
|
|
20
|
+
// --------------------------------------------------------------------------- validators
|
|
21
|
+
function digits(s) {
|
|
22
|
+
const out = [];
|
|
23
|
+
for (const c of s) {
|
|
24
|
+
if (c >= '0' && c <= '9')
|
|
25
|
+
out.push(c.charCodeAt(0) - 48);
|
|
26
|
+
}
|
|
27
|
+
return out;
|
|
28
|
+
}
|
|
29
|
+
/** Luhn (mod-10) check for a 13–19 digit payment card number. */
|
|
30
|
+
export function luhn(number) {
|
|
31
|
+
const d = digits(number);
|
|
32
|
+
if (!(d.length >= 13 && d.length <= 19))
|
|
33
|
+
return false;
|
|
34
|
+
let total = 0;
|
|
35
|
+
const rev = [...d].reverse();
|
|
36
|
+
for (let i = 0; i < rev.length; i++) {
|
|
37
|
+
let digit = rev[i];
|
|
38
|
+
if (i % 2 === 1) {
|
|
39
|
+
digit *= 2;
|
|
40
|
+
if (digit > 9)
|
|
41
|
+
digit -= 9;
|
|
42
|
+
}
|
|
43
|
+
total += digit;
|
|
44
|
+
}
|
|
45
|
+
return total % 10 === 0;
|
|
46
|
+
}
|
|
47
|
+
/** ISO 13616 IBAN check (mod-97 == 1) after the country/check-digit rearrangement. */
|
|
48
|
+
export function ibanMod97(iban) {
|
|
49
|
+
const s = iban.replace(/\s+/g, '').toUpperCase();
|
|
50
|
+
if (!/^[A-Z]{2}\d{2}[A-Z0-9]{11,30}$/.test(s))
|
|
51
|
+
return false;
|
|
52
|
+
const rearranged = s.slice(4) + s.slice(0, 4);
|
|
53
|
+
let numeric = '';
|
|
54
|
+
for (const c of rearranged) {
|
|
55
|
+
// int(c, 36): '0'-'9' -> 0-9, 'A'-'Z' -> 10-35.
|
|
56
|
+
numeric += c >= '0' && c <= '9' ? c : String(c.charCodeAt(0) - 55);
|
|
57
|
+
}
|
|
58
|
+
return BigInt(numeric) % 97n === 1n;
|
|
59
|
+
}
|
|
60
|
+
// Verhoeff dihedral-group tables (used by the Aadhaar locale pack).
|
|
61
|
+
const VERHOEFF_D = [
|
|
62
|
+
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
|
|
63
|
+
[1, 2, 3, 4, 0, 6, 7, 8, 9, 5],
|
|
64
|
+
[2, 3, 4, 0, 1, 7, 8, 9, 5, 6],
|
|
65
|
+
[3, 4, 0, 1, 2, 8, 9, 5, 6, 7],
|
|
66
|
+
[4, 0, 1, 2, 3, 9, 5, 6, 7, 8],
|
|
67
|
+
[5, 9, 8, 7, 6, 0, 4, 3, 2, 1],
|
|
68
|
+
[6, 5, 9, 8, 7, 1, 0, 4, 3, 2],
|
|
69
|
+
[7, 6, 5, 9, 8, 2, 1, 0, 4, 3],
|
|
70
|
+
[8, 7, 6, 5, 9, 3, 2, 1, 0, 4],
|
|
71
|
+
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0],
|
|
72
|
+
];
|
|
73
|
+
const VERHOEFF_P = [
|
|
74
|
+
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
|
|
75
|
+
[1, 5, 7, 6, 2, 8, 3, 0, 9, 4],
|
|
76
|
+
[5, 8, 0, 3, 7, 9, 6, 1, 4, 2],
|
|
77
|
+
[8, 9, 1, 6, 0, 4, 3, 5, 2, 7],
|
|
78
|
+
[9, 4, 5, 3, 1, 2, 6, 8, 7, 0],
|
|
79
|
+
[4, 2, 8, 6, 5, 7, 3, 9, 0, 1],
|
|
80
|
+
[2, 7, 9, 3, 8, 0, 6, 4, 1, 5],
|
|
81
|
+
[7, 0, 4, 6, 9, 1, 3, 2, 5, 8],
|
|
82
|
+
];
|
|
83
|
+
/** Verhoeff checksum (used for India's Aadhaar); true when the trailing digit checks out. */
|
|
84
|
+
export function verhoeff(number) {
|
|
85
|
+
const d = digits(number);
|
|
86
|
+
let c = 0;
|
|
87
|
+
const rev = [...d].reverse();
|
|
88
|
+
for (let i = 0; i < rev.length; i++) {
|
|
89
|
+
c = VERHOEFF_D[c][VERHOEFF_P[i % 8][rev[i]]];
|
|
90
|
+
}
|
|
91
|
+
return c === 0;
|
|
92
|
+
}
|
|
93
|
+
/** ABA routing-transit checksum for a 9-digit US routing number. */
|
|
94
|
+
export function abaValid(number) {
|
|
95
|
+
const d = digits(number);
|
|
96
|
+
if (d.length !== 9)
|
|
97
|
+
return false;
|
|
98
|
+
const checksum = 3 * (d[0] + d[3] + d[6]) + 7 * (d[1] + d[4] + d[7]) + (d[2] + d[5] + d[8]);
|
|
99
|
+
return checksum % 10 === 0;
|
|
100
|
+
}
|
|
101
|
+
/** Reject structurally-invalid US SSNs (area 000/666/900-999, group 00, serial 0000). */
|
|
102
|
+
export function ssnValid(ssn) {
|
|
103
|
+
const d = digits(ssn);
|
|
104
|
+
if (d.length !== 9)
|
|
105
|
+
return false;
|
|
106
|
+
const area = d[0] * 100 + d[1] * 10 + d[2];
|
|
107
|
+
const group = d[3] * 10 + d[4];
|
|
108
|
+
const serial = d[5] * 1000 + d[6] * 100 + d[7] * 10 + d[8];
|
|
109
|
+
if (area === 0 || area === 666 || area >= 900)
|
|
110
|
+
return false;
|
|
111
|
+
return group !== 0 && serial !== 0;
|
|
112
|
+
}
|
|
113
|
+
/** A candidate phone number is plausible when it carries 9–15 significant digits. */
|
|
114
|
+
export function phoneValid(s) {
|
|
115
|
+
const n = s.replace(/\D/g, '').length;
|
|
116
|
+
return n >= 9 && n <= 15;
|
|
117
|
+
}
|
|
118
|
+
// ISO 3166-1 alpha-2 codes, used to gate SWIFT/BIC (chars 5–6 are the country) so an arbitrary
|
|
119
|
+
// 8-letter uppercase token isn't mistaken for a bank code.
|
|
120
|
+
const ISO_ALPHA2 = new Set(('AD AE AF AG AI AL AM AO AQ AR AS AT AU AW AX AZ BA BB BD BE BF BG BH BI BJ BL BM BN BO BQ ' +
|
|
121
|
+
'BR BS BT BV BW BY BZ CA CC CD CF CG CH CI CK CL CM CN CO CR CU CV CW CX CY CZ DE DJ DK DM ' +
|
|
122
|
+
'DO DZ EC EE EG EH ER ES ET FI FJ FK FM FO FR GA GB GD GE GF GG GH GI GL GM GN GP GQ GR GS ' +
|
|
123
|
+
'GT GU GW GY HK HM HN HR HT HU ID IE IL IM IN IO IQ IR IS IT JE JM JO JP KE KG KH KI KM KN ' +
|
|
124
|
+
'KP KR KW KY KZ LA LB LC LI LK LR LS LT LU LV LY MA MC MD ME MF MG MH MK ML MM MN MO MP MQ ' +
|
|
125
|
+
'MR MS MT MU MV MW MX MY MZ NA NC NE NF NG NI NL NO NP NR NU NZ OM PA PE PF PG PH PK PL PM ' +
|
|
126
|
+
'PN PR PS PT PW PY QA RE RO RS RU RW SA SB SC SD SE SG SH SI SJ SK SL SM SN SO SR SS ST SV ' +
|
|
127
|
+
'SX SY SZ TC TD TF TG TH TJ TK TL TM TN TO TR TT TV TW TZ UA UG UM US UY UZ VA VC VE VG VI ' +
|
|
128
|
+
'VN VU WF WS YE YT ZA ZM ZW').split(' '));
|
|
129
|
+
/** Structural SWIFT/BIC check: 8 or 11 chars with a valid ISO-3166 country code at 5–6. */
|
|
130
|
+
export function bicValid(s) {
|
|
131
|
+
return (s.length === 8 || s.length === 11) && ISO_ALPHA2.has(s.slice(4, 6));
|
|
132
|
+
}
|
|
133
|
+
// --------------------------------------------------------------------------- registry
|
|
134
|
+
/** Compile a pattern (always global; add `i` for IGNORECASE). No `u` flag — ASCII class semantics. */
|
|
135
|
+
function c(pattern, ignoreCase = false) {
|
|
136
|
+
return new RegExp(pattern, ignoreCase ? 'gi' : 'g');
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* The built-in detectors. Ordered original-six-first so redaction output is byte-identical for
|
|
140
|
+
* pre-existing payloads. `registerDetector` appends to this list (custom detectors run last).
|
|
141
|
+
*/
|
|
142
|
+
export const DETECTORS = [
|
|
143
|
+
// -- the original six (order preserved; email first) ------------------------------------------
|
|
144
|
+
{
|
|
145
|
+
category: 'email',
|
|
146
|
+
group: 'pii',
|
|
147
|
+
severity: 'warning',
|
|
148
|
+
pattern: c('\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}\\b'),
|
|
149
|
+
},
|
|
150
|
+
// openai/anthropic sk- keys incl. the hyphenated modern forms (sk-ant-…, sk-proj-…) + legacy
|
|
151
|
+
{
|
|
152
|
+
category: 'api_key',
|
|
153
|
+
group: 'secret',
|
|
154
|
+
severity: 'critical',
|
|
155
|
+
pattern: c('\\bsk-[A-Za-z0-9_-]{8,}'),
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
category: 'aws_key',
|
|
159
|
+
group: 'secret',
|
|
160
|
+
severity: 'critical',
|
|
161
|
+
pattern: c('\\bAKIA[0-9A-Z]{16}\\b'),
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
category: 'google_api_key',
|
|
165
|
+
group: 'secret',
|
|
166
|
+
severity: 'critical',
|
|
167
|
+
pattern: c('\\bAIza[0-9A-Za-z_-]{35}\\b'),
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
category: 'jwt',
|
|
171
|
+
group: 'secret',
|
|
172
|
+
severity: 'critical',
|
|
173
|
+
pattern: c('\\beyJ[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}'),
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
category: 'bearer_token',
|
|
177
|
+
group: 'secret',
|
|
178
|
+
severity: 'critical',
|
|
179
|
+
pattern: c('\\b[Bb]earer\\s+[A-Za-z0-9._-]+\\b'),
|
|
180
|
+
},
|
|
181
|
+
// -- additional secrets ----------------------------------------------------------------------
|
|
182
|
+
{
|
|
183
|
+
category: 'github_token',
|
|
184
|
+
group: 'secret',
|
|
185
|
+
severity: 'critical',
|
|
186
|
+
pattern: c('\\bgh[pousr]_[A-Za-z0-9]{36,}\\b'),
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
category: 'slack_token',
|
|
190
|
+
group: 'secret',
|
|
191
|
+
severity: 'critical',
|
|
192
|
+
pattern: c('\\bxox[baprs]-[A-Za-z0-9-]{10,}\\b'),
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
category: 'private_key',
|
|
196
|
+
group: 'secret',
|
|
197
|
+
severity: 'critical',
|
|
198
|
+
pattern: c('-----BEGIN (?:[A-Z0-9 ]+ )?PRIVATE KEY-----'),
|
|
199
|
+
},
|
|
200
|
+
// -- free-text credentials -------------------------------------------------------------------
|
|
201
|
+
{
|
|
202
|
+
category: 'password',
|
|
203
|
+
group: 'credential',
|
|
204
|
+
severity: 'critical',
|
|
205
|
+
pattern: c('\\b(?:password|passphrase|passwd|pwd)\\b\\s*(?:is|:|=)\\s*\\S+', true),
|
|
206
|
+
},
|
|
207
|
+
// -- financial (validator-gated) -------------------------------------------------------------
|
|
208
|
+
{
|
|
209
|
+
category: 'credit_card',
|
|
210
|
+
group: 'financial',
|
|
211
|
+
severity: 'critical',
|
|
212
|
+
pattern: c('\\b\\d(?:[ -]?\\d){12,18}\\b'),
|
|
213
|
+
validator: luhn,
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
category: 'iban',
|
|
217
|
+
group: 'financial',
|
|
218
|
+
severity: 'critical',
|
|
219
|
+
pattern: c('\\b[A-Z]{2}\\d{2}[A-Z0-9]{11,30}\\b'),
|
|
220
|
+
validator: ibanMod97,
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
category: 'us_routing',
|
|
224
|
+
group: 'financial',
|
|
225
|
+
severity: 'critical',
|
|
226
|
+
pattern: c('\\b\\d{9}\\b'),
|
|
227
|
+
validator: abaValid,
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
category: 'swift_bic',
|
|
231
|
+
group: 'financial',
|
|
232
|
+
severity: 'critical',
|
|
233
|
+
pattern: c('\\b[A-Z]{4}[A-Z]{2}[A-Z0-9]{2}(?:[A-Z0-9]{3})?\\b'),
|
|
234
|
+
validator: bicValid,
|
|
235
|
+
},
|
|
236
|
+
// -- government IDs (validator-gated) --------------------------------------------------------
|
|
237
|
+
{
|
|
238
|
+
category: 'us_ssn',
|
|
239
|
+
group: 'gov_id',
|
|
240
|
+
severity: 'critical',
|
|
241
|
+
pattern: c('\\b\\d{3}-\\d{2}-\\d{4}\\b'),
|
|
242
|
+
validator: ssnValid,
|
|
243
|
+
},
|
|
244
|
+
// -- remaining PII ---------------------------------------------------------------------------
|
|
245
|
+
{
|
|
246
|
+
category: 'phone',
|
|
247
|
+
group: 'pii',
|
|
248
|
+
severity: 'warning',
|
|
249
|
+
pattern: c('(?<!\\w)(?:\\+?1[ .\\-]?)?(?:\\(\\d{3}\\)[ .\\-]?|\\d{3}[ .\\-])\\d{3}[ .\\-]\\d{4}(?!\\d)' +
|
|
250
|
+
'|(?<!\\w)\\+\\d{9,15}(?!\\d)'),
|
|
251
|
+
validator: phoneValid,
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
category: 'ipv4',
|
|
255
|
+
group: 'pii',
|
|
256
|
+
severity: 'warning',
|
|
257
|
+
pattern: c('\\b(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)\\.){3}' +
|
|
258
|
+
'(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)\\b'),
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
category: 'ipv6',
|
|
262
|
+
group: 'pii',
|
|
263
|
+
severity: 'warning',
|
|
264
|
+
pattern: c('\\b(?:[A-Fa-f0-9]{1,4}:){7}[A-Fa-f0-9]{1,4}\\b' +
|
|
265
|
+
'|\\b(?:[A-Fa-f0-9]{1,4}:){1,7}:(?:[A-Fa-f0-9]{1,4}\\b)?'),
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
category: 'mac_address',
|
|
269
|
+
group: 'pii',
|
|
270
|
+
severity: 'warning',
|
|
271
|
+
pattern: c('\\b(?:[0-9A-Fa-f]{2}[:-]){5}[0-9A-Fa-f]{2}\\b'),
|
|
272
|
+
},
|
|
273
|
+
// -- GDPR Art.9 special categories (best-effort keyword lexicon) -----------------------------
|
|
274
|
+
{
|
|
275
|
+
category: 'special_category',
|
|
276
|
+
group: 'special_category',
|
|
277
|
+
severity: 'warning',
|
|
278
|
+
pattern: c('\\b(?:diagnos(?:is|es|ed)?|hiv|pregnan(?:t|cy)|disab(?:led|ility)|biometric|' +
|
|
279
|
+
'fingerprints?|genetic|ethnicity|religio(?:n|us))\\b', true),
|
|
280
|
+
},
|
|
281
|
+
];
|
|
282
|
+
/** Add a custom {@link Detector} to the global registry (it runs after the built-ins). */
|
|
283
|
+
export function registerDetector(detector) {
|
|
284
|
+
DETECTORS.push(detector);
|
|
285
|
+
}
|
|
286
|
+
/** A copy of the active detector registry (built-ins plus anything registered). */
|
|
287
|
+
export function detectors() {
|
|
288
|
+
return [...DETECTORS];
|
|
289
|
+
}
|
|
290
|
+
/** The group a category belongs to per the active registry (`null` if unknown). */
|
|
291
|
+
export function groupOf(category) {
|
|
292
|
+
for (const d of DETECTORS) {
|
|
293
|
+
if (d.category === category)
|
|
294
|
+
return d.group;
|
|
295
|
+
}
|
|
296
|
+
return null;
|
|
297
|
+
}
|
|
298
|
+
// --------------------------------------------------------------------------- scan / scrub
|
|
299
|
+
/** A plain `{}`-shaped object (a JSON dict), not a wrapper instance like `PyFloat` or a Date. */
|
|
300
|
+
function isPlainObject(o) {
|
|
301
|
+
if (o === null || typeof o !== 'object')
|
|
302
|
+
return false;
|
|
303
|
+
const proto = Object.getPrototypeOf(o);
|
|
304
|
+
return proto === Object.prototype || proto === null;
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Walk `obj` (str/dict/list) and count validated matches per category. Returns an insertion-ordered
|
|
308
|
+
* map `category -> [detector, occurrences]` accumulated across the walk. Never returns raw values.
|
|
309
|
+
*/
|
|
310
|
+
export function scanCounts(obj) {
|
|
311
|
+
const counts = new Map();
|
|
312
|
+
const walk = (o) => {
|
|
313
|
+
if (typeof o === 'string') {
|
|
314
|
+
for (const det of DETECTORS) {
|
|
315
|
+
let n = 0;
|
|
316
|
+
for (const match of o.matchAll(det.pattern)) {
|
|
317
|
+
const value = match[0];
|
|
318
|
+
if (det.validator === undefined || det.validator(value))
|
|
319
|
+
n += 1;
|
|
320
|
+
}
|
|
321
|
+
if (n) {
|
|
322
|
+
const slot = counts.get(det.category);
|
|
323
|
+
if (slot === undefined)
|
|
324
|
+
counts.set(det.category, [det, n]);
|
|
325
|
+
else
|
|
326
|
+
slot[1] += n;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
else if (Array.isArray(o)) {
|
|
331
|
+
for (const v of o)
|
|
332
|
+
walk(v);
|
|
333
|
+
}
|
|
334
|
+
else if (isPlainObject(o)) {
|
|
335
|
+
for (const v of Object.values(o))
|
|
336
|
+
walk(v);
|
|
337
|
+
}
|
|
338
|
+
};
|
|
339
|
+
walk(obj);
|
|
340
|
+
return counts;
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Return a copy of `obj` with every span matching a category in `categories` replaced. Applies
|
|
344
|
+
* detectors in **registry order** (original six first), so output is byte-identical to the historical
|
|
345
|
+
* redactor. Validator-gated detectors only scrub the spans that actually validate.
|
|
346
|
+
*/
|
|
347
|
+
export function scrub(obj, categories) {
|
|
348
|
+
const wanted = new Set(categories);
|
|
349
|
+
const active = DETECTORS.filter((d) => wanted.has(d.category));
|
|
350
|
+
if (active.length === 0)
|
|
351
|
+
return obj;
|
|
352
|
+
const subs = active.map((det) => {
|
|
353
|
+
const validator = det.validator;
|
|
354
|
+
if (validator === undefined)
|
|
355
|
+
return [det.pattern, () => REDACTED];
|
|
356
|
+
return [det.pattern, (m) => (validator(m) ? REDACTED : m)];
|
|
357
|
+
});
|
|
358
|
+
const go = (o) => {
|
|
359
|
+
if (typeof o === 'string') {
|
|
360
|
+
let out = o;
|
|
361
|
+
for (const [pattern, repl] of subs) {
|
|
362
|
+
out = out.replace(pattern, (m) => repl(m));
|
|
363
|
+
}
|
|
364
|
+
return out;
|
|
365
|
+
}
|
|
366
|
+
if (Array.isArray(o))
|
|
367
|
+
return o.map(go);
|
|
368
|
+
if (isPlainObject(o)) {
|
|
369
|
+
const result = {};
|
|
370
|
+
for (const [k, v] of Object.entries(o))
|
|
371
|
+
result[k] = go(v);
|
|
372
|
+
return result;
|
|
373
|
+
}
|
|
374
|
+
return o;
|
|
375
|
+
};
|
|
376
|
+
return go(obj);
|
|
377
|
+
}
|
|
378
|
+
//# sourceMappingURL=detectors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detectors.js","sourceRoot":"","sources":["../src/detectors.ts"],"names":[],"mappings":"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AC9B,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;CAC/B,CAAC;AACF,MAAM,UAAU,GAAmC;IACjD,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAA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"}
|
package/dist/guard.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `guard()` — a batteries-included enforcement callable for `@cendor/core`'s interceptor seam. The
|
|
3
|
+
* TS port of `cendor.acttrace.guard`.
|
|
4
|
+
*
|
|
5
|
+
* The recorder/enforcer split stays intact: acttrace still only *records*. `guard()` returns a plain
|
|
6
|
+
* callable you install via `addInterceptor` — it is core that stops the call. Per call, the active
|
|
7
|
+
* {@link Policy} resolves each detected category to an action:
|
|
8
|
+
*
|
|
9
|
+
* - **block** → record `policy_flag(action="blocked")` → **throw** (the call never runs).
|
|
10
|
+
* - **redact** → scrub the outbound messages via `Reroute(messages=…)` so the *provider* receives
|
|
11
|
+
* cleaned content, record `action="redacted"` → proceed. Tools have no message-rewrite seam, so a
|
|
12
|
+
* redact on tool arguments stays record-only.
|
|
13
|
+
* - **flag** → record `policy_flag(action="flagged")` → proceed.
|
|
14
|
+
* - nothing → proceed untouched.
|
|
15
|
+
*/
|
|
16
|
+
import type { AuditLog } from './index.js';
|
|
17
|
+
import { type Finding, Policy } from './policy.js';
|
|
18
|
+
/**
|
|
19
|
+
* Raised by a {@link guard} to block an outbound call whose content a policy forbids. Carries the
|
|
20
|
+
* offending {@link Finding} list on `findings` (categories and counts only — never raw values).
|
|
21
|
+
*/
|
|
22
|
+
export declare class PolicyViolation extends Error {
|
|
23
|
+
findings: Finding[];
|
|
24
|
+
constructor(message?: string, findings?: Finding[] | null);
|
|
25
|
+
}
|
|
26
|
+
/** An exception class (called with a message) or a factory `findings -> Error`. */
|
|
27
|
+
export type OnBlock = (new (message: string) => Error) | ((findings: Finding[]) => Error);
|
|
28
|
+
/**
|
|
29
|
+
* Return a pre-call interceptor that enforces `policy` and records refusals via `audit`. Install it
|
|
30
|
+
* on core's seam via `addInterceptor(guard(Policy.gdpr(), log))`.
|
|
31
|
+
*
|
|
32
|
+
* Note that `Policy.default()` never blocks — use `Policy.gdpr()` / `pci()` / `strict()` (or a custom
|
|
33
|
+
* policy) to make a category `block`. `audit` is optional — without it the guard still enforces.
|
|
34
|
+
*/
|
|
35
|
+
export declare function guard(policy?: Policy | null, audit?: AuditLog | null, onBlock?: OnBlock): (call: unknown) => unknown;
|
|
36
|
+
//# sourceMappingURL=guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guard.d.ts","sourceRoot":"","sources":["../src/guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,EAAQ,MAAM,aAAa,CAAC;AAKzD;;;GAGG;AACH,qBAAa,eAAgB,SAAQ,KAAK;IACxC,QAAQ,EAAE,OAAO,EAAE,CAAC;gBACR,OAAO,SAAqB,EAAE,QAAQ,GAAE,OAAO,EAAE,GAAG,IAAW;CAK5E;AAED,mFAAmF;AACnF,MAAM,MAAM,OAAO,GAAG,CAAC,KAAK,OAAO,EAAE,MAAM,KAAK,KAAK,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,KAAK,CAAC,CAAC;AA0C1F;;;;;;GAMG;AACH,wBAAgB,KAAK,CACnB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,EACtB,KAAK,CAAC,EAAE,QAAQ,GAAG,IAAI,EACvB,OAAO,GAAE,OAAyB,GACjC,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,CA+C5B"}
|
package/dist/guard.js
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `guard()` — a batteries-included enforcement callable for `@cendor/core`'s interceptor seam. The
|
|
3
|
+
* TS port of `cendor.acttrace.guard`.
|
|
4
|
+
*
|
|
5
|
+
* The recorder/enforcer split stays intact: acttrace still only *records*. `guard()` returns a plain
|
|
6
|
+
* callable you install via `addInterceptor` — it is core that stops the call. Per call, the active
|
|
7
|
+
* {@link Policy} resolves each detected category to an action:
|
|
8
|
+
*
|
|
9
|
+
* - **block** → record `policy_flag(action="blocked")` → **throw** (the call never runs).
|
|
10
|
+
* - **redact** → scrub the outbound messages via `Reroute(messages=…)` so the *provider* receives
|
|
11
|
+
* cleaned content, record `action="redacted"` → proceed. Tools have no message-rewrite seam, so a
|
|
12
|
+
* redact on tool arguments stays record-only.
|
|
13
|
+
* - **flag** → record `policy_flag(action="flagged")` → proceed.
|
|
14
|
+
* - nothing → proceed untouched.
|
|
15
|
+
*/
|
|
16
|
+
import { LLMCall, MISS, Reroute, ToolCall } from '@cendor/core';
|
|
17
|
+
import { scrub } from './detectors.js';
|
|
18
|
+
import { Policy, scan } from './policy.js';
|
|
19
|
+
/** Severity ordering, so a grouped flag carries the strongest severity in the group. */
|
|
20
|
+
const SEVERITY_RANK = { info: 0, warning: 1, critical: 2 };
|
|
21
|
+
/**
|
|
22
|
+
* Raised by a {@link guard} to block an outbound call whose content a policy forbids. Carries the
|
|
23
|
+
* offending {@link Finding} list on `findings` (categories and counts only — never raw values).
|
|
24
|
+
*/
|
|
25
|
+
export class PolicyViolation extends Error {
|
|
26
|
+
findings;
|
|
27
|
+
constructor(message = 'policy violation', findings = null) {
|
|
28
|
+
super(message);
|
|
29
|
+
this.name = 'PolicyViolation';
|
|
30
|
+
this.findings = findings ?? [];
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/** The caller-supplied content of a call to scan (messages for LLMs, arguments for tools). */
|
|
34
|
+
function content(call) {
|
|
35
|
+
if (call instanceof LLMCall)
|
|
36
|
+
return call.messages;
|
|
37
|
+
if (call instanceof ToolCall)
|
|
38
|
+
return call.arguments;
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
function maxSeverity(findings) {
|
|
42
|
+
let best = 'warning';
|
|
43
|
+
let bestRank = -1;
|
|
44
|
+
for (const f of findings) {
|
|
45
|
+
const rank = SEVERITY_RANK[f.severity] ?? 0;
|
|
46
|
+
if (rank > bestRank) {
|
|
47
|
+
bestRank = rank;
|
|
48
|
+
best = f.severity;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return best;
|
|
52
|
+
}
|
|
53
|
+
/** ES6-class detection: distinguishes an exception class from a `findings -> Error` factory. */
|
|
54
|
+
function isClass(fn) {
|
|
55
|
+
return typeof fn === 'function' && /^class[\s{]/.test(Function.prototype.toString.call(fn));
|
|
56
|
+
}
|
|
57
|
+
function makeBlockException(onBlock, findings) {
|
|
58
|
+
const cats = [...new Set(findings.map((f) => f.category))].sort();
|
|
59
|
+
const message = `policy blocked outbound call: ${cats.join(', ')}`;
|
|
60
|
+
if (isClass(onBlock)) {
|
|
61
|
+
const exc = new onBlock(message);
|
|
62
|
+
try {
|
|
63
|
+
exc.findings = findings;
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
// exception type doesn't tolerate a findings attribute — ignore
|
|
67
|
+
}
|
|
68
|
+
return exc;
|
|
69
|
+
}
|
|
70
|
+
return onBlock(findings);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Return a pre-call interceptor that enforces `policy` and records refusals via `audit`. Install it
|
|
74
|
+
* on core's seam via `addInterceptor(guard(Policy.gdpr(), log))`.
|
|
75
|
+
*
|
|
76
|
+
* Note that `Policy.default()` never blocks — use `Policy.gdpr()` / `pci()` / `strict()` (or a custom
|
|
77
|
+
* policy) to make a category `block`. `audit` is optional — without it the guard still enforces.
|
|
78
|
+
*/
|
|
79
|
+
export function guard(policy, audit, onBlock = PolicyViolation) {
|
|
80
|
+
const p = policy ?? Policy.default();
|
|
81
|
+
const auditLog = audit ?? null;
|
|
82
|
+
const record = (action, findings, call, note = '') => {
|
|
83
|
+
if (auditLog === null)
|
|
84
|
+
return;
|
|
85
|
+
const cats = [...new Set(findings.map((f) => f.category))].sort();
|
|
86
|
+
const kind = call instanceof LLMCall ? 'llm_call' : 'tool_call';
|
|
87
|
+
let reason = `${action} ${cats.join(', ')} in outbound ${kind}`;
|
|
88
|
+
if (note)
|
|
89
|
+
reason = `${reason} (${note})`;
|
|
90
|
+
const severity = action === 'redacted' ? 'info' : maxSeverity(findings);
|
|
91
|
+
auditLog.flag(reason, { action, severity, data: cats, extra: { auto: true } });
|
|
92
|
+
};
|
|
93
|
+
return (call) => {
|
|
94
|
+
const c = content(call);
|
|
95
|
+
if (c === null)
|
|
96
|
+
return MISS;
|
|
97
|
+
const findings = scan(c, p);
|
|
98
|
+
if (findings.length === 0)
|
|
99
|
+
return MISS;
|
|
100
|
+
const blocked = findings.filter((f) => f.action === 'block');
|
|
101
|
+
const toRedact = findings.filter((f) => f.action === 'redact');
|
|
102
|
+
const flagged = findings.filter((f) => f.action === 'flag');
|
|
103
|
+
if (blocked.length > 0) {
|
|
104
|
+
record('blocked', blocked, call); // record the refusal *before* throwing
|
|
105
|
+
throw makeBlockException(onBlock, blocked);
|
|
106
|
+
}
|
|
107
|
+
if (flagged.length > 0) {
|
|
108
|
+
record('flagged', flagged, call);
|
|
109
|
+
}
|
|
110
|
+
if (toRedact.length > 0) {
|
|
111
|
+
if (call instanceof LLMCall) {
|
|
112
|
+
// Redact-before-send: scrub the outbound messages and reroute so the provider receives the
|
|
113
|
+
// cleaned content, then record that we did.
|
|
114
|
+
const cleaned = scrub(call.messages, new Set(toRedact.map((f) => f.category)));
|
|
115
|
+
record('redacted', toRedact, call);
|
|
116
|
+
return new Reroute({ messages: cleaned });
|
|
117
|
+
}
|
|
118
|
+
// Tools have no message-rewrite seam, so a redact on tool arguments stays record-only.
|
|
119
|
+
record('flagged', toRedact, call, 'redact-before-send applies to model calls; tool arguments unchanged');
|
|
120
|
+
}
|
|
121
|
+
return MISS;
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=guard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guard.js","sourceRoot":"","sources":["../src/guard.ts"],"names":[],"mappings":"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"}
|
package/dist/hash.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Lowercase-hex SHA-256 of the UTF-8 bytes of `text`. */
|
|
2
|
+
export declare function sha256Hex(text: string): string;
|
|
3
|
+
/** Lowercase-hex HMAC-SHA256 over the UTF-8 bytes of `text` under `key` (UTF-8 bytes of the passphrase). */
|
|
4
|
+
export declare function hmacSha256Hex(key: string | Uint8Array, text: string): string;
|
|
5
|
+
/** Constant-time string compare (both treated as UTF-8). Returns false on length mismatch. */
|
|
6
|
+
export declare function timingSafeEqualHex(a: string, b: string): boolean;
|
|
7
|
+
//# sourceMappingURL=hash.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../src/hash.ts"],"names":[],"mappings":"AA2BA,0DAA0D;AAC1D,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED,4GAA4G;AAC5G,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAE5E;AAED,8FAA8F;AAC9F,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAKhE"}
|
package/dist/hash.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Synchronous SHA-256 + HMAC-SHA256, via `node:crypto`. acttrace hashes/signs inside a synchronous
|
|
3
|
+
* bus subscriber (matching Python), so WebCrypto's async `subtle` is unusable. acttrace is a
|
|
4
|
+
* server-side governance library (signing keys never belong in a browser), so `node:crypto` is the
|
|
5
|
+
* correct dependency; it is also available in edge runtimes with `nodejs_compat`. Loaded via
|
|
6
|
+
* `createRequire` so importing the package does not force `node:crypto` into a browser bundle.
|
|
7
|
+
*/
|
|
8
|
+
import { createRequire } from 'node:module';
|
|
9
|
+
const require = createRequire(import.meta.url);
|
|
10
|
+
let cryptoMod;
|
|
11
|
+
function nodeCrypto() {
|
|
12
|
+
if (cryptoMod === undefined)
|
|
13
|
+
cryptoMod = require('node:crypto');
|
|
14
|
+
return cryptoMod;
|
|
15
|
+
}
|
|
16
|
+
/** Lowercase-hex SHA-256 of the UTF-8 bytes of `text`. */
|
|
17
|
+
export function sha256Hex(text) {
|
|
18
|
+
return nodeCrypto().createHash('sha256').update(text, 'utf8').digest('hex');
|
|
19
|
+
}
|
|
20
|
+
/** Lowercase-hex HMAC-SHA256 over the UTF-8 bytes of `text` under `key` (UTF-8 bytes of the passphrase). */
|
|
21
|
+
export function hmacSha256Hex(key, text) {
|
|
22
|
+
return nodeCrypto().createHmac('sha256', key).update(text, 'utf8').digest('hex');
|
|
23
|
+
}
|
|
24
|
+
/** Constant-time string compare (both treated as UTF-8). Returns false on length mismatch. */
|
|
25
|
+
export function timingSafeEqualHex(a, b) {
|
|
26
|
+
const ba = new TextEncoder().encode(a);
|
|
27
|
+
const bb = new TextEncoder().encode(b);
|
|
28
|
+
if (ba.length !== bb.length)
|
|
29
|
+
return false;
|
|
30
|
+
return nodeCrypto().timingSafeEqual(ba, bb);
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=hash.js.map
|
package/dist/hash.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hash.js","sourceRoot":"","sources":["../src/hash.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAY/C,IAAI,SAAiC,CAAC;AACtC,SAAS,UAAU;IACjB,IAAI,SAAS,KAAK,SAAS;QAAE,SAAS,GAAG,OAAO,CAAC,aAAa,CAAe,CAAC;IAC9E,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,0DAA0D;AAC1D,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,OAAO,UAAU,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,4GAA4G;AAC5G,MAAM,UAAU,aAAa,CAAC,GAAwB,EAAE,IAAY;IAClE,OAAO,UAAU,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACnF,CAAC;AAED,8FAA8F;AAC9F,MAAM,UAAU,kBAAkB,CAAC,CAAS,EAAE,CAAS;IACrD,MAAM,EAAE,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IACvC,MAAM,EAAE,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IACvC,IAAI,EAAE,CAAC,MAAM,KAAK,EAAE,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAC1C,OAAO,UAAU,EAAE,CAAC,eAAe,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;AAC9C,CAAC"}
|