Skip to content

feat(scanning): scheduled scans (cron-like) (#7) - #17

Merged
Metbcy merged 1 commit into
mainfrom
feat/scheduled-scans
Jun 3, 2026
Merged

feat(scanning): scheduled scans (cron-like) (#7)#17
Metbcy merged 1 commit into
mainfrom
feat/scheduled-scans

Conversation

@Metbcy

@Metbcy Metbcy commented Jun 3, 2026

Copy link
Copy Markdown
Owner

Summary

Implements #7: scheduled scans (cron-like recurring runs).

What's new

Backend

  • Migration 006_add_schedules_table.py adds two tables:
    • schedules (id, name, target_path, scan_types, cron_expression, last_run, enabled, created_at)
    • schedule_runs (id, schedule_id, scan_id, triggered_at) with index on (schedule_id, triggered_at DESC)
  • scheduler.pySchedulerService over APScheduler AsyncIOScheduler. Jobs registered from enabled DB rows at startup; reschedule/remove/add keep the live scheduler in sync with API mutations.
  • Multi-worker safety: _fire_schedule() uses a Redis SET NX EX lock (via the pubsub backplane from feat(infra): multi-worker uvicorn via Redis pubsub backplane #4) keyed on schedule:<id>:<minute_bucket> so two workers never fire the same trigger. Falls back to single-process when SECURESCAN_REDIS_URL is unset.
  • api/schedules.pyPOST/GET/PATCH/DELETE /api/v1/schedules and GET /{id}/runs. Admin scope. Cron expressions validated at 422 via CronTrigger.from_crontab.
  • apscheduler>=3.10.0 added to pyproject.toml.

Frontend

  • /settings/schedules page mirrors the keys/webhooks layout: DataTable, create/edit modal, delete confirm, schedule run-history drawer.
  • New Schedule / ScheduleRun types and CRUD helpers in lib/api.ts.
  • Sidebar nav entry.

Docs

  • docs/src/scanning/scheduled-scans.md.

Tests

  • 18 new tests pass, 1 skipped (Redis cross-worker double-fire test, gated on SECURESCAN_REDIS_URL exactly like the pubsub redis test).
  • Mocked APScheduler trigger creates a real Scan and a schedule_runs row.
  • Local: cd backend && ruff check . && ruff format --check . && python -m pytest tests/ -x -q — 950 passed, 4 skipped (pre-existing nmap/semgrep env-only failures excluded; same as main).

Notes

  • Defaults are off; admin opts in by creating a schedule.
  • Cron parser is APScheduler's, which accepts the standard 5-field crontab.
  • Lock TTL is 60s, scoped to the minute bucket so a slow worker never blocks a later trigger.

- Migration 006: adds schedules and schedule_runs tables
- SchedulerService backed by APScheduler AsyncIOScheduler; jobs are
  registered at startup from all enabled schedules in the DB
- Redis SET NX EX lock prevents double-fire across multiple workers
  when SECURESCAN_REDIS_URL is set; single-process fallback otherwise
- API: POST/GET/PATCH/DELETE /api/v1/schedules + GET /{id}/runs, all
  admin scope, cron validated via CronTrigger.from_crontab
- Frontend: /settings/schedules page (DataTable, create/edit modal,
  delete confirm, run-history drawer); sidebar entry added
- apscheduler>=3.10.0 added to pyproject.toml dependencies
- Docs: docs/src/scanning/scheduled-scans.md
- Tests: 18 unit+integration tests (CRUD, fire->scan, lock blocks
  double-fire); Redis test skipped when SECURESCAN_REDIS_URL not set
- Updated test_migrations.py to expect version 6

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@Metbcy
Metbcy merged commit 253043d into main Jun 3, 2026
2 checks passed
@Metbcy
Metbcy deleted the feat/scheduled-scans branch June 3, 2026 15:23
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.

1 participant