Skip to content

Conversation

@pheus
Copy link
Contributor

@pheus pheus commented Oct 17, 2025

Fixes: #20524

Tightens script scheduling validation:

  • Rejects schedule_at values in the past.
  • When only interval is provided, starts now and repeats.
  • Uses local_now() for accurate, timezone‑aware comparisons.

Small, backward‑compatible fix to make scheduling behave as expected.

@jeremystretch jeremystretch requested review from a team and jnovinger and removed request for a team October 17, 2025 20:46
Copy link
Member

@jnovinger jnovinger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @pheus. This fix looks good, although I did note one other edge case (w/ a suggestion) that the original bug report did not mention. Can you please address that, since we're already making changes there?

Could you please also add the following tests for this? Probably in ScriptTest around line 910 in netbox/extras/tests/test_api.py:

def test_schedule_script_past_time_rejected(self):
    """Scheduling with past schedule_at should 
fail"""
    # POST with schedule_at = timezone.now() - timedelta(hours=1)
    # Expect 400 with "must be in the future" error

def test_schedule_script_interval_only(self):
    """Interval without schedule_at should auto-set 
schedule_at to now"""
    # POST with interval=60, no schedule_at
    # Verify job created with schedule_at set

def test_schedule_script_when_disabled(self):
    """Scheduling should fail when 
script.scheduling_enabled=False"""
    # POST with schedule_at or interval

Let me know if you have any questions.

Validates the given data and ensures the necessary fields are populated.
"""
# Set the schedule_at time to now if only an interval is provided.
if 'interval' in data and 'schedule_at' not in data:
Copy link
Member

@jnovinger jnovinger Oct 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if 'interval' in data and 'schedule_at' not in data:
if 'interval' in data and not data.get('schedule_at'):

It seems there's a case not noticed in the original issue, where the API caller might pass something like {"scheduled": null, "interval": 60} and they'd end up with a recurring job that has no set start time. All other edge-case-y values that I could think of that might satisfy this conditional fail because they aren't a valid datetime format.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great point, and I agree. I’ll use .get() for both schedule_at and interval. Using .get() treats an explicit null the same as a missing key, so the “interval‑only” behavior still applies when schedule_at is null.

I’ll normalize & validate accordingly:

  • If both are None → no scheduling (run now).
  • If interval is set and schedule_at is falsy → schedule_at = local_now().
  • If schedule_at is set → must be in the future.
  • If either is set and scheduling_enabled is False → reject.

Add validation for script scheduling to ensure the `schedule_at` time
is in the future and default to the current time when only `interval`
is provided. Incorporate `local_now` for accurate time comparisons.

Fixes netbox-community#20524
@pheus pheus force-pushed the 20524-prevent-jobs-scheduled-in-the-past-via-api branch from 70d7a0a to f8b2efa Compare October 18, 2025 13:31
Comment on lines +891 to 893
@property
def python_class(self):
return self.TestScriptClass
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make this a property to mirror the model’s cached_property. This returns the class object (not a bound function), which fixes the test setup and matches production behavior.

@pheus
Copy link
Contributor Author

pheus commented Oct 18, 2025

Thanks for the thoughtful review!

I’ve pushed updates to address your suggestion and added tests:

  • Use .get() so {"schedule_at": null, "interval": 60} starts now (no start‑less recurring job).
  • Tests added: past schedule_at → 400; interval‑only → auto‑sets schedule_at; scheduling disabled → reject.
  • Fixed the test setup to return the class from python_class, matching production behavior.

Happy to tweak anything.

@pheus pheus requested a review from jnovinger October 18, 2025 13:49
@jnovinger jnovinger merged commit 2a1d315 into netbox-community:main Oct 19, 2025
7 checks passed
@pheus pheus deleted the 20524-prevent-jobs-scheduled-in-the-past-via-api branch October 19, 2025 17:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Possibility to schedule script in the past

2 participants