36 lines
1.4 KiB
Python
36 lines
1.4 KiB
Python
from __future__ import annotations
|
|
|
|
import unittest
|
|
|
|
from govoplan_core.security.redaction import contains_plain_secret, redact_secret_values
|
|
|
|
|
|
class SecurityRedactionTests(unittest.TestCase):
|
|
def test_structured_payload_redaction_covers_nested_container_shapes(self) -> None:
|
|
payload = {
|
|
"request": {
|
|
"Authorization": "Bearer must-not-leak",
|
|
"headers": [{"x-api-key": "must-not-leak"}],
|
|
},
|
|
"records": (
|
|
{"clientSecret": "must-not-leak", "status": "ok"},
|
|
{"credential_ref": "credential-1"},
|
|
),
|
|
}
|
|
|
|
redacted = redact_secret_values(payload)
|
|
|
|
self.assertEqual("<redacted>", redacted["request"]["Authorization"]) # type: ignore[index]
|
|
self.assertEqual("<redacted>", redacted["request"]["headers"][0]["x-api-key"]) # type: ignore[index]
|
|
self.assertEqual("<redacted>", redacted["records"][0]["clientSecret"]) # type: ignore[index]
|
|
self.assertEqual("<redacted>", redacted["records"][1]["credential_ref"]) # type: ignore[index]
|
|
self.assertNotIn("must-not-leak", repr(redacted))
|
|
|
|
def test_plain_secret_detection_descends_into_lists_and_tuples(self) -> None:
|
|
self.assertTrue(contains_plain_secret([{"metadata": ({"private-key": "secret"},)}]))
|
|
self.assertFalse(contains_plain_secret([{"credential_ref": "credential-1"}]))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|