Skip to content

fix(cron): reject invalid absolute timestamps#93903

Merged
vincentkoc merged 2 commits into
openclaw:mainfrom
Alix-007:fix/cron-parse-absolute-time-validation
Jun 17, 2026
Merged

fix(cron): reject invalid absolute timestamps#93903
vincentkoc merged 2 commits into
openclaw:mainfrom
Alix-007:fix/cron-parse-absolute-time-validation

Conversation

@Alix-007

Copy link
Copy Markdown
Contributor

Summary

parseAbsoluteTimeMs (src/cron/parse.ts) accepts invalid absolute timestamps. For non-numeric input it goes straight to Date.parse(normalizeUtcIso(raw)) and only checks the result is finite — but V8's Date.parse silently rolls invalid calendar dates over (2026-02-31T00:00:00Z2026-03-03) and accepts non-ISO free text (e.g. December 17, 2026 03:24:00).

Reachable path: normalizeCronJobCreate (src/cron/normalize.ts) normalizes the bad input into a valid-looking ISO string → validateScheduleTimestamp (src/cron/validate-timestamp.ts) trusts the parser result → it is used for scheduling in src/cron/service/jobs.ts. A user-supplied invalid absolute cron time is therefore silently accepted and scheduled at the wrong instant instead of being rejected.

Changes

  • parseAbsoluteTimeMs: added isValidIsoAbsolute, which re-reads the parsed UTC components to reject Date.parse's calendar rollover (so 2026-02-31 no longer becomes 2026-03-03), and rejects non-ISO free-text formats before Date.parse. Numeric / NaN inputs were already rejected; this closes the lenient-Date.parse gap. +67 across 2 files (one is the test).

Real behavior proof

Behavior addressed: invalid absolute timestamps (rolled-over calendar dates, non-ISO text) are now rejected (null) instead of silently coerced into a valid instant.

Evidence (real exported function): pre-fix, parseAbsoluteTimeMs("2026-02-31T00:00:00Z") returns 1772496000000 (Feb 31 accepted, rolled to Mar 3); post-fix it returns null.

Test: src/cron/parse.test.ts drives the real exported parseAbsoluteTimeMs — valid ISO / UTC-default / offset still parse, while invalid calendar dates / invalid times / non-ISO text are now rejected. Negative control: the invalid-date assertions fail pre-fix and pass post-fix.

Local run: node scripts/run-vitest.mjs src/cron/parse.test.ts → 1 file passed, 10 tests passed.

Scope / context

No linked issue — found via gap analysis on the cron timestamp path. Competing PRs checked (parseAbsoluteTimeMs, "cron time parse", "cron invalid date"): #91656 is test coverage, #72449/#69574 handle undefined/null, #70046 is HH:MM/timezone — none address this calendar-rollover / non-ISO acceptance gap.

@openclaw-barnacle openclaw-barnacle Bot added size: S triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. labels Jun 17, 2026
@vincentkoc
vincentkoc force-pushed the fix/cron-parse-absolute-time-validation branch from e77c043 to 1ac9fce Compare June 17, 2026 03:48
@vincentkoc

Copy link
Copy Markdown
Member

Maintainer verification completed.

  • The shared cron timestamp parser now rejects calendar rollovers and non-ISO free text before normalization, gateway validation, persistence, or scheduling.
  • Preserved the existing valid ISO end-of-day form: 2026-02-28T24:00:00Z remains accepted; nonzero hour-24 values remain rejected.
  • node scripts/run-vitest.mjs src/cron/parse.test.ts passed: 1 file, 10 tests.
  • Final structured Codex autoreview: clean, no accepted/actionable findings.
  • Full GitHub CI is green on rebased head 1ac9fce6a6 (run 27664455544).

Ready to land.

@vincentkoc
vincentkoc merged commit 4559a8d into openclaw:main Jun 17, 2026
163 of 164 checks passed
karmafeast added a commit to karmaterminal/openclaw that referenced this pull request Jun 17, 2026
…5651) (#1038)

* refactor(agents): hide update plan gating helper

* fix(e2e): keep live plugin pack paths local

* refactor(agents): drop mcp fetch type re-export

* refactor(agents): hide mcp oauth redirect classifier

* refactor(agents): remove catalog browse timer test hooks

* refactor(agents): hide execution contract resolver

* fix(e2e): reject unsafe Docker pack names

* clawdbot-d02.1.9.1.31: add sessions.create lifecycle seam (openclaw#93691)

* refactor(agents): hide assistant stream delivery types

* refactor(agents): hide message handler helpers

* fix: clean agent lint failures

* refactor(agents): hide compaction reconcile wrapper

* refactor(agents): hide context cache reset helper

* refactor(agents): hide copilot routing constants

* refactor(agents): hide subagent outcome helpers

* refactor(agents): hide tool mutation helpers

* refactor(agents): hide transport error extractor

* refactor(agents): remove video task status wrappers

* refactor(agents): hide custom api source id helper

* refactor(agents): hide docs path helpers

* fix(codex): sync app-server dynamic tool protocol

* refactor(agents): hide timeout seconds helper

* fix(gemini): bridge OAuth profiles into CLI runtime

* fix: persist Gemini CLI auth homes

* fix: preserve Gemini CLI project binding

* fix: scope CLI auth epochs to agent stores

* fix: fail closed on unstaged Gemini profiles

* fix: preserve runtime auth alias scope

* fix: keep CLI auth fallback scoped

* fix: accept Google API keys for Gemini CLI

* fix: honor Google auth order for Gemini CLI

* test: type Gemini CLI auth refresh mock

* fix: forward pinned Gemini CLI auth for validation

* fix: bind Gemini CLI epochs to profile homes

* fix: keep CLI prepare credentials private

* fix: ignore stale auto auth for Gemini CLI

* fix: stage resolved Gemini OAuth profiles

* fix: clear ambient Google ADC for Gemini CLI

* fix: stage adopted Gemini OAuth credentials

* fix: isolate Gemini CLI system auth settings

* fix: enforce Gemini CLI profile auth precedence

* fix: keep Gemini CLI system settings per run

* fix: clean Gemini bundle settings on prepare failure

* fix: preserve ambient Gemini system auth

* fix: honor inherited Gemini auth policy

* test: fix Gemini CLI auth test types

* test: narrow Gemini CLI setup agent dir

* fix: pass prepared CLI env to spawned process

* fix: expose CLI runtime env diagnostics

* fix: load staged Gemini CLI auth profiles

* fix: log Gemini CLI runtime env activation

* fix: select CLI auth profile for runtime prep

* fix: keep CLI env diagnostics opt-in

* fix: align Gemini CLI home path

* fix: add CLI empty response diagnostics

* fix: parse Gemini CLI stream output

* fix: allow Gemini CLI file edits

* docs: update Gemini CLI backend defaults

* fix: use OpenClaw temp root for Gemini CLI settings

* fix: clean up Gemini CLI backend checks

* fix: keep Gemini CLI auth out of warmup

* refactor(agents): hide cleanup timeout helpers

* refactor(agents): hide stale run cutoff

* refactor(agents): hide compaction timeout internals

* refactor(agents): remove stale compaction grace helper

* refactor(agents): hide idle timeout default

* refactor(plugins): hide cleanup timeout internals

* refactor(qqbot): hide response timeout default

* refactor(feishu): hide timeout config type

* refactor(browser): hide cdp reachability defaults

* docs: add Gemini CLI auth changelog entry

* refactor(agents): hide context window thresholds

* refactor(agents): hide fallback skip cache internals

* fix(agents): tolerate uncloneable adjusted tool params

* refactor(cli): hide compile cache and media internals

* fix(slack): preserve completed native progress titles

* refactor(acp): hide test helper internals

* refactor(tests): hide helper-only types

* refactor(tests): hide gateway state helper types

* fix(deps): remediate Dependabot alerts (openclaw#93857)

Merged via squash.

Prepared head SHA: 51ece24
Co-authored-by: vincentkoc <[email protected]>
Co-authored-by: vincentkoc <[email protected]>
Reviewed-by: @vincentkoc

* refactor(commands): hide doctor harness mocks

* refactor(commands): hide doctor e2e mock internals

* refactor(commands): hide doctor service install mock

* refactor(commands): hide gateway readiness types

* refactor(commands): hide health summary internals

* refactor(commands): trim health type reexports

* refactor(commands): trim migrate option reexports

* refactor(commands): trim backup type exports

* test(codex): refresh dynamic tool snapshots

* refactor(commands): hide onboarding install result

* fix(ui): harden chromium test runner

* refactor(commands): hide status task helper types

* refactor(commands): trim setup type reexports

* fix(slack): recognize MiniMax mm: namespaced reasoning tags in monitor preview (openclaw#93874)

* refactor(commands): hide doctor repair helper types

* feat(providers): add ClawRouter managed proxy

* docs(providers): document ClawRouter integration

* chore(providers): align ClawRouter package version

* fix(providers): preserve ClawRouter native replay policies

* chore(deps): register ClawRouter workspace

* fix(providers): consume canonical ClawRouter catalog field

* fix(providers): restore ClawRouter native runtime routes

* fix(providers): isolate ClawRouter runtime credentials

* fix(providers): cover ClawRouter runtime auth paths

* fix(providers): preserve ClawRouter catalog model ids

* fix(providers): require runnable ClawRouter Gemini routes

* fix(providers): route ClawRouter direct streams

* fix(providers): apply wrappers to direct streams

* fix(providers): wrap direct fallback streams

* fix(providers): compose ClawRouter native auth

* fix(providers): align ClawRouter package boundary

* fix(sdk): refresh plugin api baseline

* refactor(commands): hide doctor utility types

* refactor(commands): hide doctor state helper types

* refactor(commands): trim doctor probe type exports

* refactor(commands): trim setup barrel type exports

* fix(macos): preserve approvals migration data (openclaw#93880)

Merged via squash.

Prepared head SHA: a8a0dd0
Co-authored-by: vincentkoc <[email protected]>
Co-authored-by: vincentkoc <[email protected]>
Reviewed-by: @vincentkoc

* refactor(flows): hide setup helper types

* refactor(commands): trim custom provider type reexports

* fix(cron): reject invalid absolute timestamps (openclaw#93903)

* fix(cron): reject invalid absolute timestamps

* fix(cron): preserve ISO end of day

---------

Co-authored-by: Vincent Koc <[email protected]>

* refactor(commands): hide custom provider helper types

* fix(update): use configured npm registry for update metadata (openclaw#93879)

Merged via squash.

Prepared head SHA: ae8bbb0
Co-authored-by: vincentkoc <[email protected]>
Co-authored-by: vincentkoc <[email protected]>
Reviewed-by: @vincentkoc

* refactor(commands): trim status type exports

* refactor(commands): hide doctor helper types

* refactor(commands): hide migrate helper types

* refactor(config): hide local helper types

* revert(providers): remove ClawRouter provider

* refactor(config): hide session helper types

* refactor(gateway): hide local helper types

* refactor(gateway): hide websocket helper types

* refactor(infra): hide local helper types

---------

Co-authored-by: Vincent Koc <[email protected]>
Co-authored-by: Josh Lehman <[email protected]>
Co-authored-by: Shakker <[email protected]>
Co-authored-by: Jason O'Neal <[email protected]>
Co-authored-by: Vincent Koc <[email protected]>
Co-authored-by: Alix-007 <[email protected]>
Co-authored-by: ronan-dandelion-cult <[email protected]>
Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jun 17, 2026
* fix(cron): reject invalid absolute timestamps

* fix(cron): preserve ISO end of day

---------

Co-authored-by: Vincent Koc <[email protected]>
@clawsweeper clawsweeper Bot mentioned this pull request Jun 17, 2026
25 tasks
crh-code pushed a commit to crh-code/openclaw that referenced this pull request Jun 18, 2026
* fix(cron): reject invalid absolute timestamps

* fix(cron): preserve ISO end of day

---------

Co-authored-by: Vincent Koc <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size: S triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants