Two operator features that let a Setu site run things its manifest did not plan for. The first users are the Vyasa sites on the Setu production server: the public demo (demo.vyasa.site) needs demo-mode variables and an hourly reset, and a site that installs packages outside the marketplace needs VYASA_PACKAGE_TRUSTED_KEYS.
1. Extra env variables
An extra variable is a stored env entry whose name the site's manifest does not declare. Nothing marks it in storage: whether a variable is extra is derived from the manifest of the site's current version, wherever it is needed. The format of sites.env does not change.
- API.
PUT /api/v1/sites/{id}/envgains two optional fields:
The existingenvmap is unchanged; the three fields together must not be empty. Operator and above, audited assite.env_update.extra, a map from name to{ value, secret }, which adds or replaces extra variables;remove, a list of extra names to delete.
- Validation (in the API and again in the job):
- The name matches
^[A-Z_][A-Z0-9_]{0,127}$. - It is not a manifest name. Those go through
env, so the manifest always wins. - It is not reserved. The reserved names are
PATH,HOME,USER,LOGNAME,SHELL,PWD,TMPDIR,LANG,NOTIFY_SOCKET, and anything starting withLD_,SYSTEMD_,LISTEN_,INVOCATION_,CREDENTIALS_orSETU_. - The value has no control characters.
- At most 64 extra variables per site.
removenames must be existing extras.
- The name matches
- Storage. A secret extra is sealed (
v1:), like a secret manifest value, and is masked inGET envand readable only through reveal. A non-secret extra is storedplain:.GET enventries gainextra: bool. - Job.
env_updateappliesenv, thenextra, thenremove. It stores the result, rewrites the env file and restarts a running site, as today. The payload carries every value sealed, as today. - Updates. After
setu_manifest::merge, the update job re-appends every existing variable that is extra under the old manifest and not declared by the new one. If the new version starts declaring the name, the manifest rule takes over and the extra value is dropped. A rollback writes the old env, extras included. - UI. The site's Environment tab gets an Add variable form (name, value, Secret checkbox) and a Remove action on extra rows. Extra rows carry an "extra" chip.
2. Scheduled reset from a backup
An operator can choose one of a site's completed backups as its reset point and an interval. Setu then restores that backup on schedule.
- Schema. Migration
0003_site_resets.sqladds a tablesite_resetswith one row per site:
A separate table keeps every existingsitesquery unchanged.site_id, the primary key, referencessites (id)withON DELETE CASCADE;backup_idreferencesbackups (id)withON DELETE CASCADE;every_minutesis checked to be between 15 and 10080;last_reset_atrecords when the last reset was enqueued.
- API.
GET /api/v1/sites/{id}/reset(viewer and above) returns{ reset: { backup_id, every_minutes, last_reset_at, next_reset_at } | null }.PUTwith{ backup_id, every_minutes }sets the schedule (operator and above). The backup must belong to the site and becompleted. Setting it also setslast_reset_at = now, so the first reset comes one interval later.DELETE(operator and above) clears the schedule, or returns 404 when there is none.- The changes are audited as
site.reset_setandsite.reset_clear.
- Scheduler. On every tick, a site is reset when all of these hold:
The scheduler then enqueuesrestore_sitewith{ backup_id, reset: true }and setslast_reset_at = now. A missed reset happens once, on the next free tick; resets do not pile up.- its status is
running; - a schedule is set and the backup still exists and is
completed; now >= last_reset_at + every_minutes;- it has no active job.
- its status is
- Restore job. With
reset: trueitsbackupstep passes without taking apre_restorebackup; the step list stays the same, so a job resumed from its cursor still lines up. Taking a safety copy of a sandbox every hour would fill the disk with 30 days of pre-restore backups. Everything else is unchanged. - Retention. A backup that is any site's
reset_backup_idis never pruned by the scheduler, whatever its kind. Deleting it by hand is refused with 409 ("backup is the site's reset point; clear the schedule first"). - UI. The Backups tab gets Use as reset point on completed backups. It opens a dialog with an interval (every 15 min, 30 min, hourly, 6-hourly, daily, or weekly). A summary line at the top of the tab reads "Resets to <backup> every <interval>; next at <time>", with a Stop action.
Not in scope
Cron jobs inside the app (manifest v2, 0.4), env templating, and per-variable audit history.
Tests
- Env: an extra is added, masked when secret, and revealed; it survives an update to a version that does not declare it; it is replaced by the rule of a version that does.
- Env validation: a reserved name, a manifest name and a bad name are each refused in both the API and the job.
- Remove: removing an extra rewrites the env file.
- Scheduler: it resets when due, never while a job runs, and never twice for one missed window. The reset backup is never pruned, and its deletion is refused.
- Restore: with
resetthere is no pre-restore backup. - e2e: not extended in 0.1.4. The env file write is the existing
write_envpath, which e2e already covers.