|
7 | 7 | import static org.junit.jupiter.api.Assertions.assertEquals;
|
8 | 8 |
|
9 | 9 | import com.fasterxml.jackson.databind.JsonNode;
|
| 10 | +import com.fasterxml.jackson.databind.ObjectMapper; |
10 | 11 | import com.google.common.collect.ImmutableMap;
|
11 | 12 | import io.airbyte.commons.json.Jsons;
|
| 13 | +import java.io.IOException; |
| 14 | +import java.io.InputStream; |
| 15 | +import java.util.stream.Stream; |
12 | 16 | import org.junit.jupiter.api.Test;
|
| 17 | +import org.junit.jupiter.params.ParameterizedTest; |
| 18 | +import org.junit.jupiter.params.provider.Arguments; |
| 19 | +import org.junit.jupiter.params.provider.MethodSource; |
13 | 20 |
|
14 | 21 | public class JsonSecretsProcessorTest {
|
15 | 22 |
|
@@ -153,163 +160,8 @@ public class JsonSecretsProcessorTest {
|
153 | 160 | + " }\n"
|
154 | 161 | + " }");
|
155 | 162 |
|
156 |
| - private final static String test = """ |
157 |
| - { |
158 |
| - "provider": { |
159 |
| - "bucket": "bucket", |
160 |
| - "endpoint": "", |
161 |
| - "path_prefix": "", |
162 |
| - "aws_access_key_id": "nothingtosee", |
163 |
| - "aws_secret_access_key": "same" |
164 |
| - } |
165 |
| - } |
166 |
| - """; |
167 |
| - |
168 |
| - private final static String testSpecs = |
169 |
| - """ |
170 |
| - { |
171 |
| - "type": "object", |
172 |
| - "title": "S3 Source Spec", |
173 |
| - "required": [ |
174 |
| - "dataset", |
175 |
| - "path_pattern", |
176 |
| - "provider" |
177 |
| - ], |
178 |
| - "properties": { |
179 |
| - "provider": { |
180 |
| - "type": "object", |
181 |
| - "title": "S3: Amazon Web Services", |
182 |
| - "required": [ |
183 |
| - "bucket" |
184 |
| - ], |
185 |
| - "properties": { |
186 |
| - "bucket": { |
187 |
| - "type": "string", |
188 |
| - "title": "Bucket", |
189 |
| - "description": "Name of the S3 bucket where the file(s) exist." |
190 |
| - }, |
191 |
| - "use_ssl": { |
192 |
| - "type": "boolean", |
193 |
| - "title": "Use Ssl", |
194 |
| - "description": "Is remote server using secure SSL/TLS connection" |
195 |
| - }, |
196 |
| - "endpoint": { |
197 |
| - "type": "string", |
198 |
| - "title": "Endpoint", |
199 |
| - "default": "", |
200 |
| - "description": "Endpoint to an S3 compatible service. Leave empty to use AWS." |
201 |
| - }, |
202 |
| - "path_prefix": { |
203 |
| - "type": "string", |
204 |
| - "title": "Path Prefix", |
205 |
| - "default": "", |
206 |
| - "description": "By providing a path-like prefix (e.g. myFolder/thisTable/) under which all the relevant files sit, we can optimise finding these in S3. This is optional but recommended if your bucket contains many folders/files." |
207 |
| - }, |
208 |
| - "verify_ssl_cert": { |
209 |
| - "type": "boolean", |
210 |
| - "title": "Verify Ssl Cert", |
211 |
| - "description": "Allow self signed certificates" |
212 |
| - }, |
213 |
| - "aws_access_key_id": { |
214 |
| - "type": "string", |
215 |
| - "title": "Aws Access Key Id", |
216 |
| - "description": "In order to access private Buckets stored on AWS S3, this connector requires credentials with the proper permissions. If accessing publicly available data, this field is not necessary.", |
217 |
| - "airbyte_secret": true |
218 |
| - }, |
219 |
| - "aws_secret_access_key": { |
220 |
| - "type": "string", |
221 |
| - "title": "Aws Secret Access Key", |
222 |
| - "description": "In order to access private Buckets stored on AWS S3, this connector requires credentials with the proper permissions. If accessing publicly available data, this field is not necessary.", |
223 |
| - "airbyte_secret": true |
224 |
| - } |
225 |
| - } |
226 |
| - } |
227 |
| - } |
228 |
| - } |
229 |
| - """; |
230 |
| - |
231 | 163 | JsonSecretsProcessor processor = new JsonSecretsProcessor();
|
232 | 164 |
|
233 |
| - @Test |
234 |
| - public void testNestedSecrets() { |
235 |
| - final JsonNode obj = Jsons.deserialize(test); |
236 |
| - final JsonNode specObj = Jsons.deserialize(testSpecs); |
237 |
| - final JsonNode sanitized = processor.maskSecrets(obj, specObj); |
238 |
| - |
239 |
| - final JsonNode expected = Jsons.jsonNode(ImmutableMap.builder() |
240 |
| - .put("bucket", "bucket") |
241 |
| - .put("endpoint", "") |
242 |
| - .put("path_prefix", "") |
243 |
| - .put("aws_access_key_id", JsonSecretsProcessor.SECRETS_MASK) |
244 |
| - .put("aws_secret_access_key", JsonSecretsProcessor.SECRETS_MASK).build()); |
245 |
| - assertEquals(expected, sanitized.get("provider")); |
246 |
| - } |
247 |
| - |
248 |
| - @Test |
249 |
| - public void testMaskSecrets() { |
250 |
| - final JsonNode obj = Jsons.jsonNode(ImmutableMap.builder() |
251 |
| - .put("field1", "value1") |
252 |
| - .put("field2", 2) |
253 |
| - .put("secret1", "donttellanyone") |
254 |
| - .put("secret2", "verysecret").build()); |
255 |
| - |
256 |
| - final JsonNode sanitized = processor.maskSecrets(obj, SCHEMA_ONE_LAYER); |
257 |
| - |
258 |
| - final JsonNode expected = Jsons.jsonNode(ImmutableMap.builder() |
259 |
| - .put("field1", "value1") |
260 |
| - .put("field2", 2) |
261 |
| - .put("secret1", JsonSecretsProcessor.SECRETS_MASK) |
262 |
| - .put("secret2", JsonSecretsProcessor.SECRETS_MASK).build()); |
263 |
| - assertEquals(expected, sanitized); |
264 |
| - } |
265 |
| - |
266 |
| - @Test |
267 |
| - public void testMaskSecretsNotInObj() { |
268 |
| - final JsonNode obj = Jsons.jsonNode(ImmutableMap.builder() |
269 |
| - .put("field1", "value1") |
270 |
| - .put("field2", 2).build()); |
271 |
| - |
272 |
| - final JsonNode actual = processor.maskSecrets(obj, SCHEMA_ONE_LAYER); |
273 |
| - |
274 |
| - // Didn't have secrets, no fields should have been impacted. |
275 |
| - assertEquals(obj, actual); |
276 |
| - } |
277 |
| - |
278 |
| - @Test |
279 |
| - public void testMaskSecretInnerObject() { |
280 |
| - final JsonNode oneOf = Jsons.jsonNode(ImmutableMap.builder() |
281 |
| - .put("s3_bucket_name", "name") |
282 |
| - .put("secret_access_key", "secret").build()); |
283 |
| - final JsonNode base = Jsons.jsonNode(ImmutableMap.builder() |
284 |
| - .put("warehouse", "house") |
285 |
| - .put("loading_method", oneOf).build()); |
286 |
| - |
287 |
| - final JsonNode actual = processor.maskSecrets(base, SCHEMA_INNER_OBJECT); |
288 |
| - |
289 |
| - final JsonNode expectedOneOf = Jsons.jsonNode(ImmutableMap.builder() |
290 |
| - .put("s3_bucket_name", "name") |
291 |
| - .put("secret_access_key", JsonSecretsProcessor.SECRETS_MASK) |
292 |
| - .build()); |
293 |
| - final JsonNode expected = Jsons.jsonNode(ImmutableMap.builder() |
294 |
| - .put("warehouse", "house") |
295 |
| - .put("loading_method", expectedOneOf).build()); |
296 |
| - |
297 |
| - assertEquals(expected, actual); |
298 |
| - } |
299 |
| - |
300 |
| - @Test |
301 |
| - public void testMaskSecretNotInInnerObject() { |
302 |
| - final JsonNode base = Jsons.jsonNode(ImmutableMap.builder() |
303 |
| - .put("warehouse", "house").build()); |
304 |
| - |
305 |
| - final JsonNode actual = processor.maskSecrets(base, SCHEMA_INNER_OBJECT); |
306 |
| - |
307 |
| - final JsonNode expected = Jsons.jsonNode(ImmutableMap.builder() |
308 |
| - .put("warehouse", "house").build()); |
309 |
| - |
310 |
| - assertEquals(expected, actual); |
311 |
| - } |
312 |
| - |
313 | 165 | @Test
|
314 | 166 | public void testCopySecrets() {
|
315 | 167 | final JsonNode src = Jsons.jsonNode(ImmutableMap.builder()
|
@@ -431,4 +283,45 @@ void testHandlesSameKeyInOneOf() {
|
431 | 283 | final JsonNode actual = new JsonSecretsProcessor().copySecrets(src, dst, ONE_OF_WITH_SAME_KEY_IN_SUB_SCHEMAS);
|
432 | 284 | }
|
433 | 285 |
|
| 286 | + private static Stream<Arguments> scenarioProvider() { |
| 287 | + return Stream.of( |
| 288 | + Arguments.of("array", true), |
| 289 | + Arguments.of("array", false), |
| 290 | + Arguments.of("array_of_oneof", true), |
| 291 | + Arguments.of("array_of_oneof", false), |
| 292 | + Arguments.of("nested_object", true), |
| 293 | + Arguments.of("nested_object", false), |
| 294 | + Arguments.of("nested_oneof", true), |
| 295 | + Arguments.of("nested_oneof", false), |
| 296 | + Arguments.of("oneof", true), |
| 297 | + Arguments.of("oneof", false), |
| 298 | + Arguments.of("optional_password", true), |
| 299 | + Arguments.of("optional_password", false), |
| 300 | + Arguments.of("postgres_ssh_key", true), |
| 301 | + Arguments.of("postgres_ssh_key", false), |
| 302 | + Arguments.of("simple", true), |
| 303 | + Arguments.of("simple", false)); |
| 304 | + } |
| 305 | + |
| 306 | + @ParameterizedTest |
| 307 | + @MethodSource("scenarioProvider") |
| 308 | + void testSecretScenario(final String folder, final boolean partial) throws IOException { |
| 309 | + final ObjectMapper objectMapper = new ObjectMapper(); |
| 310 | + |
| 311 | + final InputStream specIs = getClass().getClassLoader().getResourceAsStream(folder + "/spec.json"); |
| 312 | + final JsonNode specs = objectMapper.readTree(specIs); |
| 313 | + |
| 314 | + final String inputFilePath = folder + (partial ? "/partial_config.json" : "/full_config.json"); |
| 315 | + final InputStream inputIs = getClass().getClassLoader().getResourceAsStream(inputFilePath); |
| 316 | + final JsonNode input = objectMapper.readTree(inputIs); |
| 317 | + |
| 318 | + final String expectedFilePath = folder + "/expected.json"; |
| 319 | + final InputStream expectedIs = getClass().getClassLoader().getResourceAsStream(expectedFilePath); |
| 320 | + final JsonNode expected = objectMapper.readTree(expectedIs); |
| 321 | + |
| 322 | + final JsonNode actual = processor.maskSecrets(input, specs); |
| 323 | + |
| 324 | + assertEquals(expected, actual); |
| 325 | + } |
| 326 | + |
434 | 327 | }
|
0 commit comments