@jinn-network/core 0.1.0 → 0.1.1-canary.7b188db5

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.
Files changed (76) hide show
  1. package/dist/corpus-read/ipfs.d.ts +10 -1
  2. package/dist/corpus-read/ipfs.js +14 -5
  3. package/dist/scrub/apply-dispositions.d.ts +74 -0
  4. package/dist/scrub/apply-dispositions.js +309 -0
  5. package/dist/scrub/build.d.ts +54 -31
  6. package/dist/scrub/build.js +114 -55
  7. package/dist/scrub/checksummed-instruments-detector.d.ts +13 -0
  8. package/dist/scrub/checksummed-instruments-detector.js +119 -0
  9. package/dist/scrub/data/bip39-english.d.ts +2 -0
  10. package/dist/scrub/data/bip39-english.js +2051 -0
  11. package/dist/scrub/data/gitleaks-rules.d.ts +56 -0
  12. package/dist/scrub/data/gitleaks-rules.js +67 -0
  13. package/dist/scrub/emit-scrub.d.ts +13 -2
  14. package/dist/scrub/emit-scrub.js +39 -4
  15. package/dist/scrub/eval/findings-from-scrub.d.ts +18 -0
  16. package/dist/scrub/eval/findings-from-scrub.js +99 -0
  17. package/dist/scrub/eval/fixtures.d.ts +14 -0
  18. package/dist/scrub/eval/fixtures.js +159 -0
  19. package/dist/scrub/eval/index.d.ts +6 -0
  20. package/dist/scrub/eval/index.js +6 -0
  21. package/dist/scrub/eval/local-corpus.d.ts +15 -0
  22. package/dist/scrub/eval/local-corpus.js +29 -0
  23. package/dist/scrub/eval/metrics.d.ts +19 -0
  24. package/dist/scrub/eval/metrics.js +77 -0
  25. package/dist/scrub/eval/run-bench.d.ts +8 -0
  26. package/dist/scrub/eval/run-bench.js +125 -0
  27. package/dist/scrub/eval/types.d.ts +69 -0
  28. package/dist/scrub/eval/types.js +7 -0
  29. package/dist/scrub/finding.d.ts +38 -0
  30. package/dist/scrub/finding.js +7 -0
  31. package/dist/scrub/git-identity-detector.d.ts +16 -0
  32. package/dist/scrub/git-identity-detector.js +116 -0
  33. package/dist/scrub/gitleaks-detector.d.ts +13 -0
  34. package/dist/scrub/gitleaks-detector.js +45 -0
  35. package/dist/scrub/gliner-detector.d.ts +65 -0
  36. package/dist/scrub/gliner-detector.js +129 -0
  37. package/dist/scrub/index.d.ts +15 -1
  38. package/dist/scrub/index.js +15 -1
  39. package/dist/scrub/ip-address-detector.d.ts +12 -0
  40. package/dist/scrub/ip-address-detector.js +81 -0
  41. package/dist/scrub/key-policy.d.ts +18 -8
  42. package/dist/scrub/key-policy.js +49 -19
  43. package/dist/scrub/known-identity-detector.d.ts +66 -0
  44. package/dist/scrub/known-identity-detector.js +284 -0
  45. package/dist/scrub/layer2.d.ts +13 -18
  46. package/dist/scrub/layer2.js +22 -26
  47. package/dist/scrub/ml-pii-stage.d.ts +28 -10
  48. package/dist/scrub/ml-pii-stage.js +100 -23
  49. package/dist/scrub/pii-build.d.ts +17 -8
  50. package/dist/scrub/pii-build.js +9 -9
  51. package/dist/scrub/pipeline.d.ts +63 -24
  52. package/dist/scrub/pipeline.js +180 -38
  53. package/dist/scrub/plain-patterns-stage.d.ts +21 -19
  54. package/dist/scrub/plain-patterns-stage.js +61 -57
  55. package/dist/scrub/policy.d.ts +28 -0
  56. package/dist/scrub/policy.js +156 -0
  57. package/dist/scrub/provenance.d.ts +53 -0
  58. package/dist/scrub/provenance.js +83 -0
  59. package/dist/scrub/reject-classes-detector.d.ts +11 -0
  60. package/dist/scrub/reject-classes-detector.js +195 -0
  61. package/dist/scrub/reject-publish-error.d.ts +30 -0
  62. package/dist/scrub/reject-publish-error.js +47 -0
  63. package/dist/scrub/review-queue.d.ts +90 -0
  64. package/dist/scrub/review-queue.js +259 -0
  65. package/dist/scrub/secretlint-stage.d.ts +11 -26
  66. package/dist/scrub/secretlint-stage.js +45 -30
  67. package/dist/scrub/transformers-detector.d.ts +15 -9
  68. package/dist/scrub/transformers-detector.js +20 -10
  69. package/dist/scrub/types.d.ts +11 -0
  70. package/dist/scrub/url-credentials-detector.d.ts +9 -0
  71. package/dist/scrub/url-credentials-detector.js +66 -0
  72. package/dist/trajectory/schema.d.ts +75 -0
  73. package/dist/trajectory/schema.js +9 -0
  74. package/package.json +8 -3
  75. package/dist/scrub/openredaction-stage.d.ts +0 -196
  76. package/dist/scrub/openredaction-stage.js +0 -270
@@ -1,9 +1,17 @@
1
1
  import { ScrubPipeline } from './pipeline.js';
2
- import { keyPolicyStage } from './key-policy.js';
3
- import { openredactionStage } from './openredaction-stage.js';
4
- import { plainPatternsStage } from './plain-patterns-stage.js';
5
- import { secretlintStage } from './secretlint-stage.js';
6
- import { mlPiiStage } from './ml-pii-stage.js';
2
+ import { keyPolicyDetector } from './key-policy.js';
3
+ import { plainPatternsDetector } from './plain-patterns-stage.js';
4
+ import { gitIdentityDetector } from './git-identity-detector.js';
5
+ import { secretlintDetector } from './secretlint-stage.js';
6
+ import { mlPiiDetector } from './ml-pii-stage.js';
7
+ import { assembleKnownIdentity, knownIdentityDetector, } from './known-identity-detector.js';
8
+ import { urlCredentialsDetector } from './url-credentials-detector.js';
9
+ import { rejectClassesDetector } from './reject-classes-detector.js';
10
+ import { checksummedInstrumentsDetector } from './checksummed-instruments-detector.js';
11
+ import { ipAddressDetector } from './ip-address-detector.js';
12
+ import { gitleaksDetector } from './gitleaks-detector.js';
13
+ import { DEFAULT_POLICY } from './policy.js';
14
+ import { computeAllowlistDigest } from './provenance.js';
7
15
  /**
8
16
  * Default key policy. `jinn.*` identity/chain attributes are structural and pass
9
17
  * raw. The `drop` tier deletes the spec's stage-1 high-confidence keys outright
@@ -11,8 +19,9 @@ import { mlPiiStage } from './ml-pii-stage.js';
11
19
  * these never carry sellable content and are never safe to publish. Globs use the
12
20
  * trailing-`*` prefix form `classifyKey` supports; the HTTP header keys are listed
13
21
  * per request/response direction (a leading `*.header.…` glob is not matched, so
14
- * we enumerate the concrete keys). Everything else is `content` and flows through
15
- * the value-scrubbing stages.
22
+ * we enumerate the concrete keys). Machine-identity keys (D3 carrier) drop
23
+ * attempt-manifest `host` / hostname telemetry. Everything else is `content` and
24
+ * flows through the value-scrubbing detectors.
16
25
  */
17
26
  export const DEFAULT_KEY_POLICY = {
18
27
  safe: ['jinn.*'],
@@ -25,60 +34,110 @@ export const DEFAULT_KEY_POLICY = {
25
34
  'http.response.header.set-cookie',
26
35
  'env.*',
27
36
  ],
37
+ machineIdentity: [
38
+ 'host',
39
+ 'hostname',
40
+ 'os.hostname',
41
+ 'attempt.host',
42
+ 'attempt.hostname',
43
+ 'system.hostname',
44
+ 'device.hostname',
45
+ 'device.host',
46
+ ],
28
47
  };
48
+ export function resolveKnownIdentity(opts) {
49
+ // AssembledKnownIdentity is a subset of AssembleKnownIdentityOptions;
50
+ // re-assembly is idempotent (allowlist entries are deduped).
51
+ return assembleKnownIdentity(opts);
52
+ }
53
+ /** Duck-type ML detector metadata for the policy hash (#1974). */
54
+ function provenanceFromPiiDetector(detector) {
55
+ if (!detector)
56
+ return { modelId: null, labels: [] };
57
+ const withMeta = detector;
58
+ if (typeof withMeta.modelId === 'string' && withMeta.labelSet) {
59
+ return { modelId: withMeta.modelId, labels: withMeta.labelSet };
60
+ }
61
+ return { modelId: null, labels: [] };
62
+ }
63
+ /** Build provenance extras from known-identity + optional ML detector (#1974). */
64
+ export function buildProvenanceExtras(knownIdentity, piiDetector) {
65
+ const ml = provenanceFromPiiDetector(piiDetector);
66
+ return {
67
+ modelId: ml.modelId,
68
+ labels: ml.labels,
69
+ allowlistDigest: computeAllowlistDigest(knownIdentity.allowlist.entries),
70
+ };
71
+ }
72
+ /**
73
+ * Shared detector inventory (#1969 / #1970 / #1971 / #1972 / #1973). Every
74
+ * publish/check consumer runs the same owned detectors (key-policy,
75
+ * plain-patterns including C1 wallet + A1 credential IDs, git-identity B2
76
+ * carriers, known-identity pack + non-address allowlist, Tier-1
77
+ * reject/URL/IP/instruments/gitleaks, secretlint). What varies is disposition /
78
+ * check-mode and whether an ML PII detector is injected. Seed keeps the entropy
79
+ * fallback off until A2 mid-band flags are absorbed without refuse-on-detection
80
+ * (#1409 shipped behavior). openredaction was retired in #1973.
81
+ */
82
+ export function sharedDetectorInventory(policy, opts = {}) {
83
+ const detectors = [keyPolicyDetector(policy)];
84
+ detectors.push(plainPatternsDetector(policy));
85
+ detectors.push(gitIdentityDetector(policy));
86
+ detectors.push(knownIdentityDetector(policy, { assembled: resolveKnownIdentity(opts.knownIdentity) }));
87
+ detectors.push(urlCredentialsDetector(policy));
88
+ detectors.push(rejectClassesDetector(policy));
89
+ detectors.push(checksummedInstrumentsDetector(policy));
90
+ detectors.push(ipAddressDetector(policy));
91
+ detectors.push(gitleaksDetector(policy));
92
+ detectors.push(secretlintDetector(policy, { entropyFallback: opts.entropyFallback ?? true }));
93
+ if (opts.piiDetector) {
94
+ detectors.push(mlPiiDetector(policy, opts.piiDetector));
95
+ }
96
+ return detectors;
97
+ }
29
98
  /**
30
- * Assembles the seller-side scrub pipeline (cost-ascending): structural key
31
- * policy → openredaction (structured PII) → secretlint + entropy (secrets) →
32
- * optional GLiNER (ML PII). The GLiNER stage is added only when a detector is
33
- * supplied, so the daemon degrades gracefully (regex + secrets still scrub) when
34
- * the ML model is unavailable.
99
+ * Trace / redact-mode preset over the shared inventory.
100
+ *
101
+ * @deprecated Prefer thinking in terms of one inventory + policy; this builder
102
+ * remains as a compatibility preset through the migration (#1969).
35
103
  */
36
104
  export function buildScrubPipeline(opts = {}) {
37
105
  const policy = opts.policy ?? DEFAULT_KEY_POLICY;
38
- return new ScrubPipeline(assembleScrubStages(policy, opts.piiDetector));
39
- }
40
- function assembleScrubStages(policy, piiDetector) {
41
- // plain-patterns runs after openredaction: deterministic email/home-path
42
- // regexes closing gaps the probabilistic stage demonstrably has (#1330).
43
- const stages = [
44
- keyPolicyStage(policy),
45
- openredactionStage(policy),
46
- plainPatternsStage(policy),
47
- secretlintStage(policy),
48
- ];
49
- if (piiDetector) {
50
- stages.push(mlPiiStage(policy, piiDetector));
51
- }
52
- return stages;
106
+ const knownIdentity = resolveKnownIdentity(opts.knownIdentity);
107
+ return new ScrubPipeline(sharedDetectorInventory(policy, {
108
+ entropyFallback: true,
109
+ piiDetector: opts.piiDetector,
110
+ knownIdentity,
111
+ }), {
112
+ policy: DEFAULT_POLICY,
113
+ checkMode: false,
114
+ reviewStore: opts.reviewStore,
115
+ failClosedOnUnresolvedFlags: opts.failClosedOnUnresolvedFlags,
116
+ provenance: buildProvenanceExtras(knownIdentity, opts.piiDetector),
117
+ });
53
118
  }
54
119
  /**
55
- * Seed-profile scrub pipeline (#1409). Seeds are public, transformed or
56
- * otherwise human-curated content — not operator trace data — so the
57
- * probabilistic stages (openredaction, secretlint's pass-2 entropy fallback,
58
- * ML PII) that exist to catch unknown-shape PII/secrets in private traces are
59
- * dropped: on prose they false-positive (trigger words, dated env-var slugs,
60
- * long camelCase identifiers) and deface the corpus. The deterministic
61
- * detectors stay:
62
- * structural key policy, plain-patterns (emails, home paths, and — seed-only,
63
- * #1415 — bare AWS access-key IDs and GCP `AIza…` API keys, deterministic
64
- * prefix shapes secretlint pass-1 does not cover), and secretlint's pass-1
65
- * preset rules (AWS secret-key assignments, GitHub / Slack / npm token
66
- * shapes, GCP service-account JSON). Accepted residual: JWTs and unprefixed
67
- * high-entropy blobs (trace profile catches them via the entropy fallback),
68
- * plus every structured identifier or PII class detected only by the omitted
69
- * openredaction stage, pass unredacted. The latter is a 570+ pattern surface;
70
- * payment cards, phone numbers, SSNs, medical or health-plan identifiers,
71
- * government identity documents, and financial account references are
72
- * examples, not an exhaustive allowlist. This is acceptable only for public
73
- * seed material that a curator has transformed and reviewed for those classes.
74
- * The reduced stage list is inspectable locally through the pipeline's
75
- * `components` surface. `TraceEnvelopeV0` does not publish that list, so a
76
- * fetched envelope cannot by itself prove which scrub profile ran.
120
+ * Seed / redact-mode preset (#1409 / #1969). Same owned inventory as layer-2.
121
+ * Entropy fallback stays off to preserve the shipped zero-corruption seed
122
+ * behavior until A2 mid-band can flag without tripping refuse-on-detection.
123
+ *
124
+ * @deprecated Compatibility preset over the one inventory + policy table.
77
125
  */
78
- export function buildSeedScrubPipeline(policy = DEFAULT_KEY_POLICY) {
79
- return new ScrubPipeline([
80
- keyPolicyStage(policy),
81
- plainPatternsStage(policy, { credentialIds: true }),
82
- secretlintStage(policy, { entropyFallback: false }),
83
- ]);
126
+ export function buildSeedScrubPipeline(policyOrOpts = DEFAULT_KEY_POLICY) {
127
+ const opts = policyOrOpts && 'safe' in policyOrOpts
128
+ ? { policy: policyOrOpts }
129
+ : policyOrOpts;
130
+ const policy = opts.policy ?? DEFAULT_KEY_POLICY;
131
+ const knownIdentity = resolveKnownIdentity(opts.knownIdentity);
132
+ return new ScrubPipeline(sharedDetectorInventory(policy, {
133
+ entropyFallback: false,
134
+ piiDetector: opts.piiDetector,
135
+ knownIdentity,
136
+ }), {
137
+ policy: DEFAULT_POLICY,
138
+ checkMode: false,
139
+ reviewStore: opts.reviewStore,
140
+ failClosedOnUnresolvedFlags: opts.failClosedOnUnresolvedFlags,
141
+ provenance: buildProvenanceExtras(knownIdentity, opts.piiDetector),
142
+ });
84
143
  }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * B7 — checksummed payment instruments (#1972 / design §6.2).
3
+ *
4
+ * Card numbers (Luhn) and IBANs (mod-97). SSN-shape stays context-gated and is
5
+ * not emitted here.
6
+ */
7
+ import { type KeyPolicy } from './key-policy.js';
8
+ import type { Detector } from './finding.js';
9
+ export declare function checksummedInstrumentsDetector(policy: KeyPolicy): Detector;
10
+ /** ISO/IEC 7812 Luhn checksum. */
11
+ export declare function luhnOk(digits: string): boolean;
12
+ /** ISO 13616 IBAN mod-97 check. */
13
+ export declare function ibanMod97Ok(iban: string): boolean;
@@ -0,0 +1,119 @@
1
+ /**
2
+ * B7 — checksummed payment instruments (#1972 / design §6.2).
3
+ *
4
+ * Card numbers (Luhn) and IBANs (mod-97). SSN-shape stays context-gated and is
5
+ * not emitted here.
6
+ */
7
+ import { classifyKey } from './key-policy.js';
8
+ const VERSION = '1.0.0';
9
+ /** 13–19 digit runs, optional spaces/dashes between digit groups. */
10
+ const CARD_CANDIDATE = /\b(?:\d[ -]*?){13,19}\b/g;
11
+ /** IBAN: country + check digits + BBAN (no internal spaces in the candidate). */
12
+ const IBAN_CANDIDATE = /\b[A-Z]{2}\d{2}[A-Z0-9]{11,30}\b/gi;
13
+ /** Spaced IBAN groups (e.g. GB82 WEST 1234 5698 7654 32). */
14
+ const IBAN_SPACED = /\b[A-Z]{2}\d{2}(?:[ ][A-Z0-9]{4}){2,7}(?:[ ][A-Z0-9]{1,4})?\b/gi;
15
+ export function checksummedInstrumentsDetector(policy) {
16
+ const meta = { name: 'checksummed-instruments', version: VERSION };
17
+ return {
18
+ ...meta,
19
+ detect(attributes) {
20
+ const findings = [];
21
+ for (const [key, value] of Object.entries(attributes)) {
22
+ if (typeof value !== 'string' || classifyKey(key, policy) !== 'content')
23
+ continue;
24
+ findings.push(...scanCards(value, key, meta));
25
+ findings.push(...scanIbans(value, key, meta));
26
+ }
27
+ return findings;
28
+ },
29
+ };
30
+ }
31
+ function scanCards(text, key, detector) {
32
+ const findings = [];
33
+ const re = new RegExp(CARD_CANDIDATE.source, CARD_CANDIDATE.flags);
34
+ let m;
35
+ while ((m = re.exec(text)) !== null) {
36
+ const raw = m[0];
37
+ const digits = raw.replace(/\D/g, '');
38
+ if (digits.length < 13 || digits.length > 19)
39
+ continue;
40
+ // Skip obvious non-cards (all same digit, leading zeros-only short ids).
41
+ if (/^(\d)\1+$/.test(digits))
42
+ continue;
43
+ if (!luhnOk(digits))
44
+ continue;
45
+ findings.push({
46
+ class: 'B7',
47
+ span: { key, start: m.index, end: m.index + raw.length },
48
+ confidence: 'VERY_HIGH',
49
+ evidence: ['card-luhn'],
50
+ detector,
51
+ });
52
+ }
53
+ return findings;
54
+ }
55
+ function scanIbans(text, key, detector) {
56
+ const findings = [];
57
+ const seen = new Set();
58
+ for (const pattern of [IBAN_CANDIDATE, IBAN_SPACED]) {
59
+ const re = new RegExp(pattern.source, pattern.flags);
60
+ let m;
61
+ while ((m = re.exec(text)) !== null) {
62
+ const raw = m[0];
63
+ const compact = raw.replace(/\s+/g, '').toUpperCase();
64
+ if (compact.length < 15 || compact.length > 34)
65
+ continue;
66
+ if (!ibanMod97Ok(compact))
67
+ continue;
68
+ const spanKey = `${m.index}:${m.index + raw.length}`;
69
+ if (seen.has(spanKey))
70
+ continue;
71
+ seen.add(spanKey);
72
+ findings.push({
73
+ class: 'B7',
74
+ span: { key, start: m.index, end: m.index + raw.length },
75
+ confidence: 'VERY_HIGH',
76
+ evidence: ['iban-mod97'],
77
+ detector,
78
+ });
79
+ }
80
+ }
81
+ return findings;
82
+ }
83
+ /** ISO/IEC 7812 Luhn checksum. */
84
+ export function luhnOk(digits) {
85
+ let sum = 0;
86
+ let alt = false;
87
+ for (let i = digits.length - 1; i >= 0; i -= 1) {
88
+ let n = digits.charCodeAt(i) - 48;
89
+ if (n < 0 || n > 9)
90
+ return false;
91
+ if (alt) {
92
+ n *= 2;
93
+ if (n > 9)
94
+ n -= 9;
95
+ }
96
+ sum += n;
97
+ alt = !alt;
98
+ }
99
+ return sum % 10 === 0;
100
+ }
101
+ /** ISO 13616 IBAN mod-97 check. */
102
+ export function ibanMod97Ok(iban) {
103
+ const rearranged = iban.slice(4) + iban.slice(0, 4);
104
+ let expanded = '';
105
+ for (const ch of rearranged) {
106
+ if (ch >= '0' && ch <= '9')
107
+ expanded += ch;
108
+ else if (ch >= 'A' && ch <= 'Z')
109
+ expanded += String(ch.charCodeAt(0) - 55);
110
+ else
111
+ return false;
112
+ }
113
+ // Progressive mod to avoid BigInt dependency for typical IBAN lengths.
114
+ let rest = 0;
115
+ for (const ch of expanded) {
116
+ rest = (rest * 10 + (ch.charCodeAt(0) - 48)) % 97;
117
+ }
118
+ return rest === 1;
119
+ }
@@ -0,0 +1,2 @@
1
+ /** BIP-39 English wordlist (2048 words). Vendored for A4 mnemonic detection. */
2
+ export declare const BIP39_ENGLISH: readonly string[];