1010# Patterns to exclude when copying between containers
1111COPY_EXCLUDE_PATTERNS = [".git" , "__pycache__" ]
1212
13+ # Secret env vars whose values must never be recorded in command output / trajectories.
14+ _SECRET_ENV_VARS = ("GITHUB_TOKEN" , "LLAMA_API_KEY" )
15+
16+
17+ def redact_secrets (text : str | None ) -> str | None :
18+ """Replace known secret values with a placeholder so they never land in recorded output."""
19+ if not text :
20+ return text
21+ for var in _SECRET_ENV_VARS :
22+ val = os .getenv (var )
23+ if val and val in text :
24+ text = text .replace (val , f"<REDACTED_{ var } >" )
25+ return text
26+
1327
1428def _scratch_dir () -> str | None :
1529 """Local scratch dir for staging `docker cp` transfers. Defaults to the system temp dir.
@@ -30,12 +44,15 @@ class ClashDockerEnvironment(DockerEnvironment):
3044 def execute (self , action : str | dict , cwd : str = "" , * , timeout : int | None = None ) -> dict :
3145 if isinstance (action , str ):
3246 action = {"command" : action }
33- return super ().execute (action , cwd , timeout = timeout )
47+ result = super ().execute (action , cwd , timeout = timeout )
48+ if isinstance (result , dict ) and result .get ("output" ):
49+ result ["output" ] = redact_secrets (result ["output" ])
50+ return result
3451
3552
3653def assert_zero_exit_code (result : dict , * , logger : logging .Logger | None = None ) -> dict :
3754 if result .get ("returncode" , 0 ) != 0 :
38- msg = f"Command failed with exit code { result .get ('returncode' )} :\n { result .get ('output' )} "
55+ msg = f"Command failed with exit code { result .get ('returncode' )} :\n { redact_secrets ( result .get ('output' ) )} "
3956 if logger is not None :
4057 logger .error (msg )
4158 raise RuntimeError (msg )
0 commit comments