from __future__ import annotations import unittest import shutil from pathlib import Path from uuid import uuid4 from mais_humana.acceptance import acceptance_markdown, build_acceptance_report from mais_humana.models import ReportBundle from mais_humana.redaction import redaction_markdown, scan_generated_artifacts, scan_text_for_secrets from tests.helpers import make_tmp class RedactionAcceptanceTests(unittest.TestCase): def make_scan_root(self) -> Path: root = Path.cwd() / "tmp-redaction-fixtures" / uuid4().hex root.mkdir(parents=True, exist_ok=False) return root def test_redaction_allows_references_but_flags_secret_values(self) -> None: text = """ credentialRef: safe-reference-only token = "abcdefghijklmnopqrstuvwxyz1234567890" Bearer abcdefghijklmnopqrstuvwxyz1234567890 """ findings = scan_text_for_secrets("sample.md", text) self.assertGreaterEqual(len(findings), 2) self.assertTrue(all(finding.path == "sample.md" for finding in findings)) def test_redaction_scans_generated_text_files(self) -> None: root = self.make_scan_root() try: (root / "dados").mkdir() (root / "dados" / "ok.json").write_text('{"credentialRef":"abc"}', encoding="utf-8") (root / "dados" / "bad.md").write_text('password="abcdefghijklmnopqrstuvwxyz123456"', encoding="utf-8") report = scan_generated_artifacts(root) finally: shutil.rmtree(root, ignore_errors=True) self.assertFalse(report.passed) markdown = redaction_markdown(report) self.assertIn("achados", markdown) def test_redaction_ignores_hashes_and_test_tmp_outputs(self) -> None: root = self.make_scan_root() try: (root / "dados").mkdir() (root / ".test-tmp" / "case" / "dados").mkdir(parents=True) hash_only = "a" * 64 (root / "dados" / "hash.json").write_text(f'{{"snapshotHash":"{hash_only}"}}', encoding="utf-8") (root / ".test-tmp" / "case" / "dados" / "bad.md").write_text( 'password="abcdefghijklmnopqrstuvwxyz123456"', encoding="utf-8", ) report = scan_generated_artifacts(root) finally: shutil.rmtree(root, ignore_errors=True) self.assertTrue(report.passed) def test_redaction_flags_contextual_cloudflare_token_values(self) -> None: findings = scan_text_for_secrets("env.txt", "cloudflare_token=abcdefghijklmnopqrstuvwxyz1234567890") self.assertEqual(len(findings), 1) self.assertEqual(findings[0].pattern_id, "cloudflare_token_assignment") def test_redaction_flags_cfat_even_when_named_as_reference(self) -> None: findings = scan_text_for_secrets("route.md", "tokenRef=cfat_abcdefghijklmnopqrstuvwxyz1234567890") self.assertEqual(len(findings), 1) self.assertEqual(findings[0].pattern_id, "cloudflare_cfat_token") def test_redaction_allows_single_opaque_reference_line(self) -> None: findings = scan_text_for_secrets("route.md", "credentialRef: cf-token-prod-readonly") self.assertEqual(findings, ()) def test_acceptance_report_handles_missing_artifacts(self) -> None: root = make_tmp() bundle = ReportBundle( output_root=str(root), generated_files=(), platform_count=0, profile_count=0, matrix_cells=0, total_code_lines_analyzed=0, warnings=(), ) report = build_acceptance_report(root, (), (), bundle) self.assertFalse(report.passed) markdown = acceptance_markdown(report) self.assertIn("pendente", markdown) self.assertIn("Leitura tecnica minima", markdown) if __name__ == "__main__": unittest.main()