Persist a redacted chained traceback in the private run output and expose redacted last_error in tool and slash listings, including historical errors. Keep the run_job concise error return unchanged for delivery classification. Slim redo of liuhao1024's earliest #104545; adds forced redaction and keeps formatting in a topical sibling. Local SDK/socket A/B verifies diagnosis visibility plus healthy-script, clearing, and private-file controls. Canonical tests queued under the campaign lock at commit time. Co-authored-by: liuhao1024 <sunsky.lau@gmail.com>
41 lines
2.3 KiB
Python
41 lines
2.3 KiB
Python
"""Failure detail belongs in the local audit, not the delivery summary."""
|
|
from cron import jobs, scheduler
|
|
|
|
|
|
def test_run_error_persists_redacted_cause_but_returns_summary(tmp_path, monkeypatch):
|
|
def fail_setup(*args):
|
|
try:
|
|
raise ConnectionError("https://user:password@localhost/api?token=secret-token")
|
|
except ConnectionError as cause:
|
|
raise RuntimeError("Connection error.") from cause
|
|
|
|
monkeypatch.setattr(scheduler, "_resolve_cron_agent_setup", fail_setup)
|
|
with jobs.use_cron_store(tmp_path):
|
|
job = jobs.create_job(prompt="Check status", schedule="every 1h", model="local-probe", deliver="local")
|
|
success, output, response, error = scheduler.run_job(job)
|
|
saved = jobs.save_job_output(job["id"], output).read_text(encoding="utf-8")
|
|
assert not success and response == "" and error == "RuntimeError: Connection error."
|
|
assert "Traceback (most recent call last)" in saved and "fail_setup" in saved
|
|
assert "ConnectionError" in saved and "localhost" in saved
|
|
assert "password" not in saved and "secret-token" not in saved
|
|
|
|
|
|
def test_list_exposes_run_error_and_clears_it_after_success(tmp_path, capsys):
|
|
from hermes_cli.cli_commands_mixin import CLICommandsMixin
|
|
from tools.cronjob_job_args import _format_job
|
|
|
|
with jobs.use_cron_store(tmp_path):
|
|
job = jobs.create_job(prompt="Check status", schedule="every 1h", model="local-probe", deliver="local")
|
|
reason = "RuntimeError: https://user:password@localhost/api?token=secret-token"
|
|
jobs.mark_job_run(job["id"], False, error=reason)
|
|
displayed = _format_job(jobs.get_job(job["id"]))
|
|
assert displayed["last_error"].startswith("RuntimeError:") and "localhost" in displayed["last_error"]
|
|
assert "password" not in displayed["last_error"] and "secret-token" not in displayed["last_error"]
|
|
assert displayed["last_delivery_error"] is None and displayed["last_fire_error"] is None
|
|
CLICommandsMixin._cron_list(object(), "list", {"all": False})
|
|
console = capsys.readouterr().out
|
|
assert f"error: {displayed['last_error']}" in console
|
|
assert "password" not in console and "secret-token" not in console
|
|
jobs.mark_job_run(job["id"], True)
|
|
assert _format_job(jobs.get_job(job["id"]))["last_error"] is None
|