fix(skillopt-sleep): redact secrets before persisting cycle diagnostics
PR #92 added a per-cycle diagnostics.json that surfaces backend stderr, optimizer replies, and task responses so a 0.0 night is self-diagnosing. Those free-text fields can carry credentials (e.g. a codex 401 stderr dump containing an auth token), so persisting them verbatim was a new on-disk leak surface. - Add a shared redact_secrets() in staging.py and route diagnostics.json's call_error / reflect_raw_head / holdout_detail through it before writing. - Redact the codex and Claude auth-error log lines too (a secondary sink when a file log handler is attached); last_call_error stays raw in memory so _AUTH_MARKERS matching is unaffected. - Centralize _SECRET_PATTERNS in staging.py (harvest_codex now reuses them) and extend coverage to AWS / GitHub / Slack / Google / JWT token shapes. - Tests: secret-shape coverage, private-key blocks, recursive/scalar passthrough, no over-redaction of plain prose, fail-fast auth-error log redaction, and an end-to-end check that diagnostics.json has no secret. Observability-only; the gate and learning algorithm are unchanged. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -582,9 +582,10 @@ class ClaudeCliBackend(CliBackend):
|
||||
combined = check_stdout + "\n" + stderr
|
||||
for marker in self._CLI_ERROR_MARKERS:
|
||||
if marker in combined:
|
||||
from skillopt_sleep.staging import redact_secrets
|
||||
logging.getLogger("skillopt_sleep").warning(
|
||||
"Claude CLI returned a likely auth error: %s",
|
||||
combined[:200].replace("\n", " "),
|
||||
redact_secrets(combined[:200].replace("\n", " ")),
|
||||
)
|
||||
self.last_call_error = combined[:500]
|
||||
return
|
||||
@@ -843,8 +844,10 @@ class CodexCliBackend(CliBackend):
|
||||
return out
|
||||
err = self.last_call_error or ""
|
||||
if any(m in err for m in self._AUTH_MARKERS):
|
||||
from skillopt_sleep.staging import redact_secrets
|
||||
logging.getLogger("skillopt_sleep").error(
|
||||
"codex auth error — re-login required (`codex login`): %s", err[:200]
|
||||
"codex auth error — re-login required (`codex login`): %s",
|
||||
redact_secrets(err[:200]),
|
||||
)
|
||||
break # fail fast: retrying a 401 just burns calls
|
||||
if attempt < retries - 1:
|
||||
|
||||
Reference in New Issue
Block a user