@@ -0,0 +1,361 @@
1 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ """Tests for navegador.security — sensitive content detection and redaction."""
2 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
3 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ import json
4 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ from pathlib import Path
5 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ from unittest.mock import MagicMock, patch
6 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
7 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ import pytest
8 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ from click.testing import CliRunner
9 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
10 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ from navegador.security import REDACTED, SensitiveContentDetector, SensitiveMatch
11 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
12 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
13 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # ---------------------------------------------------------------------------
14 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # Fixtures
15 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # ---------------------------------------------------------------------------
16 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
17 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
18 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ @pytest.fixture()
19 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def detector():
20 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ return SensitiveContentDetector()
21 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
22 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
23 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # ---------------------------------------------------------------------------
24 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # Pattern detection tests
25 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # ---------------------------------------------------------------------------
26 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
27 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
28 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ class TestAPIKeyDetection:
29 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_aws_akia_key(self, detector):
30 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ text = "key = AKIAIOSFODNN7EXAMPLE"
31 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ matches = detector.scan_content(text)
32 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ names = [m.pattern_name for m in matches]
33 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert "aws_access_key" in names
34 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
35 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_aws_asia_key(self, detector):
36 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # ASIA prefix + exactly 16 uppercase alphanumeric chars = 20-char key
37 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ text = "assume_role_key=ASIAIOSFODNN7EXAMPLE"
38 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ matches = detector.scan_content(text)
39 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ names = [m.pattern_name for m in matches]
40 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert "aws_access_key" in names
41 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
42 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_github_token_ghp(self, detector):
43 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ text = "GITHUB_TOKEN=ghp_aBcDeFgHiJkLmNoPqRsTuVwXyZ123456789012"
44 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ matches = detector.scan_content(text)
45 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ names = [m.pattern_name for m in matches]
46 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert "github_token" in names
47 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
48 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_openai_sk_key(self, detector):
49 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ text = 'api_key = "sk-abcdefghijklmnopqrstuvwxyz12345678901234567890"'
50 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ matches = detector.scan_content(text)
51 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ names = [m.pattern_name for m in matches]
52 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert "api_key_sk" in names
53 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
54 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_generic_api_key_assignment(self, detector):
55 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ text = 'API_KEY = "AbCdEfGhIjKlMnOpQrStUvWxYz123456"'
56 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ matches = detector.scan_content(text)
57 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ names = [m.pattern_name for m in matches]
58 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert "api_key_assignment" in names
59 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
60 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_severity_is_high_for_aws_key(self, detector):
61 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ text = "AKIAIOSFODNN7EXAMPLE"
62 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ matches = detector.scan_content(text)
63 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert any(m.severity == "high" for m in matches)
64 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
65 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_match_text_is_redacted(self, detector):
66 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ text = "AKIAIOSFODNN7EXAMPLE"
67 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ matches = detector.scan_content(text)
68 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert all(m.match_text == REDACTED for m in matches)
69 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
70 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_line_number_is_correct(self, detector):
71 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ text = "# header\nAKIAIOSFODNN7EXAMPLE\n# footer"
72 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ matches = detector.scan_content(text)
73 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ aws_matches = [m for m in matches if m.pattern_name == "aws_access_key"]
74 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert len(aws_matches) >= 1
75 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert aws_matches[0].line_number == 2
76 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
77 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
78 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ class TestPasswordDetection:
79 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_password_equals_string(self, detector):
80 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ text = 'password = "super_s3cr3t_pass"'
81 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ matches = detector.scan_content(text)
82 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ names = [m.pattern_name for m in matches]
83 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert "password_assignment" in names
84 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
85 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_passwd_variant(self, detector):
86 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ text = "passwd = 'hunter2hunter2'"
87 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ matches = detector.scan_content(text)
88 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ names = [m.pattern_name for m in matches]
89 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert "password_assignment" in names
90 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
91 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_secret_key_variant(self, detector):
92 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ text = 'secret = "mysecretvalue123"'
93 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ matches = detector.scan_content(text)
94 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ names = [m.pattern_name for m in matches]
95 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert "password_assignment" in names
96 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
97 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_severity_high(self, detector):
98 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ text = 'password = "hunter2hunter2"'
99 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ matches = detector.scan_content(text)
100 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ pw = [m for m in matches if m.pattern_name == "password_assignment"]
101 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert all(m.severity == "high" for m in pw)
102 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
103 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
104 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ class TestPrivateKeyDetection:
105 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_rsa_private_key_header(self, detector):
106 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ text = "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEA...\n-----END RSA PRIVATE KEY-----"
107 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ matches = detector.scan_content(text)
108 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ names = [m.pattern_name for m in matches]
109 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert "private_key_pem" in names
110 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
111 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_generic_private_key_header(self, detector):
112 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ text = "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w...\n-----END PRIVATE KEY-----"
113 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ matches = detector.scan_content(text)
114 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ names = [m.pattern_name for m in matches]
115 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert "private_key_pem" in names
116 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
117 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_openssh_private_key_header(self, detector):
118 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ text = "-----BEGIN OPENSSH PRIVATE KEY-----\nb3BlbnNzaC1...\n-----END OPENSSH PRIVATE KEY-----"
119 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ matches = detector.scan_content(text)
120 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ names = [m.pattern_name for m in matches]
121 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert "private_key_pem" in names
122 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
123 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_severity_high(self, detector):
124 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ text = "-----BEGIN RSA PRIVATE KEY-----"
125 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ matches = detector.scan_content(text)
126 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ pk = [m for m in matches if m.pattern_name == "private_key_pem"]
127 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert all(m.severity == "high" for m in pk)
128 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
129 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
130 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ class TestConnectionStringDetection:
131 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_postgres_with_credentials(self, detector):
132 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ text = 'DATABASE_URL = "postgresql://admin:[email protected] :5432/mydb"'
133 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ matches = detector.scan_content(text)
134 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ names = [m.pattern_name for m in matches]
135 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert "connection_string" in names
136 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
137 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_mysql_with_credentials(self, detector):
138 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ text = "conn = mysql://user:passw0rd@localhost/schema"
139 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ matches = detector.scan_content(text)
140 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ names = [m.pattern_name for m in matches]
141 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert "connection_string" in names
142 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
143 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_mongodb_with_credentials(self, detector):
144 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ text = 'uri = "mongodb://root:[email protected] :27017/db"'
145 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ matches = detector.scan_content(text)
146 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ names = [m.pattern_name for m in matches]
147 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert "connection_string" in names
148 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
149 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_mongodb_srv_with_credentials(self, detector):
150 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ text = 'uri = "mongodb+srv://admin:[email protected] /mydb"'
151 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ matches = detector.scan_content(text)
152 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ names = [m.pattern_name for m in matches]
153 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert "connection_string" in names
154 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
155 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_severity_high(self, detector):
156 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ text = "postgresql://admin:[email protected] /mydb"
157 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ matches = detector.scan_content(text)
158 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ cs = [m for m in matches if m.pattern_name == "connection_string"]
159 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert all(m.severity == "high" for m in cs)
160 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
161 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
162 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ class TestJWTDetection:
163 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_valid_jwt(self, detector):
164 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # A real-looking but fake JWT
165 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ header = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"
166 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ payload = "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ"
167 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ signature = "SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
168 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ jwt = f"{header}.{payload}.{signature}"
169 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ text = f'Authorization: Bearer {jwt}'
170 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ matches = detector.scan_content(text)
171 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ names = [m.pattern_name for m in matches]
172 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert "jwt_token" in names
173 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
174 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_severity_medium(self, detector):
175 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ header = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"
176 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ payload = "eyJzdWIiOiIxMjM0NTY3ODkwIn0"
177 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ sig = "SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
178 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ text = f"{header}.{payload}.{sig}"
179 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ matches = detector.scan_content(text)
180 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ jwt = [m for m in matches if m.pattern_name == "jwt_token"]
181 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert all(m.severity == "medium" for m in jwt)
182 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
183 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
184 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # ---------------------------------------------------------------------------
185 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # Redaction tests
186 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # ---------------------------------------------------------------------------
187 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
188 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
189 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ class TestRedaction:
190 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_redact_aws_key(self, detector):
191 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ text = "key = AKIAIOSFODNN7EXAMPLE"
192 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = detector.redact(text)
193 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert "AKIAIOSFODNN7EXAMPLE" not in result
194 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert REDACTED in result
195 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
196 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_redact_password(self, detector):
197 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ text = 'password = "hunter2hunter2"'
198 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = detector.redact(text)
199 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert "hunter2hunter2" not in result
200 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert REDACTED in result
201 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
202 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_redact_pem_header(self, detector):
203 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ text = "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEA\n-----END RSA PRIVATE KEY-----"
204 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = detector.redact(text)
205 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert "-----BEGIN RSA PRIVATE KEY-----" not in result
206 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert REDACTED in result
207 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
208 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_redact_connection_string(self, detector):
209 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ text = "postgresql://admin:[email protected] /mydb"
210 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = detector.redact(text)
211 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert "s3cret" not in result
212 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert REDACTED in result
213 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
214 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_redact_jwt(self, detector):
215 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ header = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"
216 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ payload = "eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ"
217 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ sig = "SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
218 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ jwt = f"{header}.{payload}.{sig}"
219 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = detector.redact(jwt)
220 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert jwt not in result
221 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert REDACTED in result
222 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
223 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_redact_returns_unchanged_clean_text(self, detector):
224 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ text = "def hello():\n return 'world'\n"
225 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = detector.redact(text)
226 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert result == text
227 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
228 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_redact_multiple_secrets_in_one_string(self, detector):
229 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ text = (
230 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ "AKIAIOSFODNN7EXAMPLE\n"
231 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ 'password = "mysecretvalue"\n'
232 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ )
233 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = detector.redact(text)
234 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert "AKIAIOSFODNN7EXAMPLE" not in result
235 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert "mysecretvalue" not in result
236 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
237 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
238 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # ---------------------------------------------------------------------------
239 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # scan_file tests
240 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # ---------------------------------------------------------------------------
241 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
242 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
243 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ class TestScanFile:
244 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_scan_file_detects_secrets(self, detector, tmp_path):
245 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ secret_file = tmp_path / "config.py"
246 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ secret_file.write_text('AWS_KEY = "AKIAIOSFODNN7EXAMPLE"\n', encoding="utf-8")
247 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ matches = detector.scan_file(secret_file)
248 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert len(matches) >= 1
249 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert any(m.pattern_name == "aws_access_key" for m in matches)
250 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
251 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_scan_file_clean_file(self, detector, tmp_path):
252 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ clean_file = tmp_path / "utils.py"
253 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ clean_file.write_text("def add(a, b):\n return a + b\n", encoding="utf-8")
254 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ matches = detector.scan_file(clean_file)
255 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert matches == []
256 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
257 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_scan_file_missing_file_returns_empty(self, detector, tmp_path):
258 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ missing = tmp_path / "does_not_exist.py"
259 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ matches = detector.scan_file(missing)
260 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert matches == []
261 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
262 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
263 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # ---------------------------------------------------------------------------
264 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # No false positives on clean code
265 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # ---------------------------------------------------------------------------
266 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
267 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
268 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ class TestNoFalsePositives:
269 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ CLEAN_SNIPPETS = [
270 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # Normal variable names
271 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ "password_length = 12\npassword_complexity = True\n",
272 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # Password prompt (no literal value)
273 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ "password = input('Enter password: ')\n",
274 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # Short strings (below minimum length threshold)
275 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ "secret = 'abc'\n",
276 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # Postgres URL without credentials
277 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ "DB_URL = 'postgresql://localhost/mydb'\n",
278 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # A function named after a key concept
279 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ "def get_api_key_name():\n return 'key_name'\n",
280 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # Normal assignment that looks vaguely like an env var
281 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ "API_BASE_URL = 'https://api.example.com'\n",
282 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # JWT-shaped but too short / clearly not a real token
283 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ "token = 'eyJ.x.y'\n",
284 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ ]
285 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
286 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ @pytest.mark.parametrize("snippet", CLEAN_SNIPPETS)
287 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_no_false_positive(self, detector, snippet):
288 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ matches = detector.scan_content(snippet)
289 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert matches == [], f"Unexpected match in: {snippet!r} → {matches}"
290 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
291 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
292 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # ---------------------------------------------------------------------------
293 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # SensitiveMatch dataclass
294 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # ---------------------------------------------------------------------------
295 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
296 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
297 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ class TestSensitiveMatch:
298 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_fields(self):
299 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ m = SensitiveMatch(
300 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ pattern_name="aws_access_key",
301 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ line_number=3,
302 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ match_text=REDACTED,
303 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ severity="high",
304 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ )
305 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert m.pattern_name == "aws_access_key"
306 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert m.line_number == 3
307 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert m.match_text == REDACTED
308 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert m.severity == "high"
309 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
310 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
311 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # ---------------------------------------------------------------------------
312 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # CLI --redact flag
313 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # ---------------------------------------------------------------------------
314 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
315 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
316 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ class TestCLIRedactFlag:
317 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_redact_flag_accepted(self):
318 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ """--redact flag should be accepted by the ingest command without error."""
319 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ from navegador.cli.commands import main
320 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
321 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ runner = CliRunner()
322 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with runner.isolated_filesystem():
323 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ Path("src").mkdir()
324 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with patch("navegador.cli.commands._get_store", return_value=MagicMock()), \
325 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ patch("navegador.ingestion.RepoIngester") as MockRI:
326 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ MockRI.return_value.ingest.return_value = {"files": 1, "functions": 2,
327 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ "classes": 0, "edges": 3, "skipped": 0}
328 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = runner.invoke(main, ["ingest", "src", "--redact"])
329 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert result.exit_code == 0
330 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
331 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_redact_flag_passes_to_ingester(self):
332 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ """RepoIngester must be constructed with redact=True when --redact is given."""
333 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ from navegador.cli.commands import main
334 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
335 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ runner = CliRunner()
336 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with runner.isolated_filesystem():
337 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ Path("src").mkdir()
338 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with patch("navegador.cli.commands._get_store", return_value=MagicMock()), \
339 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ patch("navegador.ingestion.RepoIngester") as MockRI:
340 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ MockRI.return_value.ingest.return_value = {"files": 0, "functions": 0,
341 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ "classes": 0, "edges": 0, "skipped": 0}
342 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ runner.invoke(main, ["ingest", "src", "--redact"])
343 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ MockRI.assert_called_once()
344 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ _, kwargs = MockRI.call_args
345 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert kwargs.get("redact") is True
346 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
347 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_no_redact_flag_defaults_false(self):
348 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ """Without --redact, RepoIngester should be constructed with redact=False (default)."""
349 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ from navegador.cli.commands import main
350 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
351 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ runner = CliRunner()
352 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with runner.isolated_filesystem():
353 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ Path("src").mkdir()
354 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with patch("navegador.cli.commands._get_store", return_value=MagicMock()), \
355 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ patch("navegador.ingestion.RepoIngester") as MockRI:
356 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ MockRI.return_value.ingest.return_value = {"files": 0, "functions": 0,
357 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ "classes": 0, "edges": 0, "skipped": 0}
358 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ runner.invoke(main, ["ingest", "src"])
359 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ MockRI.assert_called_once()
360 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ _, kwargs = MockRI.call_args
361 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert kwargs.get("redact", False) is False