v0.101.0 — R-82: a leaked restore-test scratch can no longer auto-start

CORRECTION: I earlier reported that the restore-test would boot a scratch guest
with the live guest's MAC/static island IP/hostname and break the control
plane. That was WRONG — RunRestoreTest step 2 link-downs EVERY interface
(withLinkDown, unit-tested) before the guest is ever started. The design
already handled it.

The real, narrower hazard: a restore that fails BEFORE step 2 (what the v0.100.0
wait bug caused) leaves a scratch holding the SOURCE guest's config verbatim,
including onboot:1. If teardown also fails (403 missing VM.Allocate — PVE
associates the pool only at restore completion), a host reboot would start that
leaked clone alongside the original with NICs up.

- proxmox.RestoreLXCOptions.ConfigOverrides: guest-config params applied AT
  RESTORE TIME.
- The restore-test passes onboot=0 — at restore time, not after, because
  'after' is exactly the path that leaks.

NOT changed: the link-down step (already correct, the primary defence); the
agent's Proxmox privileges (widening VM.Allocate to /vms would remove the
accidental guard that stopped a destructive mid-restore teardown).

restore_test_cadence_seconds was set to -1 on demo-felhom under the mistaken
reading; re-enabled.

Red-proof observed; full suite green (29 packages).
This commit is contained in:
Claude Code
2026-07-26 16:49:40 +02:00
parent a7421b09c7
commit 0fabc15896
4 changed files with 80 additions and 0 deletions
+13
View File
@@ -47,6 +47,16 @@ type RestoreLXCOptions struct {
// 'mpN' to bind mount is only possible for root"); replacing it with a throwaway volume needs
// no root and the boot-verify doesn't need the drive's data.
MountOverrides map[string]string
// ConfigOverrides sets arbitrary guest-config params AT RESTORE TIME (they take precedence over
// the archive's own values), for settings that must hold from the instant the guest exists —
// before any post-restore SetConfig could run.
//
// The restore-test uses it for `onboot=0`. A restore that fails BEFORE the post-restore config
// step leaves a scratch guest carrying the SOURCE guest's config verbatim, including
// `onboot: 1` — so a leaked scratch would auto-start on the next host reboot, with the source's
// MAC, static island IP and hostname. Observed live 2026-07-26. The normal path link-downs every
// NIC before boot, so this is defence in depth for the ABNORMAL path, where the leak happens.
ConfigOverrides map[string]string
}
// RestoreLXC restores an LXC from a vzdump/PBS archive via POST /nodes/{node}/lxc
@@ -71,6 +81,9 @@ func (c *Client) RestoreLXC(ctx context.Context, opts RestoreLXCOptions) (string
for k, val := range opts.MountOverrides {
v.Set(k, val) // e.g. mp0 -> "local-lvm:1,mp=/data,backup=0" (overrides the archive's mp0)
}
for k, val := range opts.ConfigOverrides {
v.Set(k, val) // e.g. onboot -> "0" (a leaked scratch must never auto-start)
}
return c.dataString(ctx, http.MethodPost, "/nodes/"+c.node+"/lxc", v)
}