agent v0.86.0: DR-tier-by-default — capability inactive state (GatedBy/GateActive, pbsdr gate via DRConfigured) + F-3 root-run provision parent ownership

Claude-Session: https://claude.ai/code/session_01NptTCFtu7dz2Ru89qHRagN
This commit is contained in:
2026-07-12 20:06:27 +02:00
parent bcb8dad2aa
commit c20814e6c2
11 changed files with 403 additions and 148 deletions
+20
View File
@@ -52,6 +52,9 @@ type BackHalf struct {
logger *slog.Logger
}
// geteuid is the effective-uid seam (F-3): tests fake a root run without being root.
var geteuid = os.Geteuid
// NewBackHalf builds the back-half. stateDir defaults to /var/lib/felhom-agent when empty.
func NewBackHalf(tokens TokenMinter, runner proxmox.Runner, stateDir string, logger *slog.Logger) *BackHalf {
if stateDir == "" {
@@ -135,6 +138,23 @@ func (b *BackHalf) Provision(ctx context.Context, in Input) (Result, error) {
if err := os.MkdirAll(hostDir, 0o700); err != nil {
return Result{}, fmt.Errorf("provision: config dir: %w", err)
}
// 3b. F-3 (DRILL-day0-vm-2026-07-12): a ROOT-run provision (the Day-0 one-shot) leaves the
// just-created guests/ + guests/<vmid>/ parents root:root 0700 inside the agent-owned
// state dir — the non-root daemon's lanresolver then can't traverse them ("permission
// denied"). Own the two PARENTS to whatever owns the state dir (chown --reference; the
// installer made that the agent user). NON-recursive on purpose: only the bootstrap leaf
// below belongs to the mapped guest-root. A daemon-run provision creates them as the
// agent user already — euid≠0 skips (and needs no sudoers vector for this shape).
if geteuid() == 0 {
guestsDir := filepath.Join(b.stateDir, "guests")
vmidDir := filepath.Join(guestsDir, strconv.Itoa(in.VMID))
if err := b.run(ctx, "chown", "--reference="+b.stateDir, guestsDir, vmidDir); err != nil {
// Warn-only: the drill's manual fix is a one-liner and lanresolver degrades visibly.
b.logger.Warn("provision: could not own guests parent dirs to the state-dir owner (F-3)",
"err", err)
}
}
bootPath := filepath.Join(hostDir, bootstrapFile)
if err := os.WriteFile(bootPath, rendered, 0o600); err != nil {
return Result{}, fmt.Errorf("provision: write bootstrap: %w", err)