@link-foundation/sensitive-data-sanitizer 0.18.0 → 0.19.1

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/docs/RULES.md ADDED
@@ -0,0 +1,405 @@
1
+ # Stable finding rule identifiers
2
+
3
+ Use keys from the exported frozen `builtInRules` list in `rules: {id: false}`.
4
+ Unknown ids fail with ERR_CONFIG. Credential and mixed encoded/scanner rules
5
+ require `allowCredentialDisable: true`. A disabled rule does not suppress
6
+ another rule's overlapping finding. Rules gate automatic built-in findings;
7
+ explicit findings and custom callbacks retain caller policy. See [API](API.md#rule-type-and-field-policy).
8
+
9
+ Regenerate with `node experiments/issue-118/generate-rule-catalog.mjs`.
10
+
11
+ - `age-context`
12
+ - `anthropic`
13
+ - `authorization`
14
+ - `aws`
15
+ - `birth-context`
16
+ - `birth-year`
17
+ - `booking-context`
18
+ - `booking-filename`
19
+ - `catalog/aws`
20
+ - `catalog/azure`
21
+ - `catalog/google`
22
+ - `cli-password`
23
+ - `context`
24
+ - `cookie`
25
+ - `databricks`
26
+ - `detect-secrets`
27
+ - `digitalocean`
28
+ - `discord`
29
+ - `document-age-unit`
30
+ - `document-at-employer`
31
+ - `document-bank-suffix`
32
+ - `document-birthday`
33
+ - `document-citizenship`
34
+ - `document-email-obfuscation`
35
+ - `document-email-spaces`
36
+ - `document-employer-dash`
37
+ - `document-employer-prefix`
38
+ - `document-industry`
39
+ - `document-introduction`
40
+ - `document-legal-lowercase`
41
+ - `document-local-phone`
42
+ - `document-messenger`
43
+ - `document-military-id`
44
+ - `document-mixed-name`
45
+ - `document-mobile-bare`
46
+ - `document-mobile-comma`
47
+ - `document-mobile-context`
48
+ - `document-msu`
49
+ - `document-patronymic`
50
+ - `document-person-cue`
51
+ - `document-personal-path`
52
+ - `document-phone`
53
+ - `document-phone-label`
54
+ - `document-propagation`
55
+ - `document-region`
56
+ - `document-resume-link`
57
+ - `document-reversed-role`
58
+ - `document-role`
59
+ - `document-role-employer`
60
+ - `document-school-context`
61
+ - `document-school-year`
62
+ - `document-share-link`
63
+ - `document-share-path`
64
+ - `document-social-link`
65
+ - `document-spaced-mobile`
66
+ - `document-street`
67
+ - `document-street-complete`
68
+ - `document-unfamiliar-name`
69
+ - `document-uppercase-initials`
70
+ - `document-vehicle-plate`
71
+ - `document-vin`
72
+ - `education-acronym`
73
+ - `education-bracket`
74
+ - `education-label`
75
+ - `education-named-acronym`
76
+ - `education-russian`
77
+ - `education-training`
78
+ - `education-type`
79
+ - `email`
80
+ - `employer-label`
81
+ - `employer-prose`
82
+ - `employer-years`
83
+ - `encoded`
84
+ - `encoded-engine`
85
+ - `encoded-limit`
86
+ - `entity-format`
87
+ - `entropy`
88
+ - `firebase`
89
+ - `gender-context`
90
+ - `github`
91
+ - `gitlab`
92
+ - `gitlab-runner`
93
+ - `gitleaks/1password-secret-key`
94
+ - `gitleaks/1password-service-account-token`
95
+ - `gitleaks/adafruit-api-key`
96
+ - `gitleaks/adobe-client-id`
97
+ - `gitleaks/adobe-client-secret`
98
+ - `gitleaks/age-secret-key`
99
+ - `gitleaks/airtable-api-key`
100
+ - `gitleaks/airtable-personnal-access-token`
101
+ - `gitleaks/algolia-api-key`
102
+ - `gitleaks/alibaba-access-key-id`
103
+ - `gitleaks/alibaba-secret-key`
104
+ - `gitleaks/anthropic-admin-api-key`
105
+ - `gitleaks/anthropic-api-key`
106
+ - `gitleaks/artifactory-api-key`
107
+ - `gitleaks/artifactory-reference-token`
108
+ - `gitleaks/asana-client-id`
109
+ - `gitleaks/asana-client-secret`
110
+ - `gitleaks/atlassian-api-token`
111
+ - `gitleaks/authress-service-client-access-key`
112
+ - `gitleaks/aws-access-token`
113
+ - `gitleaks/aws-amazon-bedrock-api-key-long-lived`
114
+ - `gitleaks/aws-amazon-bedrock-api-key-short-lived`
115
+ - `gitleaks/azure-ad-client-secret`
116
+ - `gitleaks/beamer-api-token`
117
+ - `gitleaks/bitbucket-client-id`
118
+ - `gitleaks/bitbucket-client-secret`
119
+ - `gitleaks/bittrex-access-key`
120
+ - `gitleaks/bittrex-secret-key`
121
+ - `gitleaks/cisco-meraki-api-key`
122
+ - `gitleaks/clickhouse-cloud-api-secret-key`
123
+ - `gitleaks/clojars-api-token`
124
+ - `gitleaks/cloudflare-api-key`
125
+ - `gitleaks/cloudflare-global-api-key`
126
+ - `gitleaks/cloudflare-origin-ca-key`
127
+ - `gitleaks/codecov-access-token`
128
+ - `gitleaks/cohere-api-token`
129
+ - `gitleaks/coinbase-access-token`
130
+ - `gitleaks/confluent-access-token`
131
+ - `gitleaks/confluent-secret-key`
132
+ - `gitleaks/contentful-delivery-api-token`
133
+ - `gitleaks/curl-auth-header`
134
+ - `gitleaks/curl-auth-user`
135
+ - `gitleaks/databricks-api-token`
136
+ - `gitleaks/datadog-access-token`
137
+ - `gitleaks/defined-networking-api-token`
138
+ - `gitleaks/digitalocean-access-token`
139
+ - `gitleaks/digitalocean-pat`
140
+ - `gitleaks/digitalocean-refresh-token`
141
+ - `gitleaks/discord-api-token`
142
+ - `gitleaks/discord-client-id`
143
+ - `gitleaks/discord-client-secret`
144
+ - `gitleaks/doppler-api-token`
145
+ - `gitleaks/droneci-access-token`
146
+ - `gitleaks/dropbox-api-token`
147
+ - `gitleaks/dropbox-long-lived-api-token`
148
+ - `gitleaks/dropbox-short-lived-api-token`
149
+ - `gitleaks/duffel-api-token`
150
+ - `gitleaks/dynatrace-api-token`
151
+ - `gitleaks/easypost-api-token`
152
+ - `gitleaks/easypost-test-api-token`
153
+ - `gitleaks/etsy-access-token`
154
+ - `gitleaks/facebook-access-token`
155
+ - `gitleaks/facebook-page-access-token`
156
+ - `gitleaks/facebook-secret`
157
+ - `gitleaks/fastly-api-token`
158
+ - `gitleaks/finicity-api-token`
159
+ - `gitleaks/finicity-client-secret`
160
+ - `gitleaks/finnhub-access-token`
161
+ - `gitleaks/flickr-access-token`
162
+ - `gitleaks/flutterwave-encryption-key`
163
+ - `gitleaks/flutterwave-public-key`
164
+ - `gitleaks/flutterwave-secret-key`
165
+ - `gitleaks/flyio-access-token`
166
+ - `gitleaks/frameio-api-token`
167
+ - `gitleaks/freemius-secret-key`
168
+ - `gitleaks/freshbooks-access-token`
169
+ - `gitleaks/gcp-api-key`
170
+ - `gitleaks/generic-api-key`
171
+ - `gitleaks/github-app-token`
172
+ - `gitleaks/github-fine-grained-pat`
173
+ - `gitleaks/github-oauth`
174
+ - `gitleaks/github-pat`
175
+ - `gitleaks/github-refresh-token`
176
+ - `gitleaks/gitlab-cicd-job-token`
177
+ - `gitleaks/gitlab-deploy-token`
178
+ - `gitleaks/gitlab-feature-flag-client-token`
179
+ - `gitleaks/gitlab-feed-token`
180
+ - `gitleaks/gitlab-incoming-mail-token`
181
+ - `gitleaks/gitlab-kubernetes-agent-token`
182
+ - `gitleaks/gitlab-oauth-app-secret`
183
+ - `gitleaks/gitlab-pat`
184
+ - `gitleaks/gitlab-pat-routable`
185
+ - `gitleaks/gitlab-ptt`
186
+ - `gitleaks/gitlab-rrt`
187
+ - `gitleaks/gitlab-runner-authentication-token`
188
+ - `gitleaks/gitlab-runner-authentication-token-routable`
189
+ - `gitleaks/gitlab-scim-token`
190
+ - `gitleaks/gitlab-session-cookie`
191
+ - `gitleaks/gitter-access-token`
192
+ - `gitleaks/gocardless-api-token`
193
+ - `gitleaks/grafana-api-key`
194
+ - `gitleaks/grafana-cloud-api-token`
195
+ - `gitleaks/grafana-service-account-token`
196
+ - `gitleaks/harness-api-key`
197
+ - `gitleaks/hashicorp-tf-api-token`
198
+ - `gitleaks/hashicorp-tf-password`
199
+ - `gitleaks/heroku-api-key`
200
+ - `gitleaks/heroku-api-key-v2`
201
+ - `gitleaks/hubspot-api-key`
202
+ - `gitleaks/huggingface-access-token`
203
+ - `gitleaks/huggingface-organization-api-token`
204
+ - `gitleaks/infracost-api-token`
205
+ - `gitleaks/intercom-api-key`
206
+ - `gitleaks/intra42-client-secret`
207
+ - `gitleaks/jfrog-api-key`
208
+ - `gitleaks/jfrog-identity-token`
209
+ - `gitleaks/jwt`
210
+ - `gitleaks/jwt-base64`
211
+ - `gitleaks/kraken-access-token`
212
+ - `gitleaks/kubernetes-secret-yaml`
213
+ - `gitleaks/kucoin-access-token`
214
+ - `gitleaks/kucoin-secret-key`
215
+ - `gitleaks/launchdarkly-access-token`
216
+ - `gitleaks/linear-api-key`
217
+ - `gitleaks/linear-client-secret`
218
+ - `gitleaks/linkedin-client-id`
219
+ - `gitleaks/linkedin-client-secret`
220
+ - `gitleaks/lob-api-key`
221
+ - `gitleaks/lob-pub-api-key`
222
+ - `gitleaks/looker-client-id`
223
+ - `gitleaks/looker-client-secret`
224
+ - `gitleaks/mailchimp-api-key`
225
+ - `gitleaks/mailgun-private-api-token`
226
+ - `gitleaks/mailgun-pub-key`
227
+ - `gitleaks/mailgun-signing-key`
228
+ - `gitleaks/mapbox-api-token`
229
+ - `gitleaks/mattermost-access-token`
230
+ - `gitleaks/maxmind-license-key`
231
+ - `gitleaks/messagebird-api-token`
232
+ - `gitleaks/messagebird-client-id`
233
+ - `gitleaks/microsoft-teams-webhook`
234
+ - `gitleaks/netlify-access-token`
235
+ - `gitleaks/new-relic-browser-api-token`
236
+ - `gitleaks/new-relic-insert-key`
237
+ - `gitleaks/new-relic-user-api-id`
238
+ - `gitleaks/new-relic-user-api-key`
239
+ - `gitleaks/notion-api-token`
240
+ - `gitleaks/npm-access-token`
241
+ - `gitleaks/nuget-config-password`
242
+ - `gitleaks/nytimes-access-token`
243
+ - `gitleaks/octopus-deploy-api-key`
244
+ - `gitleaks/okta-access-token`
245
+ - `gitleaks/openai-api-key`
246
+ - `gitleaks/openshift-user-token`
247
+ - `gitleaks/perplexity-api-key`
248
+ - `gitleaks/pkcs12-file`
249
+ - `gitleaks/plaid-api-token`
250
+ - `gitleaks/plaid-client-id`
251
+ - `gitleaks/plaid-secret-key`
252
+ - `gitleaks/planetscale-api-token`
253
+ - `gitleaks/planetscale-oauth-token`
254
+ - `gitleaks/planetscale-password`
255
+ - `gitleaks/postman-api-token`
256
+ - `gitleaks/prefect-api-token`
257
+ - `gitleaks/private-key`
258
+ - `gitleaks/privateai-api-token`
259
+ - `gitleaks/pulumi-api-token`
260
+ - `gitleaks/pypi-upload-token`
261
+ - `gitleaks/rapidapi-access-token`
262
+ - `gitleaks/readme-api-token`
263
+ - `gitleaks/rubygems-api-token`
264
+ - `gitleaks/scalingo-api-token`
265
+ - `gitleaks/sendbird-access-id`
266
+ - `gitleaks/sendbird-access-token`
267
+ - `gitleaks/sendgrid-api-token`
268
+ - `gitleaks/sendinblue-api-token`
269
+ - `gitleaks/sentry-access-token`
270
+ - `gitleaks/sentry-org-token`
271
+ - `gitleaks/sentry-user-token`
272
+ - `gitleaks/settlemint-application-access-token`
273
+ - `gitleaks/settlemint-personal-access-token`
274
+ - `gitleaks/settlemint-service-access-token`
275
+ - `gitleaks/shippo-api-token`
276
+ - `gitleaks/shopify-access-token`
277
+ - `gitleaks/shopify-custom-access-token`
278
+ - `gitleaks/shopify-private-app-access-token`
279
+ - `gitleaks/shopify-shared-secret`
280
+ - `gitleaks/sidekiq-secret`
281
+ - `gitleaks/sidekiq-sensitive-url`
282
+ - `gitleaks/slack-app-token`
283
+ - `gitleaks/slack-bot-token`
284
+ - `gitleaks/slack-config-access-token`
285
+ - `gitleaks/slack-config-refresh-token`
286
+ - `gitleaks/slack-legacy-bot-token`
287
+ - `gitleaks/slack-legacy-token`
288
+ - `gitleaks/slack-legacy-workspace-token`
289
+ - `gitleaks/slack-user-token`
290
+ - `gitleaks/slack-webhook-url`
291
+ - `gitleaks/snyk-api-token`
292
+ - `gitleaks/sonar-api-token`
293
+ - `gitleaks/sourcegraph-access-token`
294
+ - `gitleaks/square-access-token`
295
+ - `gitleaks/squarespace-access-token`
296
+ - `gitleaks/stripe-access-token`
297
+ - `gitleaks/sumologic-access-id`
298
+ - `gitleaks/sumologic-access-token`
299
+ - `gitleaks/telegram-bot-api-token`
300
+ - `gitleaks/travisci-access-token`
301
+ - `gitleaks/twilio-api-key`
302
+ - `gitleaks/twitch-api-token`
303
+ - `gitleaks/twitter-access-secret`
304
+ - `gitleaks/twitter-access-token`
305
+ - `gitleaks/twitter-api-key`
306
+ - `gitleaks/twitter-api-secret`
307
+ - `gitleaks/twitter-bearer-token`
308
+ - `gitleaks/typeform-api-token`
309
+ - `gitleaks/vault-batch-token`
310
+ - `gitleaks/vault-service-token`
311
+ - `gitleaks/yandex-access-token`
312
+ - `gitleaks/yandex-api-key`
313
+ - `gitleaks/yandex-aws-access-token`
314
+ - `gitleaks/zendesk-secret-key`
315
+ - `google`
316
+ - `grafana`
317
+ - `home-path`
318
+ - `huggingface`
319
+ - `iban-checksum`
320
+ - `identity-number`
321
+ - `international-phone`
322
+ - `ipv4`
323
+ - `ipv6`
324
+ - `jwt`
325
+ - `known-personal`
326
+ - `known-secret`
327
+ - `label`
328
+ - `linear`
329
+ - `location-gazetteer`
330
+ - `location-label`
331
+ - `location-residence`
332
+ - `luhn`
333
+ - `mac`
334
+ - `mailchimp`
335
+ - `messenger-handle`
336
+ - `messenger-label`
337
+ - `mrz`
338
+ - `name-case`
339
+ - `name-document`
340
+ - `name-gazetteer`
341
+ - `name-identity`
342
+ - `name-initials`
343
+ - `name-title`
344
+ - `name-variant`
345
+ - `national-format`
346
+ - `national-phone`
347
+ - `ner/offline`
348
+ - `netrc`
349
+ - `notion`
350
+ - `npm`
351
+ - `nuget`
352
+ - `numbered-school`
353
+ - `obfuscated-email`
354
+ - `openai`
355
+ - `organization-context`
356
+ - `organization-continuation`
357
+ - `organization-core`
358
+ - `organization-cue`
359
+ - `organization-duration`
360
+ - `organization-experience`
361
+ - `organization-experience-prose`
362
+ - `organization-group`
363
+ - `organization-group-cue`
364
+ - `organization-legal-form`
365
+ - `passport-format`
366
+ - `passport-issuer`
367
+ - `passport-series`
368
+ - `personal-profile-url`
369
+ - `phone-context`
370
+ - `postal-address`
371
+ - `postal-code`
372
+ - `presidio`
373
+ - `private-key`
374
+ - `profile-attribute`
375
+ - `profile-prose`
376
+ - `proper-name-prose`
377
+ - `putty-private-key`
378
+ - `pypi`
379
+ - `quoted-entropy`
380
+ - `residence-prose`
381
+ - `school-acronym-context`
382
+ - `secretlint`
383
+ - `sendgrid`
384
+ - `shopify`
385
+ - `slack`
386
+ - `square`
387
+ - `strict-age`
388
+ - `strict-attribute`
389
+ - `strict-date`
390
+ - `strict-number`
391
+ - `stripe`
392
+ - `tel-uri`
393
+ - `telegram`
394
+ - `ticket-context`
395
+ - `twilio`
396
+ - `url-userinfo`
397
+ - `us-ssn`
398
+ - `vault`
399
+ - `vercel`
400
+ - `visa-context`
401
+ - `vocabulary-cue`
402
+ - `vocabulary-role`
403
+ - `webhook`
404
+ - `wordpress`
405
+ - `yandex`
@@ -0,0 +1,23 @@
1
+ import { compileKnown, createSyncSanitizer } from '../src/index.js';
2
+
3
+ // Reuse caller-owned compilation in a synchronous logging hook.
4
+ const known = compileKnown([{ type: 'ORGANIZATION', value: 'Ромашка' }]);
5
+ const loggerPolicy = createSyncSanitizer({
6
+ profile: 'documents',
7
+ knownPersonal: known,
8
+ vocabulary: { roles: ['маркетолог'] },
9
+ structured: 'json',
10
+ allowedFields: ['level', 'msg'],
11
+ fields: { location: 'scan' },
12
+ transformations: { ORGANIZATION: () => 'PrivateCompany' },
13
+ });
14
+ console.log(
15
+ loggerPolicy.sanitize(
16
+ JSON.stringify({
17
+ level: 'info',
18
+ msg: 'работал в Ромашке',
19
+ privateNote: 'caller-private text',
20
+ count: 1,
21
+ })
22
+ ).text
23
+ );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@link-foundation/sensitive-data-sanitizer",
3
- "version": "0.18.0",
3
+ "version": "0.19.1",
4
4
  "description": "Offline sensitive-text sanitization with credential, multilingual personal-data and scanner union detection",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -25,7 +25,9 @@
25
25
  "README.md",
26
26
  "examples/shared-tool-logs.mjs",
27
27
  "examples/reversible-placeholders.mjs",
28
- "examples/prose-logs.mjs"
28
+ "examples/prose-logs.mjs",
29
+ "docs/RULES.md",
30
+ "examples/custom-log-policy.mjs"
29
31
  ],
30
32
  "exports": {
31
33
  ".": {
@@ -40,6 +42,10 @@
40
42
  "types": "./src/legacy.d.ts",
41
43
  "browser": "./src/arithmetic.js",
42
44
  "import": "./src/legacy.js"
45
+ },
46
+ "./ner": {
47
+ "types": "./src/ner.d.ts",
48
+ "import": "./src/ner.js"
43
49
  }
44
50
  },
45
51
  "scripts": {
@@ -96,6 +102,7 @@
96
102
  "devDependencies": {
97
103
  "@changesets/cli": "^3.0.3",
98
104
  "@eslint/js": "^10.0.1",
105
+ "@nlpjs/ner": "4.27.0",
99
106
  "browser-commander": "0.34.1",
100
107
  "cmd-shim": "^9.0.2",
101
108
  "command-stream": "2.6.0",
@@ -151,5 +158,13 @@
151
158
  },
152
159
  "overrides": {
153
160
  "minimatch@>=7 <11": "^11.0.5"
161
+ },
162
+ "peerDependencies": {
163
+ "@nlpjs/ner": "^4.27.0"
164
+ },
165
+ "peerDependenciesMeta": {
166
+ "@nlpjs/ner": {
167
+ "optional": true
168
+ }
154
169
  }
155
170
  }
@@ -0,0 +1,55 @@
1
+ import { failure } from './detection.js';
2
+ import { personalRegex } from './personal-variants.js';
3
+ import { projectText } from './projection.js';
4
+
5
+ // Caller-owned frozen arrays remain compatible with maps, streams and fakes.
6
+ // Weak keys allow the caller to release all values and compiled expressions.
7
+ const compiled = new WeakMap();
8
+ export const isCompiledKnown = (entries) => compiled.has(entries);
9
+ export const compiledPatterns = (entries) => compiled.get(entries)?.patterns;
10
+ export const projectedKnown = (entries) => compiled.get(entries)?.projected;
11
+
12
+ export function compileKnown(...lists) {
13
+ if (lists.some((list) => !Array.isArray(list))) {
14
+ throw failure('ERR_CONFIG');
15
+ }
16
+ const values = new Map();
17
+ for (const entry of lists.flat()) {
18
+ if (
19
+ !entry ||
20
+ typeof entry.value !== 'string' ||
21
+ !entry.value ||
22
+ !/^[A-Z][A-Z0-9_]{0,63}$/.test(entry.type) ||
23
+ (entry.properCase !== undefined && typeof entry.properCase !== 'boolean')
24
+ ) {
25
+ throw failure('ERR_CONFIG');
26
+ }
27
+ const copy = Object.freeze({
28
+ type: entry.type,
29
+ value: entry.value,
30
+ ...(entry.properCase === undefined
31
+ ? {}
32
+ : { properCase: entry.properCase }),
33
+ });
34
+ values.set(
35
+ `${entry.type}\0${entry.value}\0${entry.properCase ?? false}`,
36
+ copy
37
+ );
38
+ }
39
+ const entries = Object.freeze([...values.values()]);
40
+ const patterns = entries.map((entry) =>
41
+ personalRegex(entry.value, entry.type)
42
+ );
43
+ const projected = entries.map((entry) => ({
44
+ ...entry,
45
+ value: projectText(entry.value).text,
46
+ }));
47
+ const changed = projected.some(
48
+ (entry, i) => entry.value !== entries[i].value
49
+ );
50
+ compiled.set(entries, {
51
+ patterns,
52
+ projected: changed ? compileKnown(projected) : entries,
53
+ });
54
+ return entries;
55
+ }
package/src/detection.js CHANGED
@@ -16,6 +16,8 @@ import { localAddress } from './public.js';
16
16
  import { detectKnownPersonal } from './personal-variants.js';
17
17
  import { detectDocumentEntities } from './document-entities.js';
18
18
  import { detectProseAndDocuments } from './proper-names.js';
19
+ import { builtInEnabled } from './policy.js';
20
+ import { detectStrict } from './strict.js';
19
21
 
20
22
  export const REDACTED = '[REDACTED]';
21
23
  export const failure = (code = 'ERR_SANITIZATION', location = {}) =>
@@ -137,6 +139,12 @@ function detectCookies(text, emit) {
137
139
  }
138
140
 
139
141
  export function nativeDetect(text, options, emit) {
142
+ const output = emit;
143
+ emit = (finding) => {
144
+ if (builtInEnabled(finding, options)) {
145
+ output(finding);
146
+ }
147
+ };
140
148
  const credential = { type: 'SECRET', category: 'credential' };
141
149
  for (const value of options.knownSecrets ?? []) {
142
150
  collectMatches(text, new RegExp(escapePattern(value), 'g'), emit, {
@@ -179,6 +187,7 @@ export function nativeDetect(text, options, emit) {
179
187
  detectIdentity(text, emit);
180
188
  detectNational(text, emit);
181
189
  detectPersonalContext(text, emit);
190
+ detectStrict(text, emit, options);
182
191
  }
183
192
  detectCredentialFormats(text, emit);
184
193
  // detect-secrets-style quoted entropy detection; bare commit hashes and