package host import ( "crypto/ed25519" "crypto/sha256" "encoding/hex" "encoding/json" "github.com/carlosframework/platform/internal/hostactors" "github.com/carlosframework/platform/internal/hostclaim" "github.com/carlosframework/platform/internal/hostevidence" "github.com/carlosframework/platform/internal/release" "strings" "testing" "time" ) func TestPlan12RecoveryRootReceiptAlternative(t *testing.T) { t.Parallel() for _, bad := range []string{"", "session", "stamp", "enrollment", "signature", "operation", "region", "digest"} { t.Run(bad, func(t *testing.T) { f, o, h := plan12Handover(t, hostclaim.KindRestoring, "stop") key := ed25519.NewKeyFromSeed([]byte(strings.Repeat("b", 32))) en := strings.Repeat("a", 32) d := hostactors.Directory{Store: f.claims, PublicKey: f.signer.Public().(ed25519.PublicKey), Bucket: "bucket"} roster := hostactors.Roster{V: 1, Revision: 1, DeploymentBucket: "bucket", Boxes: map[string]hostactors.Box{"box-2": {Enrollment: en, BoxID: "box-2", Label: "box-2", Namespace: "platform", Region: "uk", Pool: "default", State: "active", Cloud: hostactors.Cloud{Provider: "aws", Account: "123", Region: "eu-west-2", InstanceID: "i-target"}, EvidenceSHA256: strings.Repeat("d", 64), CensusPublicKey: key.Public().(ed25519.PublicKey)}}, Consoles: map[string]hostactors.Console{}, Holds: map[string]hostactors.Reservation{}, Activations: map[string]hostactors.Reservation{}} wire, _ := release.SignRootEnvelope(release.RootSigner(f.signer), roster) if _, err := f.claims.Put(t.Context(), hostactors.Key, wire, ""); err != nil { t.Fatal(err) } r := StopReceipt{V: 1, ID: "stop", Kind: "stopped", Host: o.Host, Incarnation: o.Claim.Holder.Incarnation, InstallationStamp: 2, WriterSession: 2, OperationID: "m1", Phase: "releasing", ObligationID: "writer-session-2", Box: "box-2", Region: "uk", Enrollment: en, EvidenceAt: time.Now(), RequestLimitNS: int64(2 * time.Minute), ClaimGen: 1, FenceID: "fence", InventorySHA256: strings.Repeat("e", 64), LocalJournalSHA256: strings.Repeat("f", 64), ProducerDrainDigest: strings.Repeat("a", 64), CgroupIdentities: []string{"root-role"}} switch bad { case "session": r.WriterSession++ case "stamp": r.InstallationStamp++ case "enrollment": r.Enrollment = strings.Repeat("e", 32) case "operation": r.OperationID = "other" case "region": r.Region = "ie" } body, _ := json.Marshal(r) receiptKey := stopEvidenceKey(o.Host, "m1", "box-2", "stop") sum := sha256.Sum256(body) signer := key if bad == "signature" { signer = f.signer } if err := hostevidence.Publish(t.Context(), f.claims, signer, receiptKey, body); err != nil { t.Fatal(err) } h.Directory = d o.Claim.Op.Journal["target_stop_receipt"] = receiptKey o.Claim.Op.Journal["target_stop_sha256"] = hex.EncodeToString(sum[:]) o.Claim.Op.Journal[hostclaim.JournalTargetStamp] = "2" // Remove the unsigned report path: the receipt alone must suffice. delete(o.Claim.Op.Journal, hostclaim.JournalEvidenceTarget) if bad == "digest" { o.Claim.Op.Journal["target_stop_sha256"] = strings.Repeat("0", 64) } err := h.recoveryEvidence(t.Context(), o) if (err == nil) != (bad == "") { t.Fatal(bad, err) } }) } }