package main import ( "crypto/sha256" "encoding/hex" "encoding/json" "fmt" "os" "path/filepath" "strconv" "strings" "unicode/utf8" protocol "git.sechmachine.io.vn/sechmachine/VerseVDI-Protocol/gen/go/protocol" ) func main() { entries, err := os.ReadDir("fixtures/conformance") if err != nil { panic(err) } var results []string for _, entry := range entries { if entry.IsDir() || filepath.Ext(entry.Name()) != ".tsv" { continue } path := filepath.Join("fixtures/conformance", entry.Name()) data, err := os.ReadFile(path) if err != nil { panic(err) } lines := strings.Split(strings.TrimSuffix(string(data), "\n"), "\n") if len(lines) == 0 || lines[0] != "id\tversion\tkind\tinput\texpected" { panic("invalid fixture header") } for _, line := range lines[1:] { fields := strings.Split(line, "\t") if len(fields) != 5 { panic("invalid fixture row") } actual := evaluate(fields[2], fields[3]) if actual != fields[4] { panic(fmt.Sprintf("%s: got %s want %s", fields[0], actual, fields[4])) } results = append(results, fields[0]+"\t"+actual) } } fixtureHash := readFixtureHash() fmt.Printf("Go conformance passed normalized=%s fixtures=%s\n", normalizedDigest(results), fixtureHash) } func evaluate(kind, input string) string { parts := map[string]string{} for _, item := range strings.Split(input, ";") { pair := strings.SplitN(item, "=", 2) if len(pair) == 2 { parts[pair[0]] = pair[1] } } switch kind { case "version": if input == "1" || input == "0" || input == "-1" { return "valid" } return "invalid:unsupported_version" case "page": limit, err := strconv.Atoi(parts["limit"]) value := protocol.PageInfo{Limit: int64(limit), NextCursor: parts["cursor"]} if err == nil && value.Validate() == nil { return "valid" } return "invalid:invalid_limit" case "manifest": forbidden := []string{"provider_url", "vm_address", "password", "private_key"} for _, key := range forbidden { if _, ok := parts[key]; ok { return "invalid:forbidden_field" } } value := protocol.ConnectionManifest{ Version: parts["version"], Purpose: parts["purpose"], SessionID: "session-1", ReconnectSequence: 0, Gateway: protocol.ManifestGateway{ ID: parts["gateway_id"], Addresses: []string{"gateway.control.test:443"}, PublicIdentity: parts["gateway_id"], }, Tunnel: protocol.ManifestTunnel{Versions: []string{parts["protocol"] + "/1"}, Features: []string{"control.v1"}}, Profile: protocol.ManifestProfile{ID: "standard", Bounds: protocol.ManifestBounds{MinimumKbps: 1, TargetKbps: 2, MaximumKbps: 3}}, Grant: protocol.GrantReference{OpaqueValue: parts["grant"], ExpiresAt: parts["expires_at"], Audience: parts["audience"]}, CorrelationID: "correlation-1", } if value.Validate() == nil { return "valid" } return "invalid:invalid_manifest" case "clipboard": _, hasFile := parts["file"] value := protocol.ClipboardText{Text: parts["text"], Encoding: parts["encoding"]} if !hasFile && value.Validate() == nil { return "valid" } return "invalid:unsupported_clipboard" case "event": sequence, sequenceErr := strconv.ParseInt(parts["sequence"], 10, 64) payloadBytes, payloadErr := strconv.Atoi(parts["payload_bytes"]) if parts["version"] != "1" { return "invalid:unsupported_version" } if parts["after"] != "" && parts["earliest"] != "" { after, afterErr := strconv.ParseInt(parts["after"], 10, 64) earliest, earliestErr := strconv.ParseInt(parts["earliest"], 10, 64) if afterErr == nil && earliestErr == nil && after > 0 && earliest > 0 && after < earliest-1 { return "invalid:gap" } } value := protocol.EventEnvelope{ EventID: "event-1", Sequence: sequence, Type: "broker.session.changed", Version: 1, Resource: protocol.ResourceLink{Type: "broker_session", ID: "session-1", Version: 1}, OccurredAt: "2099-01-01T00:00:00Z", CorrelationID: parts["correlation_id"], Payload: map[string]any{}, } if payloadErr != nil || payloadBytes > 16384 { return "invalid:payload_limit" } if sequenceErr != nil || value.Validate() != nil { return "invalid:required" } return "valid" case "tunnel": feature := parts["feature"] registered := feature == "control.v1" || feature == "display.request.v1" || feature == "input.absolute.v1" || feature == "input.scroll.v1" if (parts["offered"] == "1" || parts["offered"] == "0" || parts["offered"] == "-1") && registered { return "valid" } if !registered { return "invalid:unsupported_feature" } return "invalid:unsupported_version" case "datagram": return classifyDatagram(parts["hex"]) case "gateway_input": return classifyGatewayInput(parts["hex"]) case "gateway_feedback": return classifyGatewayFeedback(parts["hex"]) case "gateway_clipboard": if _, hasFile := parts["file"]; hasFile { return "invalid:forbidden" } value := protocol.GatewayClipboardText{Direction: parts["direction"], Text: parts["text"], Encoding: parts["encoding"], LoopToken: parts["loop_token"]} if value.Validate() != nil { return "invalid:clipboard" } return "valid" case "gateway_clipboard_audit": if _, hasText := parts["text"]; hasText { return "invalid:forbidden" } textBytes, err := strconv.ParseInt(parts["text_bytes"], 10, 64) if err != nil { return "invalid:clipboard_audit" } value := protocol.GatewayClipboardAudit{Version: "1", SessionID: "fixture-session", Direction: parts["direction"], Outcome: parts["outcome"], TextBytes: textBytes, Reason: parts["reason"]} if value.Validate() != nil { return "invalid:clipboard_audit" } return "valid" default: return "invalid:unknown_kind" } } func decodeGatewayHex(encoded string) ([]byte, string) { raw, err := hex.DecodeString(encoded) if err != nil { return nil, "invalid:hex" } return raw, "" } func classifyGatewayInput(encoded string) string { raw, invalid := decodeGatewayHex(encoded) if invalid != "" { return invalid } if len(raw) < 6 { return "invalid:truncated" } if string(raw[:4]) != "VGI1" { return "invalid:magic" } kind, length := raw[4], int(raw[5]) if len(raw) != 6+length { return "invalid:length" } body := raw[6:] switch kind { case 1: if len(body) != 4 || body[0] > 1 || (body[2] == 0 && body[3] == 0) { return "invalid:field" } case 2: if len(body) != 3 { return "invalid:length" } if body[0] > 1 || body[1] < 1 || body[1] > 5 { return "invalid:field" } if body[2] != 0 { return "invalid:reserved" } case 3: if len(body) != 4 { return "invalid:length" } case 4: if len(body) < 1 || len(body) > 4 || !utf8.Valid(body) || utf8.RuneCount(body) != 1 { return "invalid:utf8" } case 5: if len(body) != 17 { return "invalid:length" } if body[0] > 15 { return "invalid:field" } if body[1] == 0 && body[2] == 0 { for _, value := range body[3:] { if value != 0 { return "invalid:field" } } } case 6: if len(body) != 8 { return "invalid:length" } x, y := uint16(body[0])<<8|uint16(body[1]), uint16(body[2])<<8|uint16(body[3]) width, height := uint16(body[4])<<8|uint16(body[5]), uint16(body[6])<<8|uint16(body[7]) if width == 0 || height == 0 || x >= width || y >= height { return "invalid:field" } case 7: if len(body) != 4 { return "invalid:length" } default: return "invalid:kind" } return "valid" } func classifyGatewayFeedback(encoded string) string { raw, invalid := decodeGatewayHex(encoded) if invalid != "" { return invalid } if len(raw) < 8 { return "invalid:truncated" } if string(raw[:4]) != "VGF1" { return "invalid:magic" } direction, kind := raw[4], raw[5] if len(raw) != 8+(int(raw[6])<<8)+int(raw[7]) { return "invalid:length" } if direction != 0 && direction != 1 { return "invalid:direction" } body := raw[8:] if direction == 0 { if kind >= 0x10 && kind <= 0x12 { return "invalid:direction" } switch kind { case 1: if len(body) == 0 { return "valid" } case 2: if validFECStatus(body) { return "valid" } return "invalid:field" case 3: if len(body) == 0 { return "valid" } default: return "invalid:type" } return "invalid:length" } if kind == 1 || kind == 2 || kind == 3 { return "invalid:direction" } switch kind { case 0x10: if len(body) == 4 { return "valid" } return "invalid:length" case 0x11: if len(body) != 5 { return "invalid:length" } if body[0] <= 15 { return "valid" } case 0x12: if len(body) != 1 { return "invalid:length" } if body[0] <= 1 { return "valid" } default: return "invalid:type" } return "invalid:field" } func validFECStatus(body []byte) bool { if len(body) != 21 || int(body[10])<<8|int(body[11]) == 0 || int(body[14])<<8|int(body[15]) > int(body[10])<<8|int(body[11]) || int(body[16])<<8|int(body[17]) > int(body[12])<<8|int(body[13]) || body[18] > 100 || body[20] == 0 || body[19] >= body[20] { return false } return true } func classifyDatagram(encoded string) string { raw, err := hex.DecodeString(encoded) if err != nil { return "invalid:hex" } if len(raw) < 3 { return "invalid:truncated" } if string(raw[:2]) != "VD" { return "invalid:magic" } if raw[2] != 1 && raw[2] != 2 { return "invalid:unsupported_version" } headerBytes := 21 limits := map[byte]int{1: 1024, 2: 2048, 3: 65515, 10: 1179, 11: 1179, 12: 1179} if raw[2] == 2 { headerBytes = 23 limits = map[byte]int{10: 1177, 11: 1177} } if len(raw) < headerBytes { return "invalid:truncated" } limit, ok := limits[raw[3]] if !ok { return "invalid:unknown_channel" } if raw[4] != 0 { return "invalid:flags" } fragmentIndex, fragmentCount := int(raw[17]), int(raw[18]) payloadOffset := 19 if raw[2] == 2 { fragmentIndex = int(raw[17])<<8 | int(raw[18]) fragmentCount = int(raw[19])<<8 | int(raw[20]) payloadOffset = 21 if fragmentCount > 891 { return "invalid:fragment_limit" } } if fragmentCount == 0 || fragmentIndex >= fragmentCount { return "invalid:fragment" } payloadLength := int(raw[payloadOffset])<<8 | int(raw[payloadOffset+1]) if payloadLength > limit { return "invalid:payload_limit" } if len(raw) != headerBytes+payloadLength { return "invalid:length_mismatch" } if raw[2] == 1 && len(raw) > 65536 || raw[2] == 2 && len(raw) > 1200 { return "invalid:frame_limit" } return "valid" } func normalizedDigest(results []string) string { const offset = uint64(14695981039346656037) const prime = uint64(1099511628211) value := offset for _, result := range results { for _, byteValue := range []byte(result + "\n") { value ^= uint64(byteValue) value *= prime } } return fmt.Sprintf("%016x", value) } func readFixtureHash() string { data, err := os.ReadFile("fixtures/manifest.json") if err != nil { panic(err) } var manifest struct { CorpusSHA256 string `json:"corpus_sha256"` } if err := json.Unmarshal(data, &manifest); err != nil || len(manifest.CorpusSHA256) != sha256.Size*2 { panic("invalid fixture manifest") } return manifest.CorpusSHA256 }