clusev/app/Models
boban 5e4f29216d feat(commands): ad-hoc fleet commands + runbooks (feature 4/8)
The multi-server amplifier: run a command (ad-hoc or a saved runbook) across the whole fleet,
a group, or a selection, with a per-server result. Because it is arbitrary remote execution,
authorization + audit are the whole feature.

- The command is intentionally arbitrary; it runs via FleetService::runPlain (the credential's
  login user, base64 transport, NO extra sudo) — the same privilege the web terminal already
  grants, batched. No injection to prevent; the concern is who may run + that every run is logged.
- CommandRunner.run: per-server runPlain, one server failing never aborts the batch, output
  byte-capped (256 KiB) + mb_scrub'd before it reaches a Livewire property.
- Commands\Index page, fully `operate`-gated: route can:operate + mount() + a per-method gate() on
  run/runRunbook/execute/createRunbook/confirmDeleteRunbook/deleteRunbook. Every run goes through a
  signed single-use ConfirmToken + R5 confirm modal ("run on N servers?"); the modal audits
  command.run from the sealed token so execute() does not re-audit. Targets resolve client UUIDs →
  ids server-side (withActiveCredential + inGroup + whereIn), and {command, serverIds} is SEALED in
  the token — a client can't swap the command or targets after confirm. A forged token is a no-op.
- Runbooks: saved name+command, operate-gated CRUD, delete via ConfirmToken.
- lang/{de,en}/commands.php + audit.php command.run / runbook.* + shell.nav_commands (de/en). No emoji.

15 new tests: CommandRunner (runs each server, one-failing-doesn't-abort, nonzero=not-ok, byte-cap
+scrub), component (route gating, ad-hoc run opens confirm, empty-command / no-target errors, execute
runs the SEALED targets, forged token runs nothing, group scope targets only members, runbook create
+audit + run + delete-via-token). 700 tests green, Pint, lang parity, Codex-reviewed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 20:38:09 +02:00
..
AlertIncident.php feat(alerts): threshold alerting + notifications (feature 2/8) 2026-07-05 20:07:54 +02:00
AlertRule.php feat(alerts): threshold alerting + notifications (feature 2/8) 2026-07-05 20:07:54 +02:00
AuditEvent.php feat(honeypot): surface login attempts in the dashboard (threats KPI, tried-credentials, sidebar badge) 2026-07-05 10:49:38 +02:00
BannedIp.php feat(auth): BannedIp model + migration 2026-06-20 17:26:28 +02:00
HostCredential.php security: harden proxy trust + model mass-assignment + terminal-token log hygiene 2026-06-26 07:16:10 +02:00
MetricSample.php feat(metrics): persistent resource-history graph on the Server-Details page 2026-06-25 01:31:27 +02:00
Runbook.php feat(commands): ad-hoc fleet commands + runbooks (feature 4/8) 2026-07-05 20:38:09 +02:00
Server.php feat(fleet): server groups — organise the fleet + filter (feature 1/8) 2026-07-05 19:36:17 +02:00
ServerGroup.php feat(fleet): server groups — organise the fleet + filter (feature 1/8) 2026-07-05 19:36:17 +02:00
Setting.php feat(security): dashboard hardening, credential mgmt, system domain/TLS + channel, self-hardening 2026-06-13 02:25:23 +02:00
SshCredential.php chore(audit): full code sweep — fix open-redirect, drop dead code, clean docs 2026-06-13 12:54:26 +02:00
TerminalSession.php security: harden proxy trust + model mass-assignment + terminal-token log hygiene 2026-06-26 07:16:10 +02:00
User.php feat(rbac): role enum + column + gates foundation (admin>operator>viewer) 2026-07-05 00:42:16 +02:00
WebauthnCredential.php fix(webauthn): hash-indexed credential ids + reset keys on 2FA disable 2026-06-14 18:40:24 +02:00
WgTrafficSample.php feat(wg): wg_traffic_samples table + model 2026-06-20 23:59:11 +02:00