aline-ai 0.2.3__py3-none-any.whl → 0.2.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
realign/redactor.py CHANGED
@@ -142,17 +142,55 @@ def redact_content(content: str, secrets: List[SecretMatch]) -> str:
142
142
  for line_num, line_secrets in secrets_by_line.items():
143
143
  secret_types = [s.type for s in line_secrets]
144
144
  # Keep the JSON structure but redact the sensitive value
145
- # This is a simple approach - we mark the line as redacted
146
145
  original_line = lines[line_num]
147
- # Try to preserve JSON structure by finding quotes and redacting content
148
- if '"' in original_line:
149
- # Simple redaction: find the value part and replace it
150
- lines[line_num] = original_line.replace(
151
- original_line[original_line.find(':'):] if ':' in original_line else original_line,
152
- f': "[REDACTED: {", ".join(set(secret_types))}]"'
153
- )
154
- else:
155
- lines[line_num] = f"[REDACTED LINE - {', '.join(set(secret_types))}]"
146
+
147
+ # Try to parse as JSON and redact only values
148
+ import json
149
+ import re
150
+
151
+ try:
152
+ # Try to parse the line as JSON
153
+ json_obj = json.loads(original_line)
154
+
155
+ # Redact all string values that might contain secrets
156
+ def redact_json_values(obj):
157
+ """Recursively redact values in JSON object."""
158
+ if isinstance(obj, dict):
159
+ return {k: redact_json_values(v) for k, v in obj.items()}
160
+ elif isinstance(obj, list):
161
+ return [redact_json_values(item) for item in obj]
162
+ elif isinstance(obj, str):
163
+ # Check if this value might be sensitive (heuristic: not too short)
164
+ # This is a simple approach - we redact string values on lines with secrets
165
+ return f"[REDACTED: {', '.join(set(secret_types))}]"
166
+ else:
167
+ return obj
168
+
169
+ redacted_obj = redact_json_values(json_obj)
170
+ lines[line_num] = json.dumps(redacted_obj, ensure_ascii=False)
171
+
172
+ except (json.JSONDecodeError, Exception):
173
+ # If JSON parsing fails, fall back to simple replacement
174
+ # Try to preserve structure by using regex to find and replace values
175
+ if ':' in original_line:
176
+ # Find the value part after the colon, preserving the closing braces/brackets
177
+ # Match pattern: : "value" or : value, capture trailing punctuation
178
+ pattern = r':\s*"[^"]*"(\s*[,}\]])'
179
+ if re.search(pattern, original_line):
180
+ lines[line_num] = re.sub(
181
+ pattern,
182
+ rf': "[REDACTED: {", ".join(set(secret_types))}]"\1',
183
+ original_line
184
+ )
185
+ else:
186
+ # Fallback: replace from colon onwards but keep trailing punctuation
187
+ match = re.search(r'(.*?:\s*)(.+?)(\s*[}\]]*\s*)$', original_line)
188
+ if match:
189
+ lines[line_num] = f'{match.group(1)}"[REDACTED: {", ".join(set(secret_types))}]"{match.group(3)}'
190
+ else:
191
+ lines[line_num] = f'{original_line}: "[REDACTED: {", ".join(set(secret_types))}]"'
192
+ else:
193
+ lines[line_num] = f"[REDACTED LINE - {', '.join(set(secret_types))}]"
156
194
 
157
195
  redacted_content = '\n'.join(lines)
158
196
  redacted_size = len(redacted_content)