package hostfence import ( "context" "crypto/sha256" "encoding/hex" "encoding/json" "testing" "github.com/aws/aws-sdk-go-v2/service/ec2/types" "github.com/carlosframework/platform/internal/awsinv" "github.com/carlosframework/platform/internal/hostclaim" ) func TestC7FenceReaderAuthenticatesRosterAndCloud(t *testing.T) { for _, tc := range []string{"valid", "enrollment", "account", "cloud-region", "instance", "reporter", "nonterminal", "signature", "self-reporter"} { t.Run(tc, func(t *testing.T) { ctx := context.Background() w, s := terminationFixture(t) w.Reader = func(context.Context, string) (awsinv.ExactEC2API, error) { return terminatedEC2{state: types.InstanceStateNameTerminated, owner: "123"}, nil } got, err := w.Describe(ctx, "dead") if err != nil { t.Fatal(err) } ref := ClaimFenceRef(got) raw, etag, err := s.Get(ctx, ref.Key) if err != nil { t.Fatal(err) } var f Termination if err = json.Unmarshal(raw, &f); err != nil { t.Fatal(err) } switch tc { case "enrollment": f.Enrollment = "cccccccccccccccccccccccccccccccc" case "account": f.Cloud.Account = "456" case "cloud-region": f.Cloud.Region = "eu-west-2" case "instance": f.Cloud.InstanceID = "i-other" case "reporter": f.WrittenBy.Enrollment = "cccccccccccccccccccccccccccccccc" case "nonterminal": f.State = "shutting-down" case "self-reporter": f.WrittenBy.Box = f.Box f.WrittenBy.Enrollment = f.Enrollment case "signature": w.Directory.PublicKey = make([]byte, 32) } raw, err = json.Marshal(f) if err != nil { t.Fatal(err) } // Deliberately replace the object in this local adversarial fixture and // recompute its digest: a digest match alone must not grant authority. if _, err = s.Put(ctx, ref.Key, raw, etag); err != nil { t.Fatal(err) } sum := sha256.Sum256(raw) ref.SHA256 = hex.EncodeToString(sum[:]) _, err = hostclaim.VerifyFence(ctx, s, ClaimFenceAuthority{Directory: w.Directory, Now: w.Now}, ref) if (err == nil) != (tc == "valid") { t.Fatalf("%s: %v", tc, err) } }) } }