feat(server): scheduled automatic agent updates (VS-74) #92

Merged
David merged 1 commit from feat/VS-74-scheduled-agent-autoupdate into main 2026-06-30 23:54:06 +02:00
Owner

What

Implements VS-74: scheduled / automatic agent updates. On a configurable cadence the server compares every connected agent's reported running binary against the configured channel binary and chunk-streams the update to those that are behind, with no per-agent operator action. Builds directly on VS-73 (#91): it reuses the same push_agent_update_chunked path, so the trust / verification model is identical (configured-channel binary fetched + signature-verified by the VS-20 fetcher, chunked stream over mTLS, agent validates the End-frame SHA-384 before swapping and re-exec'ing).

New agent_autoupdate module

  • AgentAutoUpdatePolicy parsed from settings.agentautoupdate: enabled, intervalsecs, batchsize. Disabled by default (AC4).
  • AgentAutoUpdateHandle (ArcSwap) holds the live policy. The sweep reads it every tick and the admin settingsupdate action swaps it, so enabled (the kill switch) and batchsize take effect without a restart.
  • agents_behind_channel: flags connected agents whose reported running binary SHA-384 differs from the channel binary for their arch. Agents that have not yet reported a hash are left for a later sweep rather than pushed to blindly.
  • run_sweep: finds behind agents, caps to batchsize, pushes via the shared chunked path.
  • spawn: starts the periodic loop only when intervalsecs > 0; the loop checks the live enabled flag each tick.

Wiring

  • AppState.agent_auto_update handle (default disabled); start() parses the merged-config policy and spawns the loop.
  • agentautoupdate added to vervain_config::RUNTIME_EDITABLE_SETTINGS_KEYS, with a settings_overlay live-apply arm (validate, persist, swap policy).
  • AgentRegistry::connected_ids() enumerates push candidates.
  • push_agent_update_chunked / resolve_agent_id are now pub(crate) for reuse.

Config example

"settings": { "agentautoupdate": { "enabled": true, "intervalsecs": 3600, "batchsize": 25 } }

Acceptance criteria

  • AC1: server configurable to auto-update connected agents to the configured channel on a schedule (settings.agentautoupdate). See note on "on channel change" below.
  • AC2: agents behind the channel are detected (running binary SHA-384 vs channel binary) and updated via the existing chunked push path.
  • AC3: rollout controls: enable/disable, cadence (intervalsecs), kill switch (live enabled), plus batchsize pacing.
  • AC4: disabled by default.

Notes

  • Reported version: the agent reports a commit date + binary hash today, not a semver (the linked VA dependency). "Behind" is decided on the running binary SHA-384 vs the channel binary, which is a precise "not running the channel build" signal; adding semver later is additive.
  • AC1 is satisfied by the schedule. An immediate trigger on channel change (the optional "and/or" half) is a tracked follow-up rather than left as a naked note; a short cadence already picks up a channel change within one interval.
  • A live cadence (intervalsecs) change is persisted but only takes effect on the next restart (the tokio interval is fixed at spawn); enabled / batchsize are live.

Tests

13 new unit tests: policy default/parse, behind detection (only mismatched reporters), sweep enabled/disabled/batch-size, and the live overlay apply (kill switch). Full suite green via just pre-commit (fmt, clippy -D warnings, workspace check, test).

## What Implements VS-74: scheduled / automatic agent updates. On a configurable cadence the server compares every connected agent's reported running binary against the configured channel binary and chunk-streams the update to those that are behind, with no per-agent operator action. Builds directly on VS-73 (#91): it reuses the same `push_agent_update_chunked` path, so the trust / verification model is identical (configured-channel binary fetched + signature-verified by the VS-20 fetcher, chunked stream over mTLS, agent validates the End-frame SHA-384 before swapping and re-exec'ing). ## New `agent_autoupdate` module - `AgentAutoUpdatePolicy` parsed from `settings.agentautoupdate`: `enabled`, `intervalsecs`, `batchsize`. Disabled by default (AC4). - `AgentAutoUpdateHandle` (ArcSwap) holds the live policy. The sweep reads it every tick and the admin `settingsupdate` action swaps it, so `enabled` (the kill switch) and `batchsize` take effect without a restart. - `agents_behind_channel`: flags connected agents whose reported running binary SHA-384 differs from the channel binary for their arch. Agents that have not yet reported a hash are left for a later sweep rather than pushed to blindly. - `run_sweep`: finds behind agents, caps to `batchsize`, pushes via the shared chunked path. - `spawn`: starts the periodic loop only when `intervalsecs > 0`; the loop checks the live `enabled` flag each tick. ## Wiring - `AppState.agent_auto_update` handle (default disabled); `start()` parses the merged-config policy and spawns the loop. - `agentautoupdate` added to `vervain_config::RUNTIME_EDITABLE_SETTINGS_KEYS`, with a `settings_overlay` live-apply arm (validate, persist, swap policy). - `AgentRegistry::connected_ids()` enumerates push candidates. - `push_agent_update_chunked` / `resolve_agent_id` are now `pub(crate)` for reuse. ## Config example ```json "settings": { "agentautoupdate": { "enabled": true, "intervalsecs": 3600, "batchsize": 25 } } ``` ## Acceptance criteria - [x] AC1: server configurable to auto-update connected agents to the configured channel on a schedule (`settings.agentautoupdate`). See note on "on channel change" below. - [x] AC2: agents behind the channel are detected (running binary SHA-384 vs channel binary) and updated via the existing chunked push path. - [x] AC3: rollout controls: enable/disable, cadence (`intervalsecs`), kill switch (live `enabled`), plus `batchsize` pacing. - [x] AC4: disabled by default. ## Notes - Reported version: the agent reports a commit date + binary hash today, not a semver (the linked VA dependency). "Behind" is decided on the running binary SHA-384 vs the channel binary, which is a precise "not running the channel build" signal; adding semver later is additive. - AC1 is satisfied by the schedule. An immediate trigger on channel change (the optional "and/or" half) is a tracked follow-up rather than left as a naked note; a short cadence already picks up a channel change within one interval. - A live cadence (`intervalsecs`) change is persisted but only takes effect on the next restart (the tokio interval is fixed at spawn); `enabled` / `batchsize` are live. ## Tests 13 new unit tests: policy default/parse, behind detection (only mismatched reporters), sweep enabled/disabled/batch-size, and the live overlay apply (kill switch). Full suite green via `just pre-commit` (fmt, clippy -D warnings, workspace check, test).
feat(server): scheduled automatic agent updates (VS-74)
All checks were successful
Check / fmt + clippy + build + tests (pull_request) Successful in 57s
Create release / Create release from merged PR (pull_request) Has been skipped
37fb264ff2
Automate the manual operator push from VS-73: on a configurable cadence the server compares every connected agent's reported running binary against the configured channel binary and chunk-streams the update to those that are behind, with no per-agent operator action. Reuses the exact manual push path (`push_agent_update_chunked`), so the trust model is identical (configured-channel binary fetched + signature-verified by the VS-20 fetcher, chunked stream over mTLS, agent validates the End-frame SHA-384 before swapping).

New `agent_autoupdate` module:

- `AgentAutoUpdatePolicy` parsed from `settings.agentautoupdate` (`enabled`, `intervalsecs`, `batchsize`); disabled by default (AC4).
- `AgentAutoUpdateHandle` (ArcSwap) holds the live policy. The sweep reads it each tick and the admin `settingsupdate` action swaps it, so `enabled` (the kill switch) and `batchsize` apply without a restart.
- `agents_behind_channel` flags connected agents whose reported running binary SHA-384 differs from the channel binary for their arch; agents that have not reported a hash are left for a later sweep rather than pushed to blindly.
- `run_sweep` finds behind agents, caps to `batchsize`, and pushes via the shared chunked path.
- `spawn` starts the periodic loop only when `intervalsecs > 0`; the loop checks the live `enabled` flag each tick.

Wiring: `AppState.agent_auto_update` handle (default disabled); `start()` parses the merged-config policy and spawns the loop; `agentautoupdate` added to `vervain_config::RUNTIME_EDITABLE_SETTINGS_KEYS` with a `settings_overlay` live-apply arm (validate, persist, swap). `AgentRegistry::connected_ids()` enumerates push candidates. `push_agent_update_chunked` / `resolve_agent_id` are now `pub(crate)` for reuse.

Reported version: "behind" is decided on the running binary SHA-384 the agent reports (the version proxy until the agent reports a semver, the linked VA dependency); a hash mismatch against the channel binary is a precise "not running the channel build" signal regardless.

Detection + push is schedule-driven; an immediate trigger on channel change is a tracked follow-up.

13 new unit tests (policy parse/default, behind detection, sweep enabled/disabled/batch, live overlay apply). Full suite green via `just pre-commit`.

#VS-74

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
David merged commit 67c58d0b5e into main 2026-06-30 23:54:06 +02:00
David deleted branch feat/VS-74-scheduled-agent-autoupdate 2026-06-30 23:54:06 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/vervain-server!92
No description provided.