package host import ( "context" "os" "strings" "testing" "github.com/carlosframework/platform/internal/hostguard" "github.com/carlosframework/platform/internal/rootstate" ) func TestPlan14UnitRetirementExactOwner(t *testing.T) { for _, attack := range []string{"none", "successor", "running", "lost replace", "lost final write"} { t.Run(attack, func(t *testing.T) { b, in, shape := plan14UnitBindingFixture(t, "console.service", "", "") shape.Program = strings.Repeat("a", 64) b.canonical = func(context.Context, string) (claimUnitShape, error) { return shape, nil } captured, err := b.establish(t.Context(), in.Host) if err != nil { t.Fatal(err) } files := &plan14UnitFiles{} ms := &plan14UnitBindingFault{Store: &rollbackMemory{files: map[string][]byte{}}} material := claimUnitMaterializer{idle: func(string) error { return nil }, state: ms, read: files.read, create: files.create, replace: files.replace} if err = material.install(t.Context(), captured); err != nil { t.Fatal(err) } target := hostguard.FenceTarget{Host: in.Host, Incarnation: in.Incarnation, Stamp: in.Stamp, Box: in.Box, Enrollment: in.Enrollment} if attack == "successor" { target.Stamp++ } gone := func(context.Context, string, string) error { if attack == "running" { return os.ErrPermission } return nil } original := material.replace material.replace = func(unit string, id rootstate.FileIdentity, body []byte) error { if err := original(unit, id, body); err != nil { return err } if attack == "lost replace" { return os.ErrInvalid } if attack == "lost final write" { ms.fail = true } return nil } err = retireClaimBoundUnit(t.Context(), target, b, material, gone) if attack == "none" { if err != nil { t.Fatal(err) } } else if err == nil { t.Fatal("attack accepted") } if attack == "successor" || attack == "running" { if files.retires != 0 { t.Fatal("foreign or running retired") } return } material.replace = original ms.fail = false if err = retireClaimBoundUnit(t.Context(), target, b, material, gone); err != nil { t.Fatal("recover", err) } retired, err := b.read(in.Host) if err != nil || !retired.Retired || files.retires != 1 { t.Fatal(retired, err, files.retires) } }) } }