Skip to content

fix(cron): null-safe deliver in cron list + re-resolve BSM secrets per run - #56144

Merged
teknium1 merged 2 commits into
mainfrom
fix/cron-null-deliver-bsm-reresolve
Jul 1, 2026
Merged

teknium1 merged 2 commits into
mainfrom
fix/cron-null-deliver-bsm-reresolve

Conversation

@teknium1

@teknium1 teknium1 commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator

Summary

Two live cron bugs — a cron list crash and cron jobs 401'ing on Bitwarden-backed secrets — are fixed. Both were surfaced by @banditburai in #35616, whose larger watchdog/supervisor rework is already superseded by the CronScheduler provider refactor on main (the old in-process _start_cron_ticker this PR reworked is now a deprecated shim; except BaseException + logger.error(exc_info=True), the heartbeat, and the honest cron status banner all landed since). These two adjacent one-liners were the only parts of that PR still live on main; #33527 targets the same pair.

Changes

  • hermes_cli/cron.pycron list used job.get("deliver", ["local"]); an explicit "deliver": null returns None, which then hit ", ".join(None) and crashed the whole listing. Coalesce with or ["local"] — the same present-but-null guard the sibling repeat line already uses (fix: hermes cron list crashes when job has null deliver field #32896).
  • cron/scheduler.py — the per-run env reload used a bare load_dotenv(override=True), which re-applied only the .env placeholder: startup had already recorded this HERMES_HOME in env_loader._APPLIED_HOMES, so the external-secret re-pull no-oped and Bitwarden/BSM secrets stayed stuck on the placeholder (cron jobs 401'd). Route the reload through load_hermes_dotenv() and call reset_secret_source_cache() first to force the re-pull. Bitwarden's 300s value-cache keeps the forced re-pull off the network; the override honours secrets.bitwarden.override_existing, mirroring startup ([Bug]: cron scheduler missing BSM resolution #33465).
  • Tests — null-deliver regression guard in tests/hermes_cli/test_cron.py; reset-before-reload ordering guard in tests/cron/test_scheduler.py. Migrated 31 scheduler-reload test seams from patching dotenv.load_dotenv to the new load_hermes_dotenv / reset_secret_source_cache seam (the old seam no longer intercepts the reload, so leaving it would let the real BSM apply pollute env state across tests within a process).

Validation

Before After
cron list with "deliver": null TypeError: can only join an iterable renders Deliver: local
BSM secret in long-running gateway .env placeholder re-applied, secret never re-resolved → 401 reset_secret_source_cache() forces re-pull each run
tests/cron/ 577 passed
ruff clean

Fixes verified E2E with real imports against a temp HERMES_HOME.

Closes

Credit

@banditburai diagnosed both bugs in #35616. The watchdog/supervisor bulk of that PR is superseded by the provider refactor; this ships the two still-live fixes with tests. #33527 (@zccyman) targets the same pair — its BSM swap omits reset_secret_source_cache, so secrets still wouldn't re-resolve in a long-running process; that's included here.

Infographic

cron fix infographic

teknium1 added 2 commits July 1, 2026 00:48
…r run

Two live cron bugs, both surfaced by @banditburai in #35616 (whose larger
watchdog/supervisor work is already superseded by the CronScheduler provider
refactor on main):

- #32896: `cron list` crashed on a present-but-null `deliver` field —
  `job.get("deliver", ["local"])` returns None for an explicit null, which
  then hit `", ".join(None)`. Coalesce with `or ["local"]` (same pitfall
  the sibling `repeat` line already guards against).

- #33465: cron jobs 401'd on Bitwarden/BSM-backed secrets. The per-run env
  reload used a bare `load_dotenv(override=True)`, which re-applied only the
  .env placeholder — startup had already recorded this HERMES_HOME in
  env_loader._APPLIED_HOMES, so the external-secret re-pull no-oped. Route the
  reload through load_hermes_dotenv() and call reset_secret_source_cache()
  first to force the re-pull (Bitwarden's 300s value-cache keeps it off the
  network; override honours secrets.bitwarden.override_existing, mirroring
  startup).

Tests: null-deliver regression guard in test_cron.py; reset-before-reload
ordering guard in test_scheduler.py. Migrated 31 scheduler-reload test seams
from patching dotenv.load_dotenv to the new load_hermes_dotenv /
reset_secret_source_cache seam.
Migrating the scheduler-reload seam from a single dotenv.load_dotenv patch to
two patches (load_hermes_dotenv + reset_secret_source_cache) lengthened the
positional list _make_run_job_patches returns, so the 4 callers that applied
patches[0..4] silently dropped the resolve_runtime_provider patch (now at [5]).
Under CI's hermetic env (all API keys blanked) auth then failed and AIAgent was
never constructed → 'NoneType has no attribute kwargs'. Callers now apply
patches[0..5]. Passed locally (keys present) but failed on CI shard 5/8.
@teknium1
teknium1 force-pushed the fix/cron-null-deliver-bsm-reresolve branch from b99e633 to bbfbf70 Compare July 1, 2026 07:48
@alt-glitch alt-glitch added type/bug Something isn't working comp/cron Cron scheduler and job management P2 Medium — degraded but workaround exists labels Jul 1, 2026
@alt-glitch

Copy link
Copy Markdown
Contributor

This was generated by AI during triage.

Related (same cron-fix cluster, focused live-only subset): #33527 (omnibus cron hardening), #34041 (BSM-only reload), #36863 (broader env refresh incl. MCP). This PR carries only the two parts of #35616 still live on main (null-safe cron list + per-run BSM re-resolution) — a reviewer should reconcile against the competing PRs, not treat any as a duplicate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/cron Cron scheduler and job management P2 Medium — degraded but workaround exists type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants