diff --git a/pyproject.toml b/pyproject.toml index e5403ce..5990163 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "hatchling.build" name = "supergood" description = "The Python client for Supergood" readme = "README.md" -version= "1.1.9" +version= "1.1.10" requires-python = ">=3.7" authors = [ { name = "Alex Klarfeld" }, diff --git a/src/supergood/helpers.py b/src/supergood/helpers.py index d8eaf78..2b21bdf 100644 --- a/src/supergood/helpers.py +++ b/src/supergood/helpers.py @@ -1,6 +1,7 @@ import gzip import hashlib import json +import re import sys from base64 import b64encode from typing import Tuple @@ -117,8 +118,10 @@ def redact_all_helper(elem, path=[], allowed=[]): skeys += new_skeys else: key_path = ".".join(path) - if key_path in allowed: - # this is an allowed key. We do not want to redact it + # check to see if the generic keypath (no array indexes) is an allowed key + generic_keypath = re.sub(r"\[\d+\]", "[]", key_path) + if generic_keypath in allowed: + # do not mark allowed keys to be redacted return [] (data_type, data_length) = describe_data(elem) skeys.append( diff --git a/tests/redaction/test_redact_by_default.py b/tests/redaction/test_redact_by_default.py index 57f8d82..1417267 100644 --- a/tests/redaction/test_redact_by_default.py +++ b/tests/redaction/test_redact_by_default.py @@ -13,6 +13,7 @@ keys=[ ("responseBody.string", "ALLOW"), ("responseBody.other_string", "REDACT"), + ("responseBody[].data[].string", "ALLOW"), ] ), "config": get_config(redact_by_default=True), @@ -47,3 +48,42 @@ def test_redact_by_default(self, httpserver, supergood_client): assert filtered[0]["keyPath"] == "responseBody.other_string" assert filtered[0]["type"] == "string" assert filtered[0]["length"] == 3 + + # Test that allowed keys with array indexers are not redacted + def test_allowed_keys_of_arrays(self, httpserver, supergood_client): + httpserver.expect_request("/200").respond_with_json( + [ + { + "data": [ + {"string": "abc", "other_string": "sensitive"}, + {"string": "abc", "other_string": "sensitive"}, + ] + } + ] + ) + requests.get(httpserver.url_for("/200")) + supergood_client.flush_cache() + args = Api.post_events.call_args[0][0] + response_body = args[0]["response"]["body"] + metadata = args[0]["metadata"] + assert len(response_body) == 1 + assert len(response_body[0]["data"]) == 2 + assert response_body[0]["data"][0]["string"] == "abc" + assert response_body[0]["data"][1]["string"] == "abc" + + assert response_body[0]["data"][0]["other_string"] == None + assert response_body[0]["data"][1]["other_string"] == None + + assert len(metadata["sensitiveKeys"]) > 0 + # # There are a bunch of request/response headers. Filter for just responseBody + filtered = list( + filter( + lambda x: x["keyPath"].startswith("responseBody"), + metadata["sensitiveKeys"], + ) + ) + assert len(filtered) == 2 + assert filtered[0]["keyPath"] == "responseBody[0].data[0].other_string" + assert filtered[1]["keyPath"] == "responseBody[0].data[1].other_string" + assert filtered[0]["type"] == "string" and filtered[1]["type"] == "string" + assert filtered[0]["length"] == 9 and filtered[1]["length"] == 9