Skip to content

Commit 669eb90

Browse files
Pigbibicodex
andcommitted
fix(runtime): validate weekday cron semantics
Co-Authored-By: Codex <noreply@openai.com>
1 parent 1180f59 commit 669eb90

2 files changed

Lines changed: 63 additions & 4 deletions

File tree

‎scripts/build_cloud_run_env_sync_plan.py‎

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,50 @@ def _should_add_local_src(candidate: Path) -> bool:
136136
"probe_time": "CLOUD_SCHEDULER_PROBE_TIME",
137137
"precheck_time": "CLOUD_SCHEDULER_PRECHECK_TIME",
138138
}
139+
WEEKDAY_CRON_DAYS = frozenset({1, 2, 3, 4, 5})
140+
CRON_DAY_NAMES = {
141+
"SUN": 0,
142+
"MON": 1,
143+
"TUE": 2,
144+
"WED": 3,
145+
"THU": 4,
146+
"FRI": 5,
147+
"SAT": 6,
148+
}
149+
150+
151+
def _cron_day_value(raw: str) -> int:
152+
value = raw.strip().upper()
153+
if value in CRON_DAY_NAMES:
154+
return CRON_DAY_NAMES[value]
155+
numeric = int(value)
156+
if not 0 <= numeric <= 7:
157+
raise ValueError(f"Invalid cron day-of-week value: {raw!r}")
158+
return numeric % 7
159+
160+
161+
def _cron_days_of_week(raw: str) -> set[int]:
162+
days: set[int] = set()
163+
for item in raw.split(","):
164+
base, separator, raw_step = item.strip().partition("/")
165+
step = int(raw_step) if separator else 1
166+
if step <= 0:
167+
raise ValueError(f"Invalid cron day-of-week step: {item!r}")
168+
if base == "*":
169+
values = list(range(7))
170+
elif "-" in base:
171+
raw_start, raw_end = base.split("-", 1)
172+
start = _cron_day_value(raw_start)
173+
end = _cron_day_value(raw_end)
174+
values = [start]
175+
while values[-1] != end:
176+
values.append((values[-1] + 1) % 7)
177+
if len(values) > 7:
178+
raise ValueError(f"Invalid cron day-of-week range: {item!r}")
179+
else:
180+
values = [_cron_day_value(base)]
181+
days.update(values[::step])
182+
return days
139183

140184
# Strategy-derived vars: auto-populated from platform-config.json defaults.
141185
def _derive_strategy_env_defaults(strategy_config: dict) -> dict[str, str]:
@@ -512,7 +556,11 @@ def _build_scheduler_plan(
512556
if len(fields) == 2:
513557
scheduler[key] = " ".join([*fields, "*", "*", "1-5"])
514558
fields = scheduler[key].split()
515-
if len(fields) != 5 or fields[2:] != ["*", "*", "1-5"]:
559+
try:
560+
scheduled_days = _cron_days_of_week(fields[4]) if len(fields) == 5 else set()
561+
except (TypeError, ValueError):
562+
scheduled_days = set()
563+
if len(fields) != 5 or fields[2] != "*" or not scheduled_days or not scheduled_days <= WEEKDAY_CRON_DAYS:
516564
raise ValueError(
517565
f"US live account scheduler {key} must be Mon-Fri cron: {scheduler[key]!r}"
518566
)

‎tests/test_runtime_config_support.py‎

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1306,11 +1306,22 @@ def test_build_cloud_run_env_sync_plan_rejects_weekend_schedule_and_force_run_fo
13061306

13071307
runtime_target["scheduler"] = {
13081308
"timezone": "America/New_York",
1309-
"main_time": "45 15 * * 1-5",
1310-
"probe_time": "35 9,15 * * 1-5",
1311-
"precheck_time": "45 9 * * 1-5",
1309+
"main_time": "45 15 * * 1,3,5",
1310+
"probe_time": "35 9,15 * * MON-FRI",
1311+
"precheck_time": "45 9 * * 2-5",
13121312
}
13131313
payload["targets"][0]["runtime_target"] = runtime_target
1314+
env["CLOUD_RUN_SERVICE_TARGETS_JSON"] = json.dumps(payload)
1315+
result = subprocess.run(
1316+
[sys.executable, str(SYNC_PLAN_SCRIPT_PATH), "--json"],
1317+
capture_output=True,
1318+
text=True,
1319+
env=env,
1320+
)
1321+
1322+
assert result.returncode == 0
1323+
assert json.loads(result.stdout)["targets"][0]["scheduler"] == runtime_target["scheduler"]
1324+
13141325
payload["targets"][0]["IBKR_FORCE_RUN"] = "true"
13151326
env["CLOUD_RUN_SERVICE_TARGETS_JSON"] = json.dumps(payload)
13161327
result = subprocess.run(

0 commit comments

Comments
 (0)