fix(core): reject malformed cron numeric fields#5352
Conversation
|
@qwen-code /triage |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Hi @tt-a1i, thanks for the contribution!
The PR body doesn't follow our pull request template. The current headings ("Summary", "Test Plan", "AI Assistance Disclosure") don't match the required sections. Please update the PR description to include:
- What this PR does — describe the change in prose
- Why it's needed — motivation / the problem being solved
- Reviewer Test Plan — how a reviewer can confirm this works (steps, expected behavior, evidence)
- Risk & Scope — main risk, what's out of scope, breaking changes
- Linked Issues — use
Fixes #5348to auto-close the issue - 中文说明 — Chinese translation of the above
The template also has a "Tested on" OS table — please fill that in too.
The code changes themselves look focused and relevant to #5348 — this is purely a description-format issue. Once updated, the review can continue. 🙏
中文说明
你好 @tt-a1i,感谢贡献!
PR 描述没有按照我们的 pull request 模板 来写。当前的标题("Summary"、"Test Plan"、"AI Assistance Disclosure")和要求的章节不匹配。请更新 PR 描述,包含以下内容:
- What this PR does — 用文字描述改动
- Why it's needed — 动机 / 要解决的问题
- Reviewer Test Plan — 审查者如何确认改动有效(步骤、预期行为、证据)
- Risk & Scope — 主要风险、不在范围内的内容、破坏性变更
- Linked Issues — 使用
Fixes #5348自动关闭 issue - 中文说明 — 以上英文的中文翻译
模板中还有一个 "Tested on" 操作系统表格,也请填写。
代码改动本身看起来聚焦且与 #5348 相关——这纯粹是描述格式的问题。更新后审查可以继续。🙏
— Qwen Code · qwen3.7-max
|
@qwen-code /triage |
|
Thanks for the PR! Template looks good ✓ On direction: clearly aligned. Cron is a first-class feature (CHANGELOG: "durable cron jobs" #5004, "enable loop/cron tools by default" #4950), and silent normalization of malformed input is a real correctness bug — users can end up with jobs running at unintended cadences. The linked issue #5348 lays it out well. On approach: scope is tight and appropriate. Four files, +59/-12, all directly related to the fix. The whole-token regex validation before Moving on to code review. 🔍 中文说明感谢贡献! 模板完整 ✓ 方向:明确对齐。Cron 是一等公民功能(CHANGELOG:"durable cron jobs" #5004、"enable loop/cron tools by default" #4950),静默归一化非法输入是真正的正确性 bug——用户可能会以非预期的频率运行定时任务。关联 issue #5348 描述得很清楚。 方案:范围紧凑恰当。4 个文件,+59/-12,全部与修复直接相关。在 进入代码审查 🔍 — Qwen Code · qwen3.7-max |
Code ReviewThe fix is clean and correct. Both One minor observation: No correctness bugs, no security issues, no regressions. Scope is tight. TestingBefore (main, without PR)Bug confirmed — malformed inputs silently normalized: After (PR #5352 applied)All malformed inputs rejected, valid inputs still work: Unit Tests (27/27 pass)Results match the PR's claims exactly. ✅ 中文说明代码审查修复干净正确。 一个小观察: 无正确性 bug,无安全问题,无回归。范围紧凑。 测试修复前(main 分支,无 PR)Bug 确认——非法输入被静默归一化。 修复后(应用 PR #5352)所有非法输入被拒绝,合法输入正常工作。 单元测试(27/27 通过)结果与 PR 声明完全一致。✅ — Qwen Code · qwen3.7-max |
|
This is a textbook bugfix PR: well-scoped, correctly implemented, with regression tests that actually cover the failure modes. My independent proposal would have been the same — add a The before/after testing is unambiguous: on main, The minor duplication of Approving. ✅ 中文说明这是一个教科书式的 bugfix PR:范围恰当、实现正确、回归测试覆盖了实际的失败模式。 我的独立方案也会一样——在 cron 字段解析器的每个 修复前后对比明确:main 上 两个文件中 批准 ✅ — Qwen Code · qwen3.7-max |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
LGTM, looks ready to ship. ✅
✅ Local runtime verification (real tmux, real CronCreateTool) — PR #5352Verdict: fixes #5348 as intended, no regressions, type-checks & lints clean — safe to merge. I drove the real cron functions and the real What the PR does
Evidence — PR headStatic checks Real runtime —
End-to-end through the real A/B vs
|
What this PR does
Tightens cron field parsing so numeric tokens are only accepted when the entire token is a valid integer, instead of relying on bare
parseInt()(which silently ignores trailing characters).Invalid value, a malformed or over-segmented range (e.g.1-5x,1-2-3) throwsInvalid range, and a malformed step (e.g.*/15garbage,5/2x) throwsInvalid step.humanReadableCron()applies the same whole-token check to step expressions, so a malformed pattern like*/15x * * * *falls back to the raw expression string instead of being summarized asEvery 15 minutes.Why it's needed
parseCron()previously normalized malformed fields by parsing only the leading digits, so5x * * * *behaved like5 * * * *,1-5xlike1-5,1-2-3like1-2, and*/15garbagelike*/15.humanReadableCron()had the matching problem, displaying*/15x * * * *asEvery 15 minutes.This matters because
cron_createvalidates schedules throughparseCron()(andnextFireTime()) before creating a job. If a malformed expression is silently normalized rather than rejected, a user or the model can create a scheduled task that runs at an unintended cadence instead of failing fast. The fix makes the parser fail fast on malformed numeric fields. (See issue #5348.)Reviewer Test Plan
How to verify
Repro of the original bug: before this change,
parseCron('5x * * * *')succeeded and behaved like5 * * * *, andhumanReadableCron('*/15x * * * *')returnedEvery 15 minutes. After this change, the parser throws (Invalid value/Invalid range/Invalid step) for malformed tokens, andhumanReadableCronfalls back to the raw string. The added unit tests assert exactly these expected-vs-observed outcomes.Verification commands already run on this branch:
npx vitest run packages/core/src/utils/cronParser.test.ts packages/core/src/utils/cronDisplay.test.tsnpx prettier --check packages/core/src/utils/cronParser.ts packages/core/src/utils/cronParser.test.ts packages/core/src/utils/cronDisplay.ts packages/core/src/utils/cronDisplay.test.tsnpx eslint packages/core/src/utils/cronParser.ts packages/core/src/utils/cronParser.test.ts packages/core/src/utils/cronDisplay.ts packages/core/src/utils/cronDisplay.test.tsnpm run typecheck --workspace=packages/coregit diff --checkEvidence (Before & After)
N/A — non-visible logic fix; covered by the unit tests above.
Tested on
✅ tested ·⚠️ not tested · N/A
Environment (optional)
Unit tests only (npm workspaces).
Risk & Scope
Linked Issues
Fixes #5348
中文说明
此 PR 的作用
收紧 cron 字段解析逻辑:只有当整个数字 token 都是合法整数时才接受,而不再依赖原始的
parseInt()(它会静默忽略尾部多余字符)。Invalid value;非法或多段范围(如1-5x、1-2-3)抛出Invalid range;非法步长(如*/15garbage、5/2x)抛出Invalid step。humanReadableCron()对步长表达式应用相同的整 token 校验,因此像*/15x * * * *这样的非法表达式会回退为原始表达式字符串,而不再被概括为Every 15 minutes。为什么需要
此前
parseCron()只解析前导数字,从而把非法字段静默归一化:5x * * * *表现得像5 * * * *,1-5x像1-5,1-2-3像1-2,*/15garbage像*/15。humanReadableCron()也有同样的问题,会把*/15x * * * *显示成Every 15 minutes。这很重要,因为
cron_create在创建任务前会通过parseCron()(以及nextFireTime())来校验调度表达式。如果非法表达式被静默归一化而不是被拒绝,用户或模型就可能创建出以非预期频率运行的定时任务,而不是快速失败。本次修复让解析器在遇到非法数字字段时快速失败。(见 issue #5348。)审阅者测试计划
如何验证
原始 bug 复现:在本次改动前,
parseCron('5x * * * *')会成功并表现得像5 * * * *,humanReadableCron('*/15x * * * *')会返回Every 15 minutes。改动后,对于非法 token,解析器会抛错(Invalid value/Invalid range/Invalid step),而humanReadableCron会回退为原始字符串。新增的单元测试正是断言这些"期望 vs 实际"的结果。本分支上已运行的验证命令:
npx vitest run packages/core/src/utils/cronParser.test.ts packages/core/src/utils/cronDisplay.test.tsnpx prettier --check packages/core/src/utils/cronParser.ts packages/core/src/utils/cronParser.test.ts packages/core/src/utils/cronDisplay.ts packages/core/src/utils/cronDisplay.test.tsnpx eslint packages/core/src/utils/cronParser.ts packages/core/src/utils/cronParser.test.ts packages/core/src/utils/cronDisplay.ts packages/core/src/utils/cronDisplay.test.tsnpm run typecheck --workspace=packages/coregit diff --check证据(前后对比)
N/A —— 非可见的逻辑修复;已由上述单元测试覆盖。
测试平台
✅ 已测试 ·⚠️ 未测试 · N/A
环境(可选)
仅单元测试(npm workspaces)。
风险与范围
关联 Issue
Fixes #5348
AI Assistance Disclosure
I used Codex to review the changes, sanity-check the implementation against existing patterns, and help spot potential edge cases.