|
16 | 16 | 'use strict';
|
17 | 17 |
|
18 | 18 | const path = require('path');
|
19 |
| -const assert = require('assert'); |
| 19 | +const {assert} = require('chai'); |
20 | 20 | const fs = require('fs');
|
21 |
| -const tools = require('@google-cloud/nodejs-repo-tools'); |
| 21 | +const execa = require('execa'); |
22 | 22 |
|
23 | 23 | const cmd = 'node deid.js';
|
24 |
| -const cwd = path.join(__dirname, '..'); |
25 |
| - |
| 24 | +const exec = async cmd => { |
| 25 | + const res = await execa.shell(cmd); |
| 26 | + if (res.stderr) { |
| 27 | + throw new Error(res.stderr); |
| 28 | + } |
| 29 | + return res.stdout; |
| 30 | +}; |
26 | 31 | const harmfulString = 'My SSN is 372819127';
|
27 | 32 | const harmlessString = 'My favorite color is blue';
|
28 |
| - |
29 | 33 | const surrogateType = 'SSN_TOKEN';
|
30 | 34 | let labeledFPEString;
|
31 |
| - |
32 | 35 | const wrappedKey = process.env.DLP_DEID_WRAPPED_KEY;
|
33 | 36 | const keyName = process.env.DLP_DEID_KEY_NAME;
|
34 |
| - |
35 | 37 | const csvFile = 'resources/dates.csv';
|
36 | 38 | const tempOutputFile = path.join(__dirname, 'temp.result.csv');
|
37 | 39 | const csvContextField = 'name';
|
38 | 40 | const dateShiftAmount = 30;
|
39 | 41 | const dateFields = 'birth_date register_date';
|
40 | 42 |
|
41 |
| -before(tools.checkCredentials); |
42 |
| - |
43 |
| -// deidentify_masking |
44 |
| -it('should mask sensitive data in a string', async () => { |
45 |
| - const output = await tools.runAsync( |
46 |
| - `${cmd} deidMask "${harmfulString}" -m x -n 5`, |
47 |
| - cwd |
48 |
| - ); |
49 |
| - assert.strictEqual(output, 'My SSN is xxxxx9127'); |
50 |
| -}); |
51 |
| - |
52 |
| -it('should ignore insensitive data when masking a string', async () => { |
53 |
| - const output = await tools.runAsync( |
54 |
| - `${cmd} deidMask "${harmlessString}"`, |
55 |
| - cwd |
56 |
| - ); |
57 |
| - assert.strictEqual(output, harmlessString); |
58 |
| -}); |
59 |
| - |
60 |
| -it('should handle masking errors', async () => { |
61 |
| - const output = await tools.runAsync( |
62 |
| - `${cmd} deidMask "${harmfulString}" -n -1`, |
63 |
| - cwd |
64 |
| - ); |
65 |
| - assert.strictEqual( |
66 |
| - new RegExp(/Error in deidentifyWithMask/).test(output), |
67 |
| - true |
68 |
| - ); |
69 |
| -}); |
70 |
| - |
71 |
| -// deidentify_fpe |
72 |
| -it('should FPE encrypt sensitive data in a string', async () => { |
73 |
| - const output = await tools.runAsync( |
74 |
| - `${cmd} deidFpe "${harmfulString}" ${wrappedKey} ${keyName} -a NUMERIC`, |
75 |
| - cwd |
76 |
| - ); |
77 |
| - assert.strictEqual(new RegExp(/My SSN is \d{9}/).test(output), true); |
78 |
| - assert.notStrictEqual(output, harmfulString); |
79 |
| -}); |
80 |
| - |
81 |
| -it('should use surrogate info types in FPE encryption', async () => { |
82 |
| - const output = await tools.runAsync( |
83 |
| - `${cmd} deidFpe "${harmfulString}" ${wrappedKey} ${keyName} -a NUMERIC -s ${surrogateType}`, |
84 |
| - cwd |
85 |
| - ); |
86 |
| - assert.strictEqual( |
87 |
| - new RegExp(/My SSN is SSN_TOKEN\(9\):\d{9}/).test(output), |
88 |
| - true |
89 |
| - ); |
90 |
| - labeledFPEString = output; |
91 |
| -}); |
92 |
| - |
93 |
| -it('should ignore insensitive data when FPE encrypting a string', async () => { |
94 |
| - const output = await tools.runAsync( |
95 |
| - `${cmd} deidFpe "${harmlessString}" ${wrappedKey} ${keyName}`, |
96 |
| - cwd |
97 |
| - ); |
98 |
| - assert.strictEqual(output, harmlessString); |
99 |
| -}); |
100 |
| - |
101 |
| -it('should handle FPE encryption errors', async () => { |
102 |
| - const output = await tools.runAsync( |
103 |
| - `${cmd} deidFpe "${harmfulString}" ${wrappedKey} BAD_KEY_NAME`, |
104 |
| - cwd |
105 |
| - ); |
106 |
| - assert.strictEqual( |
107 |
| - new RegExp(/Error in deidentifyWithFpe/).test(output), |
108 |
| - true |
109 |
| - ); |
110 |
| -}); |
111 |
| - |
112 |
| -// reidentify_fpe |
113 |
| -it('should FPE decrypt surrogate-typed sensitive data in a string', async () => { |
114 |
| - assert.ok(labeledFPEString, 'Verify that FPE encryption succeeded.'); |
115 |
| - const output = await tools.runAsync( |
116 |
| - `${cmd} reidFpe "${labeledFPEString}" ${surrogateType} ${wrappedKey} ${keyName} -a NUMERIC`, |
117 |
| - cwd |
118 |
| - ); |
119 |
| - assert.strictEqual(output, harmfulString); |
120 |
| -}); |
121 |
| - |
122 |
| -it('should handle FPE decryption errors', async () => { |
123 |
| - const output = await tools.runAsync( |
124 |
| - `${cmd} reidFpe "${harmfulString}" ${surrogateType} ${wrappedKey} BAD_KEY_NAME -a NUMERIC`, |
125 |
| - cwd |
126 |
| - ); |
127 |
| - assert.strictEqual( |
128 |
| - new RegExp(/Error in reidentifyWithFpe/).test(output), |
129 |
| - true |
130 |
| - ); |
131 |
| -}); |
132 |
| - |
133 |
| -// deidentify_date_shift |
134 |
| -it('should date-shift a CSV file', async () => { |
135 |
| - const outputCsvFile = 'dates.actual.csv'; |
136 |
| - const output = await tools.runAsync( |
137 |
| - `${cmd} deidDateShift "${csvFile}" "${outputCsvFile}" ${dateShiftAmount} ${dateShiftAmount} ${dateFields}`, |
138 |
| - cwd |
139 |
| - ); |
140 |
| - assert.strictEqual( |
141 |
| - output.includes(`Successfully saved date-shift output to ${outputCsvFile}`), |
142 |
| - true |
143 |
| - ); |
144 |
| - assert.notStrictEqual( |
145 |
| - fs.readFileSync(outputCsvFile).toString(), |
146 |
| - fs.readFileSync(csvFile).toString() |
147 |
| - ); |
148 |
| -}); |
149 |
| - |
150 |
| -it('should date-shift a CSV file using a context field', async () => { |
151 |
| - const outputCsvFile = 'dates-context.actual.csv'; |
152 |
| - const expectedCsvFile = |
153 |
| - 'system-test/resources/date-shift-context.expected.csv'; |
154 |
| - const output = await tools.runAsync( |
155 |
| - `${cmd} deidDateShift "${csvFile}" "${outputCsvFile}" ${dateShiftAmount} ${dateShiftAmount} ${dateFields} -f ${csvContextField} -n ${keyName} -w ${wrappedKey}`, |
156 |
| - cwd |
157 |
| - ); |
158 |
| - assert.strictEqual( |
159 |
| - output.includes(`Successfully saved date-shift output to ${outputCsvFile}`), |
160 |
| - true |
161 |
| - ); |
162 |
| - assert.strictEqual( |
163 |
| - fs.readFileSync(outputCsvFile).toString(), |
164 |
| - fs.readFileSync(expectedCsvFile).toString() |
165 |
| - ); |
166 |
| -}); |
167 |
| - |
168 |
| -it('should require all-or-none of {contextField, wrappedKey, keyName}', async () => { |
169 |
| - const output = await tools.runAsync( |
170 |
| - `${cmd} deidDateShift "${csvFile}" "${tempOutputFile}" ${dateShiftAmount} ${dateShiftAmount} ${dateFields} -f ${csvContextField} -n ${keyName}`, |
171 |
| - cwd |
172 |
| - ); |
173 |
| - |
174 |
| - assert.strictEqual( |
175 |
| - output.includes('You must set either ALL or NONE of'), |
176 |
| - true |
177 |
| - ); |
178 |
| -}); |
179 |
| - |
180 |
| -it('should handle date-shift errors', async () => { |
181 |
| - const output = await tools.runAsync( |
182 |
| - `${cmd} deidDateShift "${csvFile}" "${tempOutputFile}" ${dateShiftAmount} ${dateShiftAmount}`, |
183 |
| - cwd |
184 |
| - ); |
185 |
| - assert.strictEqual( |
186 |
| - new RegExp(/Error in deidentifyWithDateShift/).test(output), |
187 |
| - true |
188 |
| - ); |
| 43 | +describe('deid', () => { |
| 44 | + // deidentify_masking |
| 45 | + it('should mask sensitive data in a string', async () => { |
| 46 | + const output = await exec(`${cmd} deidMask "${harmfulString}" -m x -n 5`); |
| 47 | + assert.strictEqual(output, 'My SSN is xxxxx9127'); |
| 48 | + }); |
| 49 | + |
| 50 | + it('should ignore insensitive data when masking a string', async () => { |
| 51 | + const output = await exec(`${cmd} deidMask "${harmlessString}"`); |
| 52 | + assert.strictEqual(output, harmlessString); |
| 53 | + }); |
| 54 | + |
| 55 | + it('should handle masking errors', async () => { |
| 56 | + const output = await exec(`${cmd} deidMask "${harmfulString}" -n -1`); |
| 57 | + assert.match(output, /Error in deidentifyWithMask/); |
| 58 | + }); |
| 59 | + |
| 60 | + // deidentify_fpe |
| 61 | + it('should FPE encrypt sensitive data in a string', async () => { |
| 62 | + const output = await exec( |
| 63 | + `${cmd} deidFpe "${harmfulString}" ${wrappedKey} ${keyName} -a NUMERIC` |
| 64 | + ); |
| 65 | + assert.match(output, /My SSN is \d{9}/); |
| 66 | + assert.notStrictEqual(output, harmfulString); |
| 67 | + }); |
| 68 | + |
| 69 | + it('should use surrogate info types in FPE encryption', async () => { |
| 70 | + const output = await exec( |
| 71 | + `${cmd} deidFpe "${harmfulString}" ${wrappedKey} ${keyName} -a NUMERIC -s ${surrogateType}` |
| 72 | + ); |
| 73 | + assert.match(output, /My SSN is SSN_TOKEN\(9\):\d{9}/); |
| 74 | + labeledFPEString = output; |
| 75 | + }); |
| 76 | + |
| 77 | + it('should ignore insensitive data when FPE encrypting a string', async () => { |
| 78 | + const output = await exec( |
| 79 | + `${cmd} deidFpe "${harmlessString}" ${wrappedKey} ${keyName}` |
| 80 | + ); |
| 81 | + assert.strictEqual(output, harmlessString); |
| 82 | + }); |
| 83 | + |
| 84 | + it('should handle FPE encryption errors', async () => { |
| 85 | + const output = await exec( |
| 86 | + `${cmd} deidFpe "${harmfulString}" ${wrappedKey} BAD_KEY_NAME` |
| 87 | + ); |
| 88 | + assert.match(output, /Error in deidentifyWithFpe/); |
| 89 | + }); |
| 90 | + |
| 91 | + // reidentify_fpe |
| 92 | + it('should FPE decrypt surrogate-typed sensitive data in a string', async () => { |
| 93 | + assert.ok(labeledFPEString, 'Verify that FPE encryption succeeded.'); |
| 94 | + const output = await exec( |
| 95 | + `${cmd} reidFpe "${labeledFPEString}" ${surrogateType} ${wrappedKey} ${keyName} -a NUMERIC` |
| 96 | + ); |
| 97 | + assert.strictEqual(output, harmfulString); |
| 98 | + }); |
| 99 | + |
| 100 | + it('should handle FPE decryption errors', async () => { |
| 101 | + const output = await exec( |
| 102 | + `${cmd} reidFpe "${harmfulString}" ${surrogateType} ${wrappedKey} BAD_KEY_NAME -a NUMERIC` |
| 103 | + ); |
| 104 | + assert.match(output, /Error in reidentifyWithFpe/); |
| 105 | + }); |
| 106 | + |
| 107 | + // deidentify_date_shift |
| 108 | + it('should date-shift a CSV file', async () => { |
| 109 | + const outputCsvFile = 'dates.actual.csv'; |
| 110 | + const output = await exec( |
| 111 | + `${cmd} deidDateShift "${csvFile}" "${outputCsvFile}" ${dateShiftAmount} ${dateShiftAmount} ${dateFields}` |
| 112 | + ); |
| 113 | + assert.match( |
| 114 | + output, |
| 115 | + new RegExp(`Successfully saved date-shift output to ${outputCsvFile}`) |
| 116 | + ); |
| 117 | + assert.notStrictEqual( |
| 118 | + fs.readFileSync(outputCsvFile).toString(), |
| 119 | + fs.readFileSync(csvFile).toString() |
| 120 | + ); |
| 121 | + }); |
| 122 | + |
| 123 | + it('should date-shift a CSV file using a context field', async () => { |
| 124 | + const outputCsvFile = 'dates-context.actual.csv'; |
| 125 | + const expectedCsvFile = |
| 126 | + 'system-test/resources/date-shift-context.expected.csv'; |
| 127 | + const output = await exec( |
| 128 | + `${cmd} deidDateShift "${csvFile}" "${outputCsvFile}" ${dateShiftAmount} ${dateShiftAmount} ${dateFields} -f ${csvContextField} -n ${keyName} -w ${wrappedKey}` |
| 129 | + ); |
| 130 | + assert.match( |
| 131 | + output, |
| 132 | + new RegExp(`Successfully saved date-shift output to ${outputCsvFile}`) |
| 133 | + ); |
| 134 | + assert.strictEqual( |
| 135 | + fs.readFileSync(outputCsvFile).toString(), |
| 136 | + fs.readFileSync(expectedCsvFile).toString() |
| 137 | + ); |
| 138 | + }); |
| 139 | + |
| 140 | + it('should require all-or-none of {contextField, wrappedKey, keyName}', async () => { |
| 141 | + const output = await exec( |
| 142 | + `${cmd} deidDateShift "${csvFile}" "${tempOutputFile}" ${dateShiftAmount} ${dateShiftAmount} ${dateFields} -f ${csvContextField} -n ${keyName}` |
| 143 | + ); |
| 144 | + assert.match(output, /You must set either ALL or NONE of/); |
| 145 | + }); |
| 146 | + |
| 147 | + it('should handle date-shift errors', async () => { |
| 148 | + const output = await exec( |
| 149 | + `${cmd} deidDateShift "${csvFile}" "${tempOutputFile}" ${dateShiftAmount} ${dateShiftAmount}` |
| 150 | + ); |
| 151 | + assert.match(output, /Error in deidentifyWithDateShift/); |
| 152 | + }); |
189 | 153 | });
|
0 commit comments