@jinn-network/core 0.1.0-canary.3afae198

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 (155) hide show
  1. package/dist/canonical-json.d.ts +1 -0
  2. package/dist/canonical-json.js +67 -0
  3. package/dist/captured-task.d.ts +140 -0
  4. package/dist/captured-task.js +122 -0
  5. package/dist/contribution-store.d.ts +97 -0
  6. package/dist/contribution-store.js +770 -0
  7. package/dist/corpus-read/acquire.d.ts +39 -0
  8. package/dist/corpus-read/acquire.js +212 -0
  9. package/dist/corpus-read/cache.d.ts +14 -0
  10. package/dist/corpus-read/cache.js +17 -0
  11. package/dist/corpus-read/capture-meta.d.ts +16 -0
  12. package/dist/corpus-read/capture-meta.js +18 -0
  13. package/dist/corpus-read/create-corpus.d.ts +2 -0
  14. package/dist/corpus-read/create-corpus.js +97 -0
  15. package/dist/corpus-read/fetch-artifact.d.ts +21 -0
  16. package/dist/corpus-read/fetch-artifact.js +32 -0
  17. package/dist/corpus-read/fetch.d.ts +12 -0
  18. package/dist/corpus-read/fetch.js +24 -0
  19. package/dist/corpus-read/http-discovery.d.ts +9 -0
  20. package/dist/corpus-read/http-discovery.js +128 -0
  21. package/dist/corpus-read/index.d.ts +10 -0
  22. package/dist/corpus-read/index.js +10 -0
  23. package/dist/corpus-read/ipfs.d.ts +14 -0
  24. package/dist/corpus-read/ipfs.js +81 -0
  25. package/dist/corpus-read/route-resolver.d.ts +16 -0
  26. package/dist/corpus-read/route-resolver.js +19 -0
  27. package/dist/corpus-read/types.d.ts +177 -0
  28. package/dist/corpus-read/types.js +42 -0
  29. package/dist/envelope.d.ts +134 -0
  30. package/dist/envelope.js +162 -0
  31. package/dist/evidence-adapter.d.ts +26 -0
  32. package/dist/evidence-adapter.js +321 -0
  33. package/dist/evidence-filesystem.d.ts +40 -0
  34. package/dist/evidence-filesystem.js +267 -0
  35. package/dist/evidence-index.d.ts +117 -0
  36. package/dist/evidence-index.js +1083 -0
  37. package/dist/evidence-store-lock.d.ts +2 -0
  38. package/dist/evidence-store-lock.js +208 -0
  39. package/dist/execution-envelope.d.ts +3142 -0
  40. package/dist/execution-envelope.js +203 -0
  41. package/dist/index.d.ts +12 -0
  42. package/dist/index.js +12 -0
  43. package/dist/manifest.d.ts +75 -0
  44. package/dist/manifest.js +184 -0
  45. package/dist/paired.d.ts +68 -0
  46. package/dist/paired.js +92 -0
  47. package/dist/scrub/apply-dispositions.d.ts +74 -0
  48. package/dist/scrub/apply-dispositions.js +309 -0
  49. package/dist/scrub/build.d.ts +75 -0
  50. package/dist/scrub/build.js +143 -0
  51. package/dist/scrub/checksummed-instruments-detector.d.ts +13 -0
  52. package/dist/scrub/checksummed-instruments-detector.js +119 -0
  53. package/dist/scrub/data/bip39-english.d.ts +2 -0
  54. package/dist/scrub/data/bip39-english.js +2051 -0
  55. package/dist/scrub/data/gitleaks-rules.d.ts +56 -0
  56. package/dist/scrub/data/gitleaks-rules.js +67 -0
  57. package/dist/scrub/emit-scrub.d.ts +52 -0
  58. package/dist/scrub/emit-scrub.js +122 -0
  59. package/dist/scrub/eval/findings-from-scrub.d.ts +18 -0
  60. package/dist/scrub/eval/findings-from-scrub.js +99 -0
  61. package/dist/scrub/eval/fixtures.d.ts +14 -0
  62. package/dist/scrub/eval/fixtures.js +159 -0
  63. package/dist/scrub/eval/index.d.ts +6 -0
  64. package/dist/scrub/eval/index.js +6 -0
  65. package/dist/scrub/eval/local-corpus.d.ts +15 -0
  66. package/dist/scrub/eval/local-corpus.js +29 -0
  67. package/dist/scrub/eval/metrics.d.ts +19 -0
  68. package/dist/scrub/eval/metrics.js +77 -0
  69. package/dist/scrub/eval/run-bench.d.ts +8 -0
  70. package/dist/scrub/eval/run-bench.js +125 -0
  71. package/dist/scrub/eval/types.d.ts +69 -0
  72. package/dist/scrub/eval/types.js +7 -0
  73. package/dist/scrub/finding.d.ts +38 -0
  74. package/dist/scrub/finding.js +7 -0
  75. package/dist/scrub/git-identity-detector.d.ts +16 -0
  76. package/dist/scrub/git-identity-detector.js +116 -0
  77. package/dist/scrub/gitleaks-detector.d.ts +13 -0
  78. package/dist/scrub/gitleaks-detector.js +45 -0
  79. package/dist/scrub/gliner-detector.d.ts +65 -0
  80. package/dist/scrub/gliner-detector.js +129 -0
  81. package/dist/scrub/index.d.ts +26 -0
  82. package/dist/scrub/index.js +26 -0
  83. package/dist/scrub/ip-address-detector.d.ts +12 -0
  84. package/dist/scrub/ip-address-detector.js +81 -0
  85. package/dist/scrub/key-policy.d.ts +30 -0
  86. package/dist/scrub/key-policy.js +72 -0
  87. package/dist/scrub/known-identity-detector.d.ts +66 -0
  88. package/dist/scrub/known-identity-detector.js +284 -0
  89. package/dist/scrub/layer2.d.ts +18 -0
  90. package/dist/scrub/layer2.js +28 -0
  91. package/dist/scrub/ml-pii-stage.d.ts +42 -0
  92. package/dist/scrub/ml-pii-stage.js +119 -0
  93. package/dist/scrub/pii-build.d.ts +47 -0
  94. package/dist/scrub/pii-build.js +67 -0
  95. package/dist/scrub/pipeline.d.ts +77 -0
  96. package/dist/scrub/pipeline.js +225 -0
  97. package/dist/scrub/plain-patterns-stage.d.ts +33 -0
  98. package/dist/scrub/plain-patterns-stage.js +88 -0
  99. package/dist/scrub/policy.d.ts +28 -0
  100. package/dist/scrub/policy.js +156 -0
  101. package/dist/scrub/provenance.d.ts +53 -0
  102. package/dist/scrub/provenance.js +83 -0
  103. package/dist/scrub/reject-classes-detector.d.ts +11 -0
  104. package/dist/scrub/reject-classes-detector.js +195 -0
  105. package/dist/scrub/reject-publish-error.d.ts +30 -0
  106. package/dist/scrub/reject-publish-error.js +47 -0
  107. package/dist/scrub/review-queue.d.ts +90 -0
  108. package/dist/scrub/review-queue.js +259 -0
  109. package/dist/scrub/secretlint-stage.d.ts +21 -0
  110. package/dist/scrub/secretlint-stage.js +264 -0
  111. package/dist/scrub/transformers-detector.d.ts +41 -0
  112. package/dist/scrub/transformers-detector.js +77 -0
  113. package/dist/scrub/types.d.ts +36 -0
  114. package/dist/scrub/types.js +1 -0
  115. package/dist/scrub/url-credentials-detector.d.ts +9 -0
  116. package/dist/scrub/url-credentials-detector.js +66 -0
  117. package/dist/session-provenance.d.ts +75 -0
  118. package/dist/session-provenance.js +20 -0
  119. package/dist/skill-artifact.d.ts +442 -0
  120. package/dist/skill-artifact.js +136 -0
  121. package/dist/trajectory/hash-chain.d.ts +18 -0
  122. package/dist/trajectory/hash-chain.js +47 -0
  123. package/dist/trajectory/index.d.ts +4 -0
  124. package/dist/trajectory/index.js +4 -0
  125. package/dist/trajectory/schema.d.ts +681 -0
  126. package/dist/trajectory/schema.js +119 -0
  127. package/dist/trajectory/transcript-parsers/aider-history.d.ts +42 -0
  128. package/dist/trajectory/transcript-parsers/aider-history.js +181 -0
  129. package/dist/trajectory/transcript-parsers/claude-code-jsonl.d.ts +37 -0
  130. package/dist/trajectory/transcript-parsers/claude-code-jsonl.js +142 -0
  131. package/dist/trajectory/transcript-parsers/codex-session.d.ts +42 -0
  132. package/dist/trajectory/transcript-parsers/codex-session.js +235 -0
  133. package/dist/trajectory/transcript-parsers/continue-devdata.d.ts +41 -0
  134. package/dist/trajectory/transcript-parsers/continue-devdata.js +190 -0
  135. package/dist/trajectory/transcript-parsers/cursor-sqlite.d.ts +38 -0
  136. package/dist/trajectory/transcript-parsers/cursor-sqlite.js +118 -0
  137. package/dist/trajectory/transcript-parsers/gemini-session.d.ts +35 -0
  138. package/dist/trajectory/transcript-parsers/gemini-session.js +137 -0
  139. package/dist/trajectory/transcript-parsers/index.d.ts +7 -0
  140. package/dist/trajectory/transcript-parsers/index.js +7 -0
  141. package/dist/trajectory/transcript-parsers/types.d.ts +101 -0
  142. package/dist/trajectory/transcript-parsers/types.js +32 -0
  143. package/dist/trajectory/transcript-to-spans/attrs.d.ts +4 -0
  144. package/dist/trajectory/transcript-to-spans/attrs.js +30 -0
  145. package/dist/trajectory/transcript-to-spans/claude-code-stream-json.d.ts +8 -0
  146. package/dist/trajectory/transcript-to-spans/claude-code-stream-json.js +162 -0
  147. package/dist/trajectory/transcript-to-spans/codex-exec-json.d.ts +8 -0
  148. package/dist/trajectory/transcript-to-spans/codex-exec-json.js +253 -0
  149. package/dist/trajectory/transcript-to-spans/index.d.ts +4 -0
  150. package/dist/trajectory/transcript-to-spans/index.js +4 -0
  151. package/dist/trajectory/transcript-to-spans/types.d.ts +18 -0
  152. package/dist/trajectory/transcript-to-spans/types.js +1 -0
  153. package/dist/window.d.ts +12 -0
  154. package/dist/window.js +5 -0
  155. package/package.json +72 -0
@@ -0,0 +1,129 @@
1
+ /**
2
+ * GLiNER ONNX ML PII detector (#1973 / design §5.1, §6.3).
3
+ *
4
+ * Local-only inference behind the {@link PiiDetector} seam. Default model is
5
+ * `urchade/gliner_multi_pii-v1` (Apache-2.0, PII-tuned, multilingual). ONNX
6
+ * weights load from the community mirror `onnx-community/gliner_multi_pii-v1`
7
+ * (same weights; Transformers.js-compatible layout).
8
+ *
9
+ * Benchmark note (locked Q3): `urchade/gliner_multi_pii-v1` is the pinned
10
+ * default. The smaller `knowledgator/gliner-pii-edge-v1.0` family remains an
11
+ * alternate via `captures.piiDetection.model` — operators should measure
12
+ * Fβ=2 + latency on their local corpus before switching.
13
+ *
14
+ * Download-on-first-run is intentional (same posture as the retired
15
+ * bert-base-NER path). Init failure is fail-closed via
16
+ * {@link maybeBuildPiiDetector}.
17
+ */
18
+ /**
19
+ * Logical model id operators configure. ONNX weights for the default pin live
20
+ * under the onnx-community mirror (see {@link resolveOnnxModelId}).
21
+ */
22
+ export const DEFAULT_GLINER_MODEL = 'urchade/gliner_multi_pii-v1';
23
+ /** Alternate smaller pin — set via config `captures.piiDetection.model`. */
24
+ export const ALTERNATE_GLINER_EDGE_MODEL = 'knowledgator/gliner-pii-edge-v1.0';
25
+ /**
26
+ * Zero-shot labels pinned in config (#1974 will hash these into the policy
27
+ * hash). Keep the list stable and reviewable — do not derive from model
28
+ * metadata at runtime.
29
+ */
30
+ export const DEFAULT_GLINER_PII_LABELS = [
31
+ 'person',
32
+ 'phone number',
33
+ 'email address',
34
+ 'street address',
35
+ 'credit card number',
36
+ 'social security number',
37
+ 'organization',
38
+ 'username',
39
+ 'ip address',
40
+ 'date of birth',
41
+ ];
42
+ /** Map a logical / source model id onto an ONNX-capable Hugging Face repo. */
43
+ export function resolveOnnxModelId(modelId) {
44
+ if (modelId === DEFAULT_GLINER_MODEL || modelId === 'urchade/gliner_multi_pii-v1') {
45
+ return 'onnx-community/gliner_multi_pii-v1';
46
+ }
47
+ // knowledgator edge/base variants often ship ONNX under the same id or an
48
+ // onnx-community mirror; pass through and let fromPretrained fail closed.
49
+ return modelId;
50
+ }
51
+ /**
52
+ * Production GLiNER PII detector. Loads ONNX weights via `@lmoe/gliner-onnx`
53
+ * (dynamic import so unit tests never pull the runtime). Call {@link init}
54
+ * before {@link detect}; {@link maybeBuildPiiDetector} owns that lifecycle.
55
+ */
56
+ export class GlinerPiiDetector {
57
+ runtime;
58
+ initPromise;
59
+ model;
60
+ labels;
61
+ threshold;
62
+ constructor(opts = {}) {
63
+ this.model = opts.model ?? DEFAULT_GLINER_MODEL;
64
+ this.labels = opts.labels ?? DEFAULT_GLINER_PII_LABELS;
65
+ this.threshold = opts.threshold ?? 0.5;
66
+ }
67
+ /** Logical model id (hashed into the policy digest — #1974). */
68
+ get modelId() {
69
+ return this.model;
70
+ }
71
+ /** Zero-shot labels (hashed into the policy digest — #1974). */
72
+ get labelSet() {
73
+ return this.labels;
74
+ }
75
+ /** Eagerly load the model (daemon boot / first publish). */
76
+ async init() {
77
+ await this.ensureReady();
78
+ }
79
+ ensureReady() {
80
+ if (this.runtime)
81
+ return Promise.resolve();
82
+ if (!this.initPromise) {
83
+ this.initPromise = (async () => {
84
+ let mod;
85
+ try {
86
+ mod = (await import('@lmoe/gliner-onnx'));
87
+ }
88
+ catch (err) {
89
+ const message = err instanceof Error ? err.message : String(err);
90
+ throw new Error(`GLiNER ONNX runtime unavailable (install @lmoe/gliner-onnx / onnxruntime-node): ${message}`);
91
+ }
92
+ if (!mod.GLiNER1ONNXRuntime?.fromPretrained) {
93
+ throw new Error('GLiNER ONNX runtime loaded but GLiNER1ONNXRuntime.fromPretrained is missing');
94
+ }
95
+ const onnxId = resolveOnnxModelId(this.model);
96
+ this.runtime = await mod.GLiNER1ONNXRuntime.fromPretrained(onnxId);
97
+ })();
98
+ }
99
+ return this.initPromise;
100
+ }
101
+ async detect(text) {
102
+ if (!text.trim())
103
+ return [];
104
+ await this.ensureReady();
105
+ const runtime = this.runtime;
106
+ const entities = await runtime.extractEntities(text, this.labels, {
107
+ threshold: this.threshold,
108
+ });
109
+ const out = [];
110
+ const seen = new Set();
111
+ for (const e of entities) {
112
+ const t = e.text?.trim();
113
+ if (!t)
114
+ continue;
115
+ const key = `${e.label}:${e.start}:${e.end}:${t}`;
116
+ if (seen.has(key))
117
+ continue;
118
+ seen.add(key);
119
+ out.push({
120
+ label: e.label,
121
+ text: t,
122
+ start: e.start,
123
+ end: e.end,
124
+ score: e.score,
125
+ });
126
+ }
127
+ return out;
128
+ }
129
+ }
@@ -0,0 +1,26 @@
1
+ export * from './apply-dispositions.js';
2
+ export * from './build.js';
3
+ export * from './checksummed-instruments-detector.js';
4
+ export * from './emit-scrub.js';
5
+ export * from './eval/index.js';
6
+ export * from './finding.js';
7
+ export * from './git-identity-detector.js';
8
+ export * from './gitleaks-detector.js';
9
+ export * from './ip-address-detector.js';
10
+ export * from './key-policy.js';
11
+ export * from './known-identity-detector.js';
12
+ export * from './layer2.js';
13
+ export * from './ml-pii-stage.js';
14
+ export * from './gliner-detector.js';
15
+ export * from './pii-build.js';
16
+ export * from './pipeline.js';
17
+ export * from './plain-patterns-stage.js';
18
+ export * from './policy.js';
19
+ export * from './provenance.js';
20
+ export * from './reject-classes-detector.js';
21
+ export * from './reject-publish-error.js';
22
+ export * from './review-queue.js';
23
+ export * from './secretlint-stage.js';
24
+ export * from './transformers-detector.js';
25
+ export * from './types.js';
26
+ export * from './url-credentials-detector.js';
@@ -0,0 +1,26 @@
1
+ export * from './apply-dispositions.js';
2
+ export * from './build.js';
3
+ export * from './checksummed-instruments-detector.js';
4
+ export * from './emit-scrub.js';
5
+ export * from './eval/index.js';
6
+ export * from './finding.js';
7
+ export * from './git-identity-detector.js';
8
+ export * from './gitleaks-detector.js';
9
+ export * from './ip-address-detector.js';
10
+ export * from './key-policy.js';
11
+ export * from './known-identity-detector.js';
12
+ export * from './layer2.js';
13
+ export * from './ml-pii-stage.js';
14
+ export * from './gliner-detector.js';
15
+ export * from './pii-build.js';
16
+ export * from './pipeline.js';
17
+ export * from './plain-patterns-stage.js';
18
+ export * from './policy.js';
19
+ export * from './provenance.js';
20
+ export * from './reject-classes-detector.js';
21
+ export * from './reject-publish-error.js';
22
+ export * from './review-queue.js';
23
+ export * from './secretlint-stage.js';
24
+ export * from './transformers-detector.js';
25
+ export * from './types.js';
26
+ export * from './url-credentials-detector.js';
@@ -0,0 +1,12 @@
1
+ /**
2
+ * D2 — IPv4 addresses with range classification (#1972 / design §3.2 / §6.2).
3
+ *
4
+ * - public → VERY_HIGH (redact)
5
+ * - private (RFC1918 / link-local) → MEDIUM (flag)
6
+ * - loopback / unspecified / broadcast / documentation → no finding (pass)
7
+ */
8
+ import { type KeyPolicy } from './key-policy.js';
9
+ import type { Detector } from './finding.js';
10
+ export type IpRangeClass = 'public' | 'private' | 'loopback' | 'reserved';
11
+ export declare function classifyIpv4(ip: string): IpRangeClass;
12
+ export declare function ipAddressDetector(policy: KeyPolicy): Detector;
@@ -0,0 +1,81 @@
1
+ /**
2
+ * D2 — IPv4 addresses with range classification (#1972 / design §3.2 / §6.2).
3
+ *
4
+ * - public → VERY_HIGH (redact)
5
+ * - private (RFC1918 / link-local) → MEDIUM (flag)
6
+ * - loopback / unspecified / broadcast / documentation → no finding (pass)
7
+ */
8
+ import { classifyKey } from './key-policy.js';
9
+ const VERSION = '1.0.0';
10
+ const IPV4_PATTERN = /\b(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\b/g;
11
+ export function classifyIpv4(ip) {
12
+ const parts = ip.split('.').map((p) => Number(p));
13
+ if (parts.length !== 4 || parts.some((n) => !Number.isInteger(n) || n < 0 || n > 255)) {
14
+ return 'reserved';
15
+ }
16
+ const [a, b] = parts;
17
+ // Loopback 127.0.0.0/8
18
+ if (a === 127)
19
+ return 'loopback';
20
+ // Unspecified
21
+ if (a === 0)
22
+ return 'reserved';
23
+ // Broadcast
24
+ if (a === 255 && b === 255 && parts[2] === 255 && parts[3] === 255)
25
+ return 'reserved';
26
+ // Current network / this host on this network historically
27
+ // Link-local 169.254.0.0/16
28
+ if (a === 169 && b === 254)
29
+ return 'reserved';
30
+ // Multicast 224.0.0.0/4
31
+ if (a >= 224 && a <= 239)
32
+ return 'reserved';
33
+ // Reserved for future / class E
34
+ if (a >= 240)
35
+ return 'reserved';
36
+ // Documentation (TEST-NET)
37
+ if (a === 192 && b === 0 && parts[2] === 2)
38
+ return 'reserved';
39
+ if (a === 198 && b === 51 && parts[2] === 100)
40
+ return 'reserved';
41
+ if (a === 203 && b === 0 && parts[2] === 113)
42
+ return 'reserved';
43
+ // RFC1918 private
44
+ if (a === 10)
45
+ return 'private';
46
+ if (a === 172 && b >= 16 && b <= 31)
47
+ return 'private';
48
+ if (a === 192 && b === 168)
49
+ return 'private';
50
+ return 'public';
51
+ }
52
+ export function ipAddressDetector(policy) {
53
+ const meta = { name: 'ip-address', version: VERSION };
54
+ return {
55
+ ...meta,
56
+ detect(attributes) {
57
+ const findings = [];
58
+ for (const [key, value] of Object.entries(attributes)) {
59
+ if (typeof value !== 'string' || classifyKey(key, policy) !== 'content')
60
+ continue;
61
+ const re = new RegExp(IPV4_PATTERN.source, IPV4_PATTERN.flags);
62
+ let m;
63
+ while ((m = re.exec(value)) !== null) {
64
+ const ip = m[0];
65
+ const range = classifyIpv4(ip);
66
+ if (range === 'loopback' || range === 'reserved')
67
+ continue;
68
+ const confidence = range === 'public' ? 'VERY_HIGH' : 'MEDIUM';
69
+ findings.push({
70
+ class: 'D2',
71
+ span: { key, start: m.index, end: m.index + ip.length },
72
+ confidence,
73
+ evidence: [`ipv4-${range}`],
74
+ detector: meta,
75
+ });
76
+ }
77
+ }
78
+ return findings;
79
+ },
80
+ };
81
+ }
@@ -0,0 +1,30 @@
1
+ import type { ScrubStage } from './types.js';
2
+ import type { Detector } from './finding.js';
3
+ export interface KeyPolicy {
4
+ /** keys whose values are structural and safe to publish raw */
5
+ safe: string[];
6
+ /** keys to delete entirely (never published) — A5 structural drop */
7
+ drop: string[];
8
+ /**
9
+ * Machine-identity keys (D3 carrier): attempt-manifest `host`, hostname
10
+ * telemetry, and similar. Deleted at the key level (redact disposition) —
11
+ * not reject-publish.
12
+ */
13
+ machineIdentity?: string[];
14
+ }
15
+ export type KeyClass = 'safe' | 'content' | 'drop' | 'machine-identity';
16
+ /**
17
+ * Classify an attribute key against the policy. Precedence:
18
+ * `drop` > `machine-identity` > `safe` > `content`. Fail-safe: a key matching
19
+ * both drop and anything else is dropped.
20
+ */
21
+ export declare function classifyKey(key: string, policy: KeyPolicy): KeyClass;
22
+ /**
23
+ * Key-policy detector: emits A5 drop-key findings for `drop`-classified keys,
24
+ * and D3 machine-identity findings for hostname/carrier keys.
25
+ */
26
+ export declare function keyPolicyDetector(policy: KeyPolicy): Detector;
27
+ /**
28
+ * Legacy ScrubStage wrapper around {@link keyPolicyDetector}.
29
+ */
30
+ export declare function keyPolicyStage(policy: KeyPolicy): ScrubStage;
@@ -0,0 +1,72 @@
1
+ import { applyDispositions } from './apply-dispositions.js';
2
+ const VERSION = '0.3.0';
3
+ /** Exact match, or prefix match when the pattern ends with `*`. */
4
+ function matches(key, pattern) {
5
+ if (pattern.endsWith('*'))
6
+ return key.startsWith(pattern.slice(0, -1));
7
+ return key === pattern;
8
+ }
9
+ /**
10
+ * Classify an attribute key against the policy. Precedence:
11
+ * `drop` > `machine-identity` > `safe` > `content`. Fail-safe: a key matching
12
+ * both drop and anything else is dropped.
13
+ */
14
+ export function classifyKey(key, policy) {
15
+ if (policy.drop.some((p) => matches(key, p)))
16
+ return 'drop';
17
+ if ((policy.machineIdentity ?? []).some((p) => matches(key, p)))
18
+ return 'machine-identity';
19
+ if (policy.safe.some((p) => matches(key, p)))
20
+ return 'safe';
21
+ return 'content';
22
+ }
23
+ /**
24
+ * Key-policy detector: emits A5 drop-key findings for `drop`-classified keys,
25
+ * and D3 machine-identity findings for hostname/carrier keys.
26
+ */
27
+ export function keyPolicyDetector(policy) {
28
+ const meta = { name: 'key-policy', version: VERSION };
29
+ return {
30
+ ...meta,
31
+ detect(attributes) {
32
+ const findings = [];
33
+ for (const key of Object.keys(attributes)) {
34
+ const cls = classifyKey(key, policy);
35
+ if (cls === 'drop') {
36
+ findings.push({
37
+ class: 'A5',
38
+ span: { key, start: 0, end: 0 },
39
+ confidence: 'VERY_HIGH',
40
+ evidence: ['drop-key'],
41
+ detector: meta,
42
+ });
43
+ }
44
+ else if (cls === 'machine-identity') {
45
+ findings.push({
46
+ class: 'D3',
47
+ span: { key, start: 0, end: 0 },
48
+ confidence: 'VERY_HIGH',
49
+ evidence: ['machine-identity-key'],
50
+ detector: meta,
51
+ });
52
+ }
53
+ }
54
+ return findings;
55
+ },
56
+ };
57
+ }
58
+ /**
59
+ * Legacy ScrubStage wrapper around {@link keyPolicyDetector}.
60
+ */
61
+ export function keyPolicyStage(policy) {
62
+ const detector = keyPolicyDetector(policy);
63
+ return {
64
+ name: detector.name,
65
+ version: detector.version,
66
+ scrub(attributes) {
67
+ const findings = detector.detect(attributes);
68
+ const applied = applyDispositions(attributes, findings);
69
+ return { attributes: applied.attributes, redactions: applied.redactions };
70
+ },
71
+ };
72
+ }
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Known-identity pack + non-address instance allowlist (#1971 / design §6.4).
3
+ *
4
+ * Locked Q1: stub ALL address-shaped values (no address pass-allowlist). The
5
+ * pack exact-matches operator self-PII only. The allowlist covers loopback /
6
+ * reserved IPs and repo-slug patterns — never wallets.
7
+ */
8
+ import { type KeyPolicy } from './key-policy.js';
9
+ import type { Detector } from './finding.js';
10
+ import type { ScrubStage } from './types.js';
11
+ /** Operator self-PII assembled locally. No addresses (Q1). */
12
+ export interface KnownIdentityPack {
13
+ gitUserName?: string;
14
+ gitUserEmail?: string;
15
+ homeUsername?: string;
16
+ hostname?: string;
17
+ ghLogin?: string;
18
+ }
19
+ export type InstanceAllowlistKind = 'loopback-ip' | 'reserved-ip' | 'repo-slug';
20
+ export interface InstanceAllowlistEntry {
21
+ /** Exact value matched in content (case-insensitive for slugs/IPs). */
22
+ value: string;
23
+ kind: InstanceAllowlistKind;
24
+ /** Auditable provenance note recorded in the redaction manifest. */
25
+ provenance: string;
26
+ }
27
+ export interface InstanceAllowlist {
28
+ entries: InstanceAllowlistEntry[];
29
+ }
30
+ export interface AssembledKnownIdentity {
31
+ pack: KnownIdentityPack;
32
+ allowlist: InstanceAllowlist;
33
+ }
34
+ export interface AssembleKnownIdentityOptions {
35
+ /** Injected pack (tests / daemon). Wins over env/homedir fillers. */
36
+ pack?: KnownIdentityPack;
37
+ /** Extra allowlist entries merged onto the built-in non-address defaults. */
38
+ allowlist?: InstanceAllowlist;
39
+ /** Optional env (daemon). Only used to fill pack gaps. */
40
+ env?: NodeJS.ProcessEnv;
41
+ /** Optional homedir provider — basename becomes homeUsername when unset. */
42
+ homedir?: () => string;
43
+ /** Optional hostname provider. */
44
+ hostname?: () => string;
45
+ }
46
+ /** Built-in non-address public values (Q1): loopback + common reserved. */
47
+ export declare const DEFAULT_INSTANCE_ALLOWLIST: InstanceAllowlist;
48
+ export declare function isAddressShaped(value: string): boolean;
49
+ /**
50
+ * Assemble pack + allowlist from injected options, optionally filling gaps from
51
+ * env/homedir. Injectable pack is enough for this PR; daemon wiring stays thin.
52
+ */
53
+ export declare function assembleKnownIdentity(opts?: AssembleKnownIdentityOptions): AssembledKnownIdentity;
54
+ export interface KnownIdentityDetectorOptions {
55
+ pack?: KnownIdentityPack;
56
+ allowlist?: InstanceAllowlist;
57
+ /** Pre-assembled identity; when set, pack/allowlist options are ignored. */
58
+ assembled?: AssembledKnownIdentity;
59
+ }
60
+ /**
61
+ * Detector: pack → VERY_HIGH redact findings; allowlist → pass findings with
62
+ * auditable evidence; public IPs → D2 redact; private IPs → D2 flag band.
63
+ */
64
+ export declare function knownIdentityDetector(policy: KeyPolicy, opts?: KnownIdentityDetectorOptions): Detector;
65
+ /** Legacy ScrubStage wrapper for stage-chain tests. */
66
+ export declare function knownIdentityStage(policy: KeyPolicy, opts?: KnownIdentityDetectorOptions): ScrubStage;