Files
felhom-agent/internal/signedjobs/chain.go
T
admin 109dd853a3 v0.28.0: backup re-target → felhom-pbs (offsite DR) + operator-signed decommission
- BackupConfig.BackupTarget() defaults whole-guest backup to felhom-pbs (separate
  hardware = real DR), configurable via backup.local_backup_target; all NewBackupRunner
  sites route through it. PBS round-trip proven live (snapshot marker + restore-test +
  pct-restore) before the re-point.
- signedjobs DecommissionExecutor + ExecutorChain: makes IntentDecommissioned reachable
  ONLY via a verified operator signature (keyed by the watchdog's storage durable-id);
  felhom-opsign builds decommission params from -durable-id. Runner wiring moved below
  the intent-store open.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-12 20:26:34 +02:00

26 lines
1017 B
Go

package signedjobs
import (
"context"
"encoding/json"
)
// ExecutorChain dispatches a verified signed op to the first sub-executor that OWNS it. A sub-
// executor returns ErrNoExecutor for an op class it does not handle; the chain then tries the next.
// If no sub-executor owns the op, the chain returns ErrNoExecutor so the runner leaves the job
// queued for a later slice (the same contract a single executor has). The chain adds no policy — the
// gate has already verified+bound the op before any Execute runs.
type ExecutorChain []Executor
// Execute implements Executor by trying each sub-executor in order.
func (c ExecutorChain) Execute(ctx context.Context, op string, params json.RawMessage) error {
for _, e := range c {
err := e.Execute(ctx, op, params)
if errorsIs(err, ErrNoExecutor) {
continue // this sub-executor doesn't own the op — try the next
}
return err // owned (handled or failed) — done
}
return ErrNoExecutor // no sub-executor owns this op class in this build
}