11from __future__ import annotations
22
3+ import re
34import subprocess
45import sys
56from pathlib import Path
67
78
89ROOT = Path (__file__ ).resolve ().parents [1 ]
910FIXTURES = ROOT / "tests" / "fixtures" / "codex_sessions"
11+ FIXTURES_REDACT = ROOT / "tests" / "fixtures" / "codex_sessions_redact"
1012
1113
1214def _run_cli (args : list [str ], cwd : Path | None = None ) -> subprocess .CompletedProcess [str ]:
13- env = {"PYTHONPATH" : str (ROOT / "src" )}
15+ env = {"PYTHONPATH" : str (ROOT / "src" ), "NO_COLOR" : "1" }
1416 return subprocess .run (
1517 [sys .executable , "-m" , "conversation_exporter" , * args ],
1618 cwd = str (cwd or ROOT ),
@@ -21,6 +23,13 @@ def _run_cli(args: list[str], cwd: Path | None = None) -> subprocess.CompletedPr
2123 )
2224
2325
26+ def _assert_backup_counts (stdout : str , exported : int | None = None , skipped : int | None = None ) -> None :
27+ if exported is not None :
28+ assert re .search (rf"Exported\s+{ exported } \b" , stdout ), f"Expected Exported { exported } in { stdout !r} "
29+ if skipped is not None :
30+ assert re .search (rf"Skipped\s+{ skipped } \b" , stdout ), f"Expected Skipped { skipped } in { stdout !r} "
31+
32+
2433def _init_git_repo (path : Path ) -> None :
2534 path .mkdir (parents = True , exist_ok = True )
2635 subprocess .run (["git" , "init" , str (path )], check = True , capture_output = True , text = True )
@@ -39,7 +48,7 @@ def test_backup_writes_expected_structure_and_is_idempotent(tmp_path: Path) -> N
3948 "--system-name" , "macbook-pro" ,
4049 ])
4150 assert run_one .returncode == 0 , run_one .stderr
42- assert " exported=2" in run_one . stdout
51+ _assert_backup_counts ( run_one . stdout , exported = 2 )
4352
4453 target = output_repo / "history" / "alice" / "codex" / "macbook-pro" / "Code"
4554 markdown_files = sorted (target .rglob ("*.md" ))
@@ -56,7 +65,7 @@ def test_backup_writes_expected_structure_and_is_idempotent(tmp_path: Path) -> N
5665 "--system-name" , "macbook-pro" ,
5766 ])
5867 assert run_two .returncode == 0 , run_two .stderr
59- assert " skipped=2" in run_two . stdout
68+ _assert_backup_counts ( run_two . stdout , skipped = 2 )
6069 assert len (sorted (target .rglob ("*.md" ))) == 2
6170 assert len (sorted (target .rglob (".*.json" ))) == 2
6271
@@ -80,3 +89,24 @@ def test_sync_filters_to_current_git_repository(tmp_path: Path) -> None:
8089 history_root = project_repo / ".ai" / "history" / "alice" / "codex"
8190 markdown_files = sorted (history_root .rglob ("*.md" ))
8291 assert len (markdown_files ) == 1
92+
93+
94+ def test_secrets_redacted_in_output (tmp_path : Path ) -> None :
95+ output_repo = tmp_path / "backup-repo"
96+ _init_git_repo (output_repo )
97+ secret_literal = "sk-proj-redact-test-abc123xyz"
98+
99+ run = _run_cli ([
100+ "backup" ,
101+ "--output-path" , str (output_repo ),
102+ "--source-system" , "codex" ,
103+ "--input-path" , str (FIXTURES_REDACT ),
104+ "--user" , "alice" ,
105+ "--system-name" , "macbook-pro" ,
106+ ])
107+ assert run .returncode == 0 , run .stderr
108+ _assert_backup_counts (run .stdout , exported = 1 )
109+
110+ for md_path in (output_repo / "history" ).rglob ("*.md" ):
111+ content = md_path .read_text (encoding = "utf-8" )
112+ assert secret_literal not in content , f"Secret found in { md_path } "
0 commit comments