fix(cron): repair a scalar 'jobs' field instead of returning it from load_jobs

{"jobs": null} (or a string, number or bool) escaped load_jobs unchanged, so every reader crashed the same way the non-object list entries did. Replace it with an empty list and persist the repair. Ported from #123405.

(cherry picked from commit 1f380ec62c2ce65fd1d31656850b611234e3385e)
This commit is contained in:
JoaoMarcos44
2026-09-26 12:39:36 +09:00
committed by kshitij
parent e66e351cf5
commit 883f5422a1
2 changed files with 21 additions and 0 deletions

View File

@@ -1368,6 +1368,12 @@ def load_jobs() -> List[Dict[str, Any]]:
", ".join(map(repr, skipped)))
jobs = [{**v, "id": v.get("id") or k} for k, v in jobs.items() if isinstance(v, dict)]
repair = "id-keyed jobs map flattened to list"
elif not isinstance(jobs, list):
logger.warning(
"Replacing invalid jobs.json 'jobs' field (%s) with an empty list",
type(jobs).__name__)
jobs = []
repair = "invalid jobs field replaced with list"
elif isinstance(data, list):
jobs = data
repair = "bare list wrapped as dict"

View File

@@ -1749,6 +1749,21 @@ class TestJobsJsonIdKeyedMap:
assert json.loads(JOBS_FILE.read_text(encoding="utf-8"))["jobs"] == []
assert "sk-leaked-value" not in caplog.text
@pytest.mark.parametrize("bad_jobs", [None, "not-a-list", 42, True])
def test_invalid_jobs_field_is_repaired_to_empty_list(self, tmp_cron_dir, bad_jobs, caplog):
"""A dict root with a scalar jobs value must not escape the load boundary."""
import json
from cron.jobs import JOBS_FILE, ensure_dirs, load_jobs
ensure_dirs()
JOBS_FILE.write_text(json.dumps({"jobs": bad_jobs}), encoding="utf-8")
with caplog.at_level("WARNING", logger="cron.jobs"):
assert load_jobs() == []
assert list_jobs(include_disabled=True) == []
assert json.loads(JOBS_FILE.read_text(encoding="utf-8"))["jobs"] == []
assert type(bad_jobs).__name__ in caplog.text