package firmwareconformance import ( "encoding/json" "strings" "testing" "time" ) func TestEvaluateABRollbackEvidence(t *testing.T) { cloud, device := rollbackFixture() report := Evaluate(cloud, device, time.Date(2026, 8, 25, 2, 0, 0, 0, time.UTC)) if report.Result != "PASS" || report.EvidenceScope != "PROTOCOL_SIMULATION" || report.CloudEventCount != 4 || len(report.Checks) < 10 { t.Fatalf("report=%+v", report) } device.FinalVersion = "3.1.0" report = Evaluate(cloud, device, time.Now()) if report.Result != "FAIL" { t.Fatalf("mismatched rollback version passed: %+v", report) } found := false for _, check := range report.Checks { if check.Code == "VERSION_TRANSITION" && check.Status == "FAIL" { found = true } } if !found { t.Fatal("version mismatch was not identified") } } func TestParseCloudEnvelopeAndStrictDeviceEvidence(t *testing.T) { cloud, device := rollbackFixture() cloudJSON, _ := json.Marshal(map[string]any{"request_id": "request-1", "data": cloud}) parsed, err := ParseCloud(cloudJSON) if err != nil || parsed.ID != cloud.ID { t.Fatalf("parsed cloud=%+v err=%v", parsed, err) } deviceJSON, _ := json.Marshal(device) if _, err := ParseDeviceEvidence(deviceJSON); err != nil { t.Fatalf("valid evidence error=%v", err) } var payload map[string]any _ = json.Unmarshal(deviceJSON, &payload) payload["unexpected_secret"] = "must-not-be-accepted" invalid, _ := json.Marshal(payload) if _, err := ParseDeviceEvidence(invalid); err == nil { t.Fatal("unknown device evidence field was accepted") } } func TestParseReportRejectsUnknownFields(t *testing.T) { t.Parallel() if _, err := ParseReport([]byte(`{"schema_version":"firmware-conformance-report-v1","unknown":true}`)); err == nil { t.Fatal("unknown firmware report field was accepted") } } func rollbackFixture() (CloudRollout, DeviceEvidence) { base := time.Date(2026, 8, 25, 1, 0, 0, 0, time.UTC) deviceID := "10000000-0000-0000-0000-000000000511" releaseID := "20000000-0000-0000-0000-000000000001" commandID := "30000000-0000-0000-0000-000000000001" bootAttemptID := "boot-attempt-1" phases := []string{"staging", "reboot_pending", "boot_verifying", "rolled_back"} cloudEvents := make([]CloudEvent, 0, len(phases)) deviceEvents := make([]DeviceEvent, 0, len(phases)) for index, phase := range phases { commandStatus, assignmentStatus := "ACKNOWLEDGED", "INSTALLING" if phase == "rolled_back" { commandStatus, assignmentStatus = "FAILED", "FAILED" } reported := base.Add(time.Duration(index) * time.Minute) event := CloudEvent{ ID: "40000000-0000-0000-0000-00000000000" + string(rune('1'+index)), CommandID: commandID, CommandStatus: commandStatus, AssignmentStatus: assignmentStatus, Phase: phase, ResultDigest: strings.Repeat(string(rune('a'+index)), 64), ReportedAt: reported, BootAttemptID: bootAttemptID, } if phase == "staging" { event.ActiveSlot, event.TargetSlot = "A", "B" event.VerifiedSHA256, event.VerifiedSigningKeyID = strings.Repeat("d", 64), "sim-key" } if phase == "rolled_back" { rollbackApplied := true event.RollbackApplied = &rollbackApplied event.RollbackVersion = "0.2.0-sim" event.ActiveSlot, event.FailedSlot = "A", "B" } cloudEvents = append(cloudEvents, event) deviceEvents = append(deviceEvents, DeviceEvent{Phase: phase, OccurredAt: reported.Add(-2 * time.Second), ActiveSlot: event.ActiveSlot, TargetSlot: event.TargetSlot, BootAttemptID: bootAttemptID}) } cloud := CloudRollout{ ID: "50000000-0000-0000-0000-000000000001", ReleaseID: releaseID, Status: "PAUSED", Assignments: []CloudAssignment{{DeviceID: deviceID, DeviceModel: "simulated-terminal", PreviousVersion: "0.2.0-sim", Status: "FAILED", Events: cloudEvents}}, } device := DeviceEvidence{ SchemaVersion: DeviceEvidenceSchema, EvidenceSource: "SIMULATOR", CandidateVersion: "candidate-1", BuildDigest: "sha256:" + strings.Repeat("b", 64), DeviceID: deviceID, DeviceModel: "simulated-terminal", HardwareRevision: "sim-rev-a", ReleaseID: releaseID, CommandID: commandID, Scenario: "AB_ROLLBACK", BootloaderVersion: "sim-boot-1", PartitionTableSHA256: strings.Repeat("c", 64), SecureBootEnabled: false, ArtifactSHA256: strings.Repeat("d", 64), SigningKeyID: "sim-key", InitialSlot: "A", TargetSlot: "B", FinalSlot: "A", InitialVersion: "0.2.0-sim", TargetVersion: "3.1.0", FinalVersion: "0.2.0-sim", BootAttemptID: bootAttemptID, CollectedAt: base.Add(10 * time.Minute), Events: deviceEvents, } return cloud, device }