fix(debug): redact log content at upload time in hermes debug share#19318
Conversation
|
Fixes #19316 — applying at upload boundary in . |
Apply agent.redact.redact_sensitive_text with force=True to log content captured by _capture_log_snapshot before it reaches upload_to_pastebin. On-disk logs are untouched. Compatible with the off-by-default local redaction policy from NousResearch#16794: this is upload-time-only and applies regardless of security.redact_secrets because the public paste service is the leak surface. A visible banner is prepended to each uploaded log paste so reviewers know redaction was applied. --no-redact preserves deliberate unredacted sharing for maintainer-coordinated cases. The bug-report, setup-help, and feature-request issue templates direct users to run hermes debug share and paste the resulting public URLs. With redaction off by default per NousResearch#16794, those uploads have been carrying credentials onto paste.rs and dpaste.com. force=True is non-negotiable: without it, redact_sensitive_text short-circuits at agent/redact.py:322 when the env var is unset, so the fix would silently be a no-op for its target audience. A regression test pins this down. Fixes NousResearch#19316
9d50635 to
a983a5e
Compare
|
Nice catch @GodsBoy — this is a real leak path that's easy to miss. The issue is well-described and the fix is targeted at the right location. A few thoughts on the diff that might help it land faster:
The |
What does this PR do?
Closes a public-leak path:
hermes debug shareuploads logs to paste.rs / dpaste.com per the bug-report templates' explicit instructions, but never appliesredact_sensitive_textbefore upload. Withsecurity.redact_secretsoff by default after #16794, those uploads have been carrying credentials onto a public paste service.This PR applies
agent.redact.redact_sensitive_text(text, force=True)to log content at the_capture_log_snapshotboundary, before it reachesupload_to_pastebin. On-disk logs are not modified. A visible banner is prepended to each upload-bound log paste so reviewers know redaction was applied. A--no-redactflag preserves deliberate unredacted sharing for maintainer-coordinated cases.force=Trueis non-negotiable: without it,redact_sensitive_textshort-circuits atagent/redact.py:322whenHERMES_REDACT_SECRETSis unset, so the fix would silently be a no-op for its target audience. The regression testTestCaptureLogSnapshotRedaction::test_force_true_overrides_unset_env_varpins this down so a future refactor cannot accidentally drop it.This is upload-time-only, not local-disk redaction. It does not change
security.redact_secretsdefaults; it closes the public-leak path that is structurally upstream of the local-redaction question.Related Issue
Fixes #19316
Type of Change
Changes Made
hermes_cli/debug.py(+89, -7): added_redact_log_texthelper that callsredact_sensitive_text(text, force=True). Threaded aredact: bool = Trueparameter through_capture_log_snapshotand_capture_default_log_snapshotssotail_textandfull_textare sanitized before being returned.run_debug_sharenow readsargs.no_redact, passes the inverted flag through, and prepends a visible_REDACTION_BANNERto the report and each upload-bound log paste when redaction is enabled. Help-fallback text inrun_debugupdated. INFO log line records that redaction was applied.hermes_cli/main.py(+11): added--no-redactargument to thedebug sharesubparser and updated the epilog example.tests/hermes_cli/test_debug.py(+213): two new test classes covering the capture-time redaction path (TestCaptureLogSnapshotRedaction, 5 tests) and the CLI-level wiring (TestRunDebugShareRedaction, 3 tests). The regression testtest_force_true_overrides_unset_env_varpins theforce=Truerequirement.How to Test
security.redact_secretsis unset (orfalse) andHERMES_REDACT_SECRETSis not exported.~/.hermes/logs/agent.logcontaining a vendor-prefixed token (e.g., the literal stringsk-proj-A1B2C3D4E5F6G7H8I9J0aA).hermes debug share --local. Observe that the printed report and full-log block do NOT contain the literal token, and a redaction banner appears at the top of each log section.hermes debug share --no-redact --localagainst the same fixture. Observe that the original token is preserved and no banner appears.pytest tests/hermes_cli/test_debug.py -v. All 66 tests pass (8 new + 58 existing).Checklist
Code
fix(scope):,feat(scope):, etc.)pytest tests/hermes_cli/test_debug.py -qand all tests pass (66/66; full suite not run locally because the development venv was not provisioned in this environment, but the change is bounded to debug.py and main.py and the focused tests cover the new code paths)Documentation & Housekeeping
docs/, docstrings) : docstrings on_redact_log_text,_capture_log_snapshot,_capture_default_log_snapshots, and the file-level docstring inhermes_cli/debug.pywere updated. Help-fallback text inrun_debugand the argparse epilog example inhermes_cli/main.pyreference--no-redact.cli-config.yaml.exampleif I added/changed config keys : N/A (no config keys added)CONTRIBUTING.mdorAGENTS.mdif I changed architecture or workflows : N/A (no architecture or workflow change)logging) plus existing Hermes patterns (pathlib, the canonicalredact_sensitive_textand_capture_log_snapshotpaths). Notermios,fcntl, encoding-specific, or platform-conditional code added.Screenshots / Logs
Empirical confirmation that
force=Trueis required (run from the repo root):Without
force=True,redact_sensitive_textreturns input unchanged (agent/redact.py:322). The regression test in this PR pins this down.