nz-privacy-auditor 0.8.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.
Files changed (67) hide show
  1. package/README.md +152 -0
  2. package/data/llm_cache/cache.json +1 -0
  3. package/dist/cli.d.ts +16 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +233 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/detectors/address.d.ts +48 -0
  8. package/dist/detectors/address.d.ts.map +1 -0
  9. package/dist/detectors/address.js +262 -0
  10. package/dist/detectors/address.js.map +1 -0
  11. package/dist/detectors/base.d.ts +43 -0
  12. package/dist/detectors/base.d.ts.map +1 -0
  13. package/dist/detectors/base.js +6 -0
  14. package/dist/detectors/base.js.map +1 -0
  15. package/dist/detectors/driver_licence.d.ts +38 -0
  16. package/dist/detectors/driver_licence.d.ts.map +1 -0
  17. package/dist/detectors/driver_licence.js +80 -0
  18. package/dist/detectors/driver_licence.js.map +1 -0
  19. package/dist/detectors/ird.d.ts +37 -0
  20. package/dist/detectors/ird.d.ts.map +1 -0
  21. package/dist/detectors/ird.js +103 -0
  22. package/dist/detectors/ird.js.map +1 -0
  23. package/dist/detectors/maori_name.d.ts +36 -0
  24. package/dist/detectors/maori_name.d.ts.map +1 -0
  25. package/dist/detectors/maori_name.js +251 -0
  26. package/dist/detectors/maori_name.js.map +1 -0
  27. package/dist/detectors/nhi.d.ts +44 -0
  28. package/dist/detectors/nhi.d.ts.map +1 -0
  29. package/dist/detectors/nhi.js +147 -0
  30. package/dist/detectors/nhi.js.map +1 -0
  31. package/dist/detectors/phone.d.ts +49 -0
  32. package/dist/detectors/phone.d.ts.map +1 -0
  33. package/dist/detectors/phone.js +126 -0
  34. package/dist/detectors/phone.js.map +1 -0
  35. package/dist/index.d.ts +25 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +52 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/report.d.ts +14 -0
  40. package/dist/report.d.ts.map +1 -0
  41. package/dist/report.js +90 -0
  42. package/dist/report.js.map +1 -0
  43. package/dist/scanner.d.ts +51 -0
  44. package/dist/scanner.d.ts.map +1 -0
  45. package/dist/scanner.js +114 -0
  46. package/dist/scanner.js.map +1 -0
  47. package/dist/verification.d.ts +25 -0
  48. package/dist/verification.d.ts.map +1 -0
  49. package/dist/verification.js +89 -0
  50. package/dist/verification.js.map +1 -0
  51. package/dist/verifiers/base.d.ts +27 -0
  52. package/dist/verifiers/base.d.ts.map +1 -0
  53. package/dist/verifiers/base.js +24 -0
  54. package/dist/verifiers/base.js.map +1 -0
  55. package/dist/verifiers/cache.d.ts +23 -0
  56. package/dist/verifiers/cache.d.ts.map +1 -0
  57. package/dist/verifiers/cache.js +103 -0
  58. package/dist/verifiers/cache.js.map +1 -0
  59. package/dist/verifiers/gemini.d.ts +38 -0
  60. package/dist/verifiers/gemini.d.ts.map +1 -0
  61. package/dist/verifiers/gemini.js +121 -0
  62. package/dist/verifiers/gemini.js.map +1 -0
  63. package/dist/verifiers/index.d.ts +8 -0
  64. package/dist/verifiers/index.d.ts.map +1 -0
  65. package/dist/verifiers/index.js +16 -0
  66. package/dist/verifiers/index.js.map +1 -0
  67. package/package.json +96 -0
@@ -0,0 +1,262 @@
1
+ "use strict";
2
+ /**
3
+ * NZ address detector.
4
+ *
5
+ * Address detection combines three signals to flag values that look like a
6
+ * New Zealand street address:
7
+ *
8
+ * 1. **Street-suffix shape** — a numeric prefix followed by 1–4 words and a
9
+ * recognised NZ street-type suffix (`Street`, `Road`, `Avenue`, `Drive`,
10
+ * `Lane`, etc., and their common abbreviations).
11
+ * 2. **NZ postcode** — a 4-digit token (NZ Post uses 4-digit postcodes).
12
+ * 3. **NZ location name** — one of the 16 regions, major cities, or common
13
+ * metropolitan suburbs from the bundled gazetteer.
14
+ *
15
+ * Severity is MEDIUM because an address is a quasi-identifier under the
16
+ * Privacy Act 2020. Confidence scales with the number of corroborating
17
+ * signals:
18
+ *
19
+ * - 0.5 — street-suffix shape only
20
+ * - 0.7 — street-suffix shape + postcode OR location
21
+ * - 0.9 — street-suffix shape + postcode + location
22
+ *
23
+ * TypeScript port of `src/nz_privacy_auditor/detectors/address.py`. The
24
+ * NZ_LOCATIONS list is a verbatim mirror of the Python `_NZ_LOCATIONS`
25
+ * frozenset — any change to one must be applied to the other. A parity
26
+ * check across the two lists lives in the JS test suite.
27
+ */
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.AddressDetector = exports.NZ_LOCATIONS = void 0;
30
+ const STREET_SUFFIXES = [
31
+ // Full forms
32
+ "street",
33
+ "road",
34
+ "avenue",
35
+ "drive",
36
+ "lane",
37
+ "place",
38
+ "crescent",
39
+ "terrace",
40
+ "boulevard",
41
+ "highway",
42
+ "court",
43
+ "close",
44
+ "parade",
45
+ "mall",
46
+ "quay",
47
+ "square",
48
+ "loop",
49
+ "rise",
50
+ "grove",
51
+ "way",
52
+ "heights",
53
+ "park",
54
+ "esplanade",
55
+ "promenade",
56
+ // Abbreviations
57
+ "st",
58
+ "rd",
59
+ "ave",
60
+ "av",
61
+ "dr",
62
+ "ln",
63
+ "pl",
64
+ "cres",
65
+ "tce",
66
+ "blvd",
67
+ "hwy",
68
+ "ct",
69
+ "cl",
70
+ "pde",
71
+ "sq",
72
+ ];
73
+ /**
74
+ * NZ regions, major cities, and common metropolitan suburbs.
75
+ *
76
+ * IMPORTANT: this list is a mirror of `_NZ_LOCATIONS` in the Python
77
+ * detector at `src/nz_privacy_auditor/detectors/address.py`. Any addition
78
+ * or removal must be applied to both files simultaneously.
79
+ */
80
+ exports.NZ_LOCATIONS = [
81
+ // 16 regions
82
+ "Northland",
83
+ "Auckland",
84
+ "Waikato",
85
+ "Bay of Plenty",
86
+ "Gisborne",
87
+ "Hawke's Bay",
88
+ "Hawkes Bay",
89
+ "Taranaki",
90
+ "Manawatu-Whanganui",
91
+ "Manawatū-Whanganui",
92
+ "Wellington",
93
+ "Tasman",
94
+ "Nelson",
95
+ "Marlborough",
96
+ "West Coast",
97
+ "Canterbury",
98
+ "Otago",
99
+ "Southland",
100
+ // Major cities / towns
101
+ "Whangarei",
102
+ "Whangārei",
103
+ "Hamilton",
104
+ "Tauranga",
105
+ "Rotorua",
106
+ "Taupo",
107
+ "Taupō",
108
+ "Napier",
109
+ "Hastings",
110
+ "New Plymouth",
111
+ "Palmerston North",
112
+ "Whanganui",
113
+ "Lower Hutt",
114
+ "Upper Hutt",
115
+ "Porirua",
116
+ "Kapiti",
117
+ "Kāpiti",
118
+ "Blenheim",
119
+ "Greymouth",
120
+ "Christchurch",
121
+ "Timaru",
122
+ "Dunedin",
123
+ "Queenstown",
124
+ "Invercargill",
125
+ // Common Auckland suburbs
126
+ "Albany",
127
+ "Botany",
128
+ "Devonport",
129
+ "Epsom",
130
+ "Glenfield",
131
+ "Grey Lynn",
132
+ "Henderson",
133
+ "Howick",
134
+ "Manukau",
135
+ "Mt Albert",
136
+ "Mt Eden",
137
+ "Mount Albert",
138
+ "Mount Eden",
139
+ "Newmarket",
140
+ "North Shore",
141
+ "Onehunga",
142
+ "Otahuhu",
143
+ "Otāhuhu",
144
+ "Pakuranga",
145
+ "Papakura",
146
+ "Papatoetoe",
147
+ "Parnell",
148
+ "Ponsonby",
149
+ "Remuera",
150
+ "Takapuna",
151
+ // Common Wellington suburbs
152
+ "Brooklyn",
153
+ "Karori",
154
+ "Kelburn",
155
+ "Khandallah",
156
+ "Miramar",
157
+ "Newtown",
158
+ "Petone",
159
+ "Thorndon",
160
+ // Common Christchurch suburbs
161
+ "Addington",
162
+ "Fendalton",
163
+ "Hornby",
164
+ "Ilam",
165
+ "Linwood",
166
+ "Merivale",
167
+ "Papanui",
168
+ "Riccarton",
169
+ "Sumner",
170
+ "Sydenham",
171
+ ];
172
+ function escapeRegex(s) {
173
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
174
+ }
175
+ // Build a case-insensitive alternation, longest first so multi-word
176
+ // locations like "Bay of Plenty" match before "Bay" alone would.
177
+ const LOCATION_PATTERN = new RegExp("\\b(?:" +
178
+ [...exports.NZ_LOCATIONS]
179
+ .sort((a, b) => b.length - a.length)
180
+ .map(escapeRegex)
181
+ .join("|") +
182
+ ")\\b", "gi");
183
+ // 4-digit NZ postcode. NZ Post issues postcodes in 0110-9999; values
184
+ // below 0100 are unused.
185
+ const POSTCODE_PATTERN = /\b(0[1-9]\d{2}|[1-9]\d{3})\b/g;
186
+ const SUFFIX_GROUP = STREET_SUFFIXES.join("|");
187
+ // Street-shape: optional unit prefix (e.g. "5/"), street number with optional
188
+ // trailing letter (e.g. "12A"), 1-4 capitalised words, then a recognised suffix.
189
+ const ADDRESS_PATTERN = new RegExp("\\b(" +
190
+ "(?:\\d+\\s*/\\s*)?" +
191
+ "\\d{1,5}[A-Za-z]?" +
192
+ "\\s+" +
193
+ "(?:[A-Z][A-Za-z\\u00C0-\\u017F'\\u2019]*[-\\s]){1,4}" +
194
+ "(?:" +
195
+ SUFFIX_GROUP +
196
+ ")" +
197
+ ")\\b", "gi");
198
+ function supportingSignals(value, addressStart, addressEnd) {
199
+ const signals = [];
200
+ // Postcode — outside the address span only.
201
+ POSTCODE_PATTERN.lastIndex = 0;
202
+ let pc;
203
+ while ((pc = POSTCODE_PATTERN.exec(value)) !== null) {
204
+ if (pc.index >= addressStart && pc.index + pc[0].length <= addressEnd)
205
+ continue;
206
+ signals.push(`postcode:${pc[0]}`);
207
+ break;
208
+ }
209
+ // Location — outside the address span only.
210
+ LOCATION_PATTERN.lastIndex = 0;
211
+ let loc;
212
+ while ((loc = LOCATION_PATTERN.exec(value)) !== null) {
213
+ if (loc.index >= addressStart && loc.index + loc[0].length <= addressEnd)
214
+ continue;
215
+ signals.push(`location:${loc[0]}`);
216
+ break;
217
+ }
218
+ return signals;
219
+ }
220
+ function confidenceFor(signals) {
221
+ const hasPostcode = signals.some((s) => s.startsWith("postcode:"));
222
+ const hasLocation = signals.some((s) => s.startsWith("location:"));
223
+ if (hasPostcode && hasLocation)
224
+ return 0.9;
225
+ if (hasPostcode || hasLocation)
226
+ return 0.7;
227
+ return 0.5;
228
+ }
229
+ /**
230
+ * Detects NZ street addresses via shape + postcode + gazetteer signals.
231
+ *
232
+ * Emits a finding for each street-shape match. Confidence reflects how
233
+ * many corroborating signals (postcode, NZ region / city / suburb) are
234
+ * present in the same value.
235
+ */
236
+ class AddressDetector {
237
+ constructor() {
238
+ this.name = "address";
239
+ this.severity = "medium";
240
+ }
241
+ scan(value) {
242
+ const findings = [];
243
+ ADDRESS_PATTERN.lastIndex = 0;
244
+ let match;
245
+ while ((match = ADDRESS_PATTERN.exec(value)) !== null) {
246
+ const raw = match[1].trim();
247
+ const signals = supportingSignals(value, match.index, match.index + match[1].length);
248
+ findings.push({
249
+ detector: this.name,
250
+ severity: this.severity,
251
+ value: raw,
252
+ start: match.index,
253
+ end: match.index + match[1].length,
254
+ confidence: confidenceFor(signals),
255
+ context: { signals },
256
+ });
257
+ }
258
+ return findings;
259
+ }
260
+ }
261
+ exports.AddressDetector = AddressDetector;
262
+ //# sourceMappingURL=address.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"address.js","sourceRoot":"","sources":["../../src/detectors/address.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Base detector interface and shared types.
3
+ */
4
+ /**
5
+ * Severity of a Privacy Act 2020 finding.
6
+ *
7
+ * - HIGH — directly identifying, regulated identifiers (IRD, NHI, driver licence).
8
+ * - MEDIUM — quasi-identifiers that combine readily (phone, address).
9
+ * - LOW — context-sensitive signals (te reo names, generic name tokens).
10
+ */
11
+ export type Severity = "high" | "medium" | "low";
12
+ /** A single PII match within a value. */
13
+ export interface Finding {
14
+ /** Detector name (e.g. `"ird"`, `"nhi"`). */
15
+ detector: string;
16
+ /** Severity of the finding. */
17
+ severity: Severity;
18
+ /** The matched substring (raw). */
19
+ value: string;
20
+ /** Zero-indexed character offset within the source value. */
21
+ start: number;
22
+ /** Exclusive end offset. */
23
+ end: number;
24
+ /** Detector confidence, 0..1. 1.0 for checksum-verified matches. */
25
+ confidence: number;
26
+ /** Detector-specific context (e.g. normalised form). */
27
+ context: Record<string, unknown>;
28
+ }
29
+ /**
30
+ * Abstract base for all PII detectors.
31
+ *
32
+ * Implementations must be stateless — a single instance may be called
33
+ * across many rows / columns of a dataset.
34
+ */
35
+ export interface Detector {
36
+ /** Machine-readable detector name (e.g. `"ird"`). */
37
+ readonly name: string;
38
+ /** Severity emitted by this detector. */
39
+ readonly severity: Severity;
40
+ /** Scan a single string value and yield findings. */
41
+ scan(value: string): Finding[];
42
+ }
43
+ //# sourceMappingURL=base.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../src/detectors/base.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;;GAMG;AACH,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;AAEjD,yCAAyC;AACzC,MAAM,WAAW,OAAO;IACtB,6CAA6C;IAC7C,QAAQ,EAAE,MAAM,CAAC;IACjB,+BAA+B;IAC/B,QAAQ,EAAE,QAAQ,CAAC;IACnB,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,6DAA6D;IAC7D,KAAK,EAAE,MAAM,CAAC;IACd,4BAA4B;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,oEAAoE;IACpE,UAAU,EAAE,MAAM,CAAC;IACnB,wDAAwD;IACxD,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED;;;;;GAKG;AACH,MAAM,WAAW,QAAQ;IACvB,qDAAqD;IACrD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,yCAAyC;IACzC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,qDAAqD;IACrD,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,EAAE,CAAC;CAChC"}
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ /**
3
+ * Base detector interface and shared types.
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ //# sourceMappingURL=base.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.js","sourceRoot":"","sources":["../../src/detectors/base.ts"],"names":[],"mappings":";AAAA;;GAEG"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * NZ driver licence number detector.
3
+ *
4
+ * NZ driver licence numbers are issued by Waka Kotahi | NZ Transport Agency
5
+ * in the format `[A-Z]{2}\d{6}` — two uppercase letters followed by six
6
+ * digits, e.g. `BQ739482` or `UE093153`. The licence number remains the
7
+ * same when a new card is issued; the three-digit card version number
8
+ * printed on the card is per-issue and is not detected by this module.
9
+ *
10
+ * Unlike IRD and NHI numbers, NZTA does NOT publish a check-digit algorithm
11
+ * for driver licence numbers. This means a regex alone produces many false
12
+ * positives on dataset columns containing 2-letter prefixed codes (order
13
+ * IDs, SKUs, flight references). To compensate, this detector lowers
14
+ * confidence when no contextual keyword (`licence`, `license`, `driver`,
15
+ * `DL`) appears within a 300-character window of the match — the same
16
+ * approach used by Microsoft Purview's NZ driver licence sensitive-
17
+ * information type.
18
+ *
19
+ * Findings are emitted at confidence 0.9 when a keyword is nearby, and
20
+ * confidence 0.5 otherwise. Downstream code may filter on confidence to
21
+ * trade off precision against recall.
22
+ *
23
+ * TypeScript port of `src/nz_privacy_auditor/detectors/driver_licence.py`.
24
+ */
25
+ import type { Detector, Finding, Severity } from "./base";
26
+ /**
27
+ * Detects NZ driver licence numbers (`[A-Z]{2}\d{6}`).
28
+ *
29
+ * Confidence is 0.9 when a contextual keyword (licence, license, driver,
30
+ * DL, NZTA, Waka Kotahi) is found within ±300 characters of the match,
31
+ * and 0.5 otherwise. There is no public NZTA checksum to validate against.
32
+ */
33
+ export declare class DriverLicenceDetector implements Detector {
34
+ readonly name = "driver_licence";
35
+ readonly severity: Severity;
36
+ scan(value: string): Finding[];
37
+ }
38
+ //# sourceMappingURL=driver_licence.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"driver_licence.d.ts","sourceRoot":"","sources":["../../src/detectors/driver_licence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAuB1D;;;;;;GAMG;AACH,qBAAa,qBAAsB,YAAW,QAAQ;IACpD,QAAQ,CAAC,IAAI,oBAAoB;IACjC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAU;IAErC,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,EAAE;CAsB/B"}
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ /**
3
+ * NZ driver licence number detector.
4
+ *
5
+ * NZ driver licence numbers are issued by Waka Kotahi | NZ Transport Agency
6
+ * in the format `[A-Z]{2}\d{6}` — two uppercase letters followed by six
7
+ * digits, e.g. `BQ739482` or `UE093153`. The licence number remains the
8
+ * same when a new card is issued; the three-digit card version number
9
+ * printed on the card is per-issue and is not detected by this module.
10
+ *
11
+ * Unlike IRD and NHI numbers, NZTA does NOT publish a check-digit algorithm
12
+ * for driver licence numbers. This means a regex alone produces many false
13
+ * positives on dataset columns containing 2-letter prefixed codes (order
14
+ * IDs, SKUs, flight references). To compensate, this detector lowers
15
+ * confidence when no contextual keyword (`licence`, `license`, `driver`,
16
+ * `DL`) appears within a 300-character window of the match — the same
17
+ * approach used by Microsoft Purview's NZ driver licence sensitive-
18
+ * information type.
19
+ *
20
+ * Findings are emitted at confidence 0.9 when a keyword is nearby, and
21
+ * confidence 0.5 otherwise. Downstream code may filter on confidence to
22
+ * trade off precision against recall.
23
+ *
24
+ * TypeScript port of `src/nz_privacy_auditor/detectors/driver_licence.py`.
25
+ */
26
+ Object.defineProperty(exports, "__esModule", { value: true });
27
+ exports.DriverLicenceDetector = void 0;
28
+ // Two letters + six digits, case-insensitive.
29
+ const LICENCE_PATTERN = /\b([A-Z]{2}\d{6})\b/gi;
30
+ // Context keywords. Case-insensitive whole-word match within the proximity
31
+ // window. `DL` is constrained to upper-case-only via a separate pattern
32
+ // below to avoid matching the common English word "dl" in chemistry / units.
33
+ const KEYWORD_PATTERN = /\b(?:licen[cs]e|driver(?:'?s)?|driver\s*licen[cs]e|driving\s*licen[cs]e|nzta|waka\s*kotahi)\b/i;
34
+ const DL_PATTERN = /\bDL\b/;
35
+ // Proximity window (chars) used to look for a contextual keyword around the
36
+ // matched licence-shaped token. Matches Microsoft Purview's NZ DLP setting.
37
+ const PROXIMITY = 300;
38
+ function hasKeywordNear(value, start, end) {
39
+ const lo = Math.max(0, start - PROXIMITY);
40
+ const hi = Math.min(value.length, end + PROXIMITY);
41
+ const window = value.slice(lo, hi);
42
+ return KEYWORD_PATTERN.test(window) || DL_PATTERN.test(window);
43
+ }
44
+ /**
45
+ * Detects NZ driver licence numbers (`[A-Z]{2}\d{6}`).
46
+ *
47
+ * Confidence is 0.9 when a contextual keyword (licence, license, driver,
48
+ * DL, NZTA, Waka Kotahi) is found within ±300 characters of the match,
49
+ * and 0.5 otherwise. There is no public NZTA checksum to validate against.
50
+ */
51
+ class DriverLicenceDetector {
52
+ constructor() {
53
+ this.name = "driver_licence";
54
+ this.severity = "high";
55
+ }
56
+ scan(value) {
57
+ const findings = [];
58
+ LICENCE_PATTERN.lastIndex = 0;
59
+ let match;
60
+ while ((match = LICENCE_PATTERN.exec(value)) !== null) {
61
+ const raw = match[1];
62
+ const hasKw = hasKeywordNear(value, match.index, match.index + raw.length);
63
+ findings.push({
64
+ detector: this.name,
65
+ severity: this.severity,
66
+ value: raw,
67
+ start: match.index,
68
+ end: match.index + raw.length,
69
+ confidence: hasKw ? 0.9 : 0.5,
70
+ context: {
71
+ normalised: raw.toUpperCase(),
72
+ keyword_proximity: hasKw,
73
+ },
74
+ });
75
+ }
76
+ return findings;
77
+ }
78
+ }
79
+ exports.DriverLicenceDetector = DriverLicenceDetector;
80
+ //# sourceMappingURL=driver_licence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"driver_licence.js","sourceRoot":"","sources":["../../src/detectors/driver_licence.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;;;AAIH,8CAA8C;AAC9C,MAAM,eAAe,GAAG,uBAAuB,CAAC;AAEhD,2EAA2E;AAC3E,wEAAwE;AACxE,6EAA6E;AAC7E,MAAM,eAAe,GACnB,gGAAgG,CAAC;AACnG,MAAM,UAAU,GAAG,QAAQ,CAAC;AAE5B,4EAA4E;AAC5E,4EAA4E;AAC5E,MAAM,SAAS,GAAG,GAAG,CAAC;AAEtB,SAAS,cAAc,CAAC,KAAa,EAAE,KAAa,EAAE,GAAW;IAC/D,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,SAAS,CAAC,CAAC;IAC1C,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,GAAG,SAAS,CAAC,CAAC;IACnD,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;IACnC,OAAO,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AACjE,CAAC;AAED;;;;;;GAMG;AACH,MAAa,qBAAqB;IAAlC;QACW,SAAI,GAAG,gBAAgB,CAAC;QACxB,aAAQ,GAAa,MAAM,CAAC;IAwBvC,CAAC;IAtBC,IAAI,CAAC,KAAa;QAChB,MAAM,QAAQ,GAAc,EAAE,CAAC;QAC/B,eAAe,CAAC,SAAS,GAAG,CAAC,CAAC;QAC9B,IAAI,KAA6B,CAAC;QAClC,OAAO,CAAC,KAAK,GAAG,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YACtD,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC;YACtB,MAAM,KAAK,GAAG,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC;YAC3E,QAAQ,CAAC,IAAI,CAAC;gBACZ,QAAQ,EAAE,IAAI,CAAC,IAAI;gBACnB,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,KAAK,EAAE,GAAG;gBACV,KAAK,EAAE,KAAK,CAAC,KAAK;gBAClB,GAAG,EAAE,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,MAAM;gBAC7B,UAAU,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG;gBAC7B,OAAO,EAAE;oBACP,UAAU,EAAE,GAAG,CAAC,WAAW,EAAE;oBAC7B,iBAAiB,EAAE,KAAK;iBACzB;aACF,CAAC,CAAC;QACL,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF;AA1BD,sDA0BC"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * IRD (Inland Revenue Department) number detector.
3
+ *
4
+ * NZ IRD numbers are 8 or 9 digits with a mod-11 check digit. The algorithm
5
+ * is published by Inland Revenue and uses a primary weight set, falling back
6
+ * to a secondary weight set when the primary calculation yields a check
7
+ * digit of 10.
8
+ *
9
+ * Reference:
10
+ * https://www.ird.govt.nz/-/media/project/ir/home/documents/digital-service-providers/draft-documents/payday-filing/algorithm-for-ird-numbers.pdf
11
+ *
12
+ * Valid IRD numbers fall between 10,000,000 and ~150,000,000. We use the
13
+ * conservative upper bound of 150,000,000 to reject obviously out-of-range
14
+ * candidates while remaining future-proof.
15
+ *
16
+ * TypeScript port of `src/nz_privacy_auditor/detectors/ird.py`. Test vectors
17
+ * for both implementations live in `fixtures/ird.json`.
18
+ */
19
+ import type { Detector, Finding, Severity } from "./base";
20
+ /**
21
+ * Validate the mod-11 check digit for an 8- or 9-digit IRD string.
22
+ *
23
+ * `digits` must contain only digit characters. Returns true only when the
24
+ * IRD passes range and checksum validation.
25
+ */
26
+ export declare function checksumOk(digits: string): boolean;
27
+ /**
28
+ * Detects NZ Inland Revenue (IRD) numbers via regex + mod-11 checksum.
29
+ *
30
+ * Only checksum-validated matches are emitted. The detector is stateless.
31
+ */
32
+ export declare class IRDDetector implements Detector {
33
+ readonly name = "ird";
34
+ readonly severity: Severity;
35
+ scan(value: string): Finding[];
36
+ }
37
+ //# sourceMappingURL=ird.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ird.d.ts","sourceRoot":"","sources":["../../src/detectors/ird.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAe1D;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CA6BlD;AAED;;;;GAIG;AACH,qBAAa,WAAY,YAAW,QAAQ;IAC1C,QAAQ,CAAC,IAAI,SAAS;IACtB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAU;IAErC,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,EAAE;CAsB/B"}
@@ -0,0 +1,103 @@
1
+ "use strict";
2
+ /**
3
+ * IRD (Inland Revenue Department) number detector.
4
+ *
5
+ * NZ IRD numbers are 8 or 9 digits with a mod-11 check digit. The algorithm
6
+ * is published by Inland Revenue and uses a primary weight set, falling back
7
+ * to a secondary weight set when the primary calculation yields a check
8
+ * digit of 10.
9
+ *
10
+ * Reference:
11
+ * https://www.ird.govt.nz/-/media/project/ir/home/documents/digital-service-providers/draft-documents/payday-filing/algorithm-for-ird-numbers.pdf
12
+ *
13
+ * Valid IRD numbers fall between 10,000,000 and ~150,000,000. We use the
14
+ * conservative upper bound of 150,000,000 to reject obviously out-of-range
15
+ * candidates while remaining future-proof.
16
+ *
17
+ * TypeScript port of `src/nz_privacy_auditor/detectors/ird.py`. Test vectors
18
+ * for both implementations live in `fixtures/ird.json`.
19
+ */
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ exports.IRDDetector = void 0;
22
+ exports.checksumOk = checksumOk;
23
+ // IRD numbers appear as 8 or 9 digit runs, optionally hyphen- or space-separated
24
+ // in groups like 49-091-850 or 49 091 850 or 049091850.
25
+ const IRD_PATTERN = /\b(\d{2,3}[-\s]?\d{3}[-\s]?\d{3})\b/g;
26
+ // Inland Revenue's published weight sets.
27
+ const PRIMARY_WEIGHTS = [3, 2, 7, 6, 5, 4, 3, 2];
28
+ const SECONDARY_WEIGHTS = [7, 4, 3, 2, 5, 2, 7, 6];
29
+ // IRDs below 10_000_000 are not issued.
30
+ const MIN_IRD = 10000000;
31
+ // Upper sanity bound; IR is currently issuing in the 100M+ range.
32
+ const MAX_IRD = 150000000;
33
+ /**
34
+ * Validate the mod-11 check digit for an 8- or 9-digit IRD string.
35
+ *
36
+ * `digits` must contain only digit characters. Returns true only when the
37
+ * IRD passes range and checksum validation.
38
+ */
39
+ function checksumOk(digits) {
40
+ if (![8, 9].includes(digits.length))
41
+ return false;
42
+ if (!/^\d+$/.test(digits))
43
+ return false;
44
+ // Left-pad 8-digit IRDs to 9 digits for uniform handling.
45
+ const padded = digits.padStart(9, "0");
46
+ const body = padded.slice(0, 8);
47
+ const check = Number(padded[8]);
48
+ const bodyInt = Number(padded);
49
+ if (bodyInt < MIN_IRD || bodyInt > MAX_IRD)
50
+ return false;
51
+ const calc = (weights) => {
52
+ let total = 0;
53
+ for (let i = 0; i < 8; i++) {
54
+ total += Number(body[i]) * weights[i];
55
+ }
56
+ const rem = total % 11;
57
+ return rem === 0 ? 0 : 11 - rem;
58
+ };
59
+ const primary = calc(PRIMARY_WEIGHTS);
60
+ if (primary < 10)
61
+ return primary === check;
62
+ // Primary produced 10 — fall back to secondary weights.
63
+ const secondary = calc(SECONDARY_WEIGHTS);
64
+ // Number is invalid per IR spec if secondary also yields 10.
65
+ if (secondary === 10)
66
+ return false;
67
+ return secondary === check;
68
+ }
69
+ /**
70
+ * Detects NZ Inland Revenue (IRD) numbers via regex + mod-11 checksum.
71
+ *
72
+ * Only checksum-validated matches are emitted. The detector is stateless.
73
+ */
74
+ class IRDDetector {
75
+ constructor() {
76
+ this.name = "ird";
77
+ this.severity = "high";
78
+ }
79
+ scan(value) {
80
+ const findings = [];
81
+ // Reset lastIndex — the regex is global and shared across calls.
82
+ IRD_PATTERN.lastIndex = 0;
83
+ let match;
84
+ while ((match = IRD_PATTERN.exec(value)) !== null) {
85
+ const raw = match[1];
86
+ const digits = raw.replace(/[-\s]/g, "");
87
+ if (checksumOk(digits)) {
88
+ findings.push({
89
+ detector: this.name,
90
+ severity: this.severity,
91
+ value: raw,
92
+ start: match.index,
93
+ end: match.index + raw.length,
94
+ confidence: 1.0,
95
+ context: { normalised: digits },
96
+ });
97
+ }
98
+ }
99
+ return findings;
100
+ }
101
+ }
102
+ exports.IRDDetector = IRDDetector;
103
+ //# sourceMappingURL=ird.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ird.js","sourceRoot":"","sources":["../../src/detectors/ird.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Te reo Māori personal-name detector.
3
+ *
4
+ * Detects predominantly Māori given names and surnames from a curated
5
+ * gazetteer. The detector is **macron-aware**: a value like `Tāne` and its
6
+ * non-macron form `Tane` both match the canonical entry. Confidence is
7
+ * higher (0.9) when the input preserved the macron — a signal that the
8
+ * data was entered with cultural care — and lower (0.7) otherwise.
9
+ *
10
+ * Severity is LOW because a personal name on its own is not necessarily
11
+ * identifying under the Privacy Act 2020. The detector exists so that
12
+ * downstream consumers can apply additional care to records that contain
13
+ * culturally significant te reo Māori identifiers (e.g. IPP 4 collection
14
+ * manner, IPP 8 accuracy obligations around name spelling and macron
15
+ * preservation).
16
+ *
17
+ * TypeScript port of `src/nz_privacy_auditor/detectors/maori_name.py`. The
18
+ * name lists below are verbatim mirrors of the Python `_GIVEN_NAMES` and
19
+ * `_SURNAMES` sets — any change to one must be applied to the other.
20
+ */
21
+ import type { Detector, Finding, Severity } from "./base";
22
+ /** Casefold and strip combining marks (macrons) for fuzzy matching. */
23
+ export declare function foldMacrons(s: string): string;
24
+ /**
25
+ * Detects te reo Māori personal names from a curated gazetteer.
26
+ *
27
+ * The detector is macron-aware and case-insensitive. Findings carry the
28
+ * canonical macron-preserved form in `context.canonical` even when the
29
+ * input did not use macrons.
30
+ */
31
+ export declare class MaoriNameDetector implements Detector {
32
+ readonly name = "maori_name";
33
+ readonly severity: Severity;
34
+ scan(value: string): Finding[];
35
+ }
36
+ //# sourceMappingURL=maori_name.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"maori_name.d.ts","sourceRoot":"","sources":["../../src/detectors/maori_name.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAoK1D,uEAAuE;AACvE,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE7C;AAiCD;;;;;;GAMG;AACH,qBAAa,iBAAkB,YAAW,QAAQ;IAChD,QAAQ,CAAC,IAAI,gBAAgB;IAC7B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAS;IAEpC,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,EAAE;CAyB/B"}