Document the PHP api layer and fix what documenting it exposed
Writing down what each endpoint actually guarantees made the places it didn't obvious — shell arguments reaching a crontab or a bash -c unescaped, master.conf written without tmp+rename, and conf edits that could be saved without ever being parsed.
This commit is contained in:
@@ -1,6 +1,64 @@
|
||||
<?php
|
||||
// Save custom-script folder assignments to schedule.json (__folders key).
|
||||
// POST: folders (JSON-encoded object: {"FolderName": ["Custom/script.sh", ...]})
|
||||
// ═══════════════════════════════════════════════════════════════════════════════════════════════
|
||||
// PURPOSE
|
||||
// Script folder assignments. Saves the grouping of scripts into named folders on the
|
||||
// scheduler page, stored in schedule.json under the __folders key.
|
||||
//
|
||||
// OPERATIONAL MODEL
|
||||
// Whole-map replacement, not a patch. The page sends the complete folder structure and it
|
||||
// replaces __folders entirely, so a removed folder disappears by absence. Reconciling
|
||||
// individual moves would need a change log the UI does not have and cannot produce from a
|
||||
// drag.
|
||||
//
|
||||
// Stored alongside the schedule rather than in a file of its own, under a key prefixed with
|
||||
// __ to keep it out of the job namespace — the same convention __rsync_* uses. Everything
|
||||
// that iterates the schedule as jobs skips these keys by prefix.
|
||||
//
|
||||
// DESIGN PRINCIPLES
|
||||
// Presentation only. Folder membership changes nothing about whether or when a script runs;
|
||||
// vv_cron_rebuild() never reads __folders, which is why this endpoint does not trigger one.
|
||||
//
|
||||
// Invalid entries are dropped, not rejected.
|
||||
// A bad folder name or an unrecognised script id is skipped and the rest of the map is
|
||||
// saved. Failing the whole request would lose a full reorganisation over one stale
|
||||
// entry — and the entries most likely to be stale are scripts deleted since the page
|
||||
// loaded.
|
||||
//
|
||||
// OPERATIONAL SAFEGUARDS
|
||||
// POST only, checked before the payload is read.
|
||||
//
|
||||
// The payload must decode to an array.
|
||||
// is_array() on the decoded JSON — a truncated or non-JSON body is refused outright
|
||||
// rather than writing an empty map, which would silently erase every folder.
|
||||
//
|
||||
// Every script id is validated exactly as the run paths validate it.
|
||||
// ^[A-Za-z0-9_.\-/]+\.sh$ with an explicit '..' check, applied per entry. These ids are
|
||||
// stored and later handed back to the page as job references, so a value that could not
|
||||
// be run has no business being persisted next to ones that can.
|
||||
//
|
||||
// Folder names are length-capped and type-coerced.
|
||||
// Cast to string, trimmed, empty rejected, and capped at 80 characters — a JSON object
|
||||
// with numeric or absurdly long keys cannot bloat schedule.json, which is read on every
|
||||
// scheduler page load and every cron rebuild.
|
||||
//
|
||||
// Non-array folder contents are skipped.
|
||||
// is_array() per folder before iterating, so a malformed value cannot raise a warning
|
||||
// into the JSON response.
|
||||
//
|
||||
// The rest of the schedule is preserved.
|
||||
// The file is loaded, one key replaced, and the whole structure written back — job
|
||||
// entries and __rsync_* keys are carried through untouched.
|
||||
//
|
||||
// REQUEST
|
||||
// POST folders=<JSON object: {"<folder name>": ["Category/script.sh", …], …}>
|
||||
//
|
||||
// RESPONSE
|
||||
// {"ok":true}
|
||||
// {"ok":false,"error":"POST only"|"Invalid JSON"|"Write failed"}
|
||||
//
|
||||
// DEPENDS ON
|
||||
// include/scheduler.php vv_schedule_load(), vv_schedule_save()
|
||||
// ═══════════════════════════════════════════════════════════════════════════════════════════════
|
||||
header('Content-Type: application/json');
|
||||
require_once dirname(__DIR__) . '/include/config.php';
|
||||
require_once dirname(__DIR__) . '/include/scheduler.php';
|
||||
|
||||
Reference in New Issue
Block a user