package host import ( "context" "errors" "testing" "github.com/carlosframework/platform/internal/hostbox" "github.com/carlosframework/platform/internal/hostclaim" "github.com/carlosframework/platform/internal/hostwrite" "github.com/carlosframework/platform/internal/provision" ) // mpLaunch is the probe's launch identity (Plan 3 H4): the pinned config // and the pinned release it launches with. func mpLaunch() hostwrite.Identity { p := mpPins() return hostwrite.Identity{Config: HeldConfigIdentity(p.BundleETags, p.OverlayETag).Config, Release: p.Release} } func mpProbingRecord() *provision.Record { rec := mpRecord() rec.Move.LandingPhase = provision.LandProbing return rec } // The probe's rows (Plan 3 Task 5, H4): at probing the held render, the // held release and the spawn are granted, the spawn only with the launch // identity bound to the pins, through hostbox.Policy.Check with the hold the // landing has. probed grants nothing to a fresh selection. func TestMovesClaimPolicyProbingRows(t *testing.T) { ctx := t.Context() moves := MovesClaimPolicy((&mpReader{rec: mpProbingRecord()}).read) policy := hostbox.Policy{Moves: moves, Held: func(context.Context, string) (string, error) { return mpOp, nil }} probing := mpClaim(hostclaim.KindLanding, hostclaim.PhaseLandingProbing) for action, id := range map[string]hostwrite.Identity{ "held-config": mpIdentity("held-config"), "held-release": mpIdentity("held-release"), "spawn": mpLaunch(), } { if err := policy.Check(ctx, probing, mpSelection(probing, action), id); err != nil { t.Fatalf("probing/%s: %v", action, err) } } for _, action := range []string{"held-timers", "restore", "seed", "writer", "install"} { if err := policy.Check(ctx, probing, mpSelection(probing, action), hostwrite.Identity{}); err == nil { t.Fatalf("probing/%s was granted", action) } } refused := func(err error, reason string) { t.Helper() var r *MovesPolicyRefusal if !errors.As(err, &r) || r.Reason != reason { t.Fatalf("got %v, want the refusal %q", err, reason) } } s := mpSelection(probing, "spawn") refused(moves(ctx, probing, s, hostwrite.Identity{}), "the identity does not fit the action") refused(moves(ctx, probing, s, hostwrite.Identity{Config: mpLaunch().Config}), "the identity does not fit the action") refused(moves(ctx, probing, s, hostwrite.Identity{Config: mpLaunch().Config, Release: "v9"}), "the launch is not the pinned one") refused(moves(ctx, probing, s, hostwrite.Identity{Config: HeldConfigIdentity(nil, "x").Config, Release: mpPins().Release}), "the launch is not the pinned one") noPins := mpProbingRecord() noPins.Move.Inputs = nil refused(MovesClaimPolicy((&mpReader{rec: noPins}).read)(ctx, probing, s, mpLaunch()), "no pinned inputs") marked := mpProbingRecord() marked.Move.Reason = provision.RollbackProbeAttempts refused(MovesClaimPolicy((&mpReader{rec: marked}).read)(ctx, probing, s, mpLaunch()), "the record is not this landing") probed := mpClaim(hostclaim.KindLanding, hostclaim.PhaseLandingProbed) for _, action := range mpActions { if err := policy.Check(ctx, probed, mpSelection(probed, action), mpLaunch()); err == nil { t.Fatalf("a fresh probed/%s selection was granted", action) } } } // The admitted probe session survives the landing's forward steps (H3): its // spawn selection, made at probing, is still granted once the claim is at // probed and then committed, with the same session; a held render selected // at probing is not, and no backward or skipped step is. func TestMovesClaimPolicyProbeSessionContinues(t *testing.T) { ctx := t.Context() reader := &mpReader{rec: mpProbingRecord()} moves := MovesClaimPolicy(reader.read) policy := hostbox.Policy{Moves: moves, Held: func(context.Context, string) (string, error) { return mpOp, nil }} selected := mpSelection(mpClaim(hostclaim.KindLanding, hostclaim.PhaseLandingProbing), "spawn") for phase, state := range map[string][2]string{ hostclaim.PhaseLandingProbed: {provision.MoveLanding, provision.LandProbed}, hostclaim.PhaseLandingCommitted: {provision.MoveCommitted, ""}, } { c := mpClaim(hostclaim.KindLanding, phase) reader.rec = mpProbingRecord() reader.rec.Move.State, reader.rec.Move.LandingPhase = state[0], state[1] if err := policy.Check(ctx, c, selected, mpLaunch()); err != nil { t.Fatalf("the probe's spawn at %s: %v", phase, err) } } reader.rec = mpProbingRecord() held := mpSelection(mpClaim(hostclaim.KindLanding, hostclaim.PhaseLandingProbing), "held-config") if err := policy.Check(ctx, mpClaim(hostclaim.KindLanding, hostclaim.PhaseLandingProbed), held, mpIdentity("held-config")); err == nil { t.Fatal("a held render selected at probing was granted at probed") } restored := mpSelection(mpClaim(hostclaim.KindLanding, provision.LandRestored), "spawn") if err := policy.Check(ctx, mpClaim(hostclaim.KindLanding, hostclaim.PhaseLandingProbing), restored, mpLaunch()); err == nil { t.Fatal("a spawn selected at restored was granted at probing") } back := mpSelection(mpClaim(hostclaim.KindLanding, hostclaim.PhaseLandingProbed), "spawn") if err := policy.Check(ctx, mpClaim(hostclaim.KindLanding, hostclaim.PhaseLandingProbing), back, mpLaunch()); err == nil { t.Fatal("a backward step was granted") } } // Task 7, the committed wake: at landing/committed a fresh selection's spawn // is granted only with the ordinary launch identity the committed input // check accepts, against a committed record of this move. Without the check // (production until the claim binds one) it is refused. func TestMovesClaimPolicyCommittedSpawn(t *testing.T) { ctx := t.Context() committed := mpRecord() committed.Move.State, committed.Move.LandingPhase = provision.MoveCommitted, "" reader := &mpReader{rec: committed} checked := 0 ordinary := hostwrite.Identity{Config: "sha256:env", Release: "sha256:bytes"} inputs := func(_ context.Context, c *hostclaim.Claim, s hostbox.Selection, id hostwrite.Identity) error { checked++ if id != ordinary { return errors.New("not the launch") } return nil } policy := hostbox.Policy{Moves: MovesClaimPolicyWithInputs(reader.read, inputs), Held: func(context.Context, string) (string, error) { return "", nil }} c := mpClaim(hostclaim.KindLanding, hostclaim.PhaseLandingCommitted) s := mpSelection(c, "spawn") if err := policy.Check(ctx, c, s, ordinary); err != nil || checked != 1 { t.Fatalf("the committed wake's spawn: %v checked=%d", err, checked) } if err := policy.Check(ctx, c, s, hostwrite.Identity{Config: "x", Release: "y"}); err == nil { t.Fatal("another launch was granted") } for _, action := range []string{"held-config", "held-release", "restore", "install"} { if err := policy.Check(ctx, c, mpSelection(c, action), ordinary); err == nil { t.Fatalf("committed/%s was granted", action) } } reader.rec = mpProbingRecord() if err := policy.Check(ctx, c, s, ordinary); err == nil { t.Fatal("a committed spawn over a record that is not committed was granted") } reader.rec = committed unchecked := hostbox.Policy{Moves: MovesClaimPolicy(reader.read), Held: func(context.Context, string) (string, error) { return "", nil }} if err := unchecked.Check(ctx, c, s, ordinary); err == nil { t.Fatal("a committed spawn without an input check was granted") } }