package main import ( "bytes" "encoding/json" "io" ) // exactFields 验证精确字段集合;原文重复键、大小写别名和尾随JSON均拒绝。 func exactFields(raw json.RawMessage, names ...string) (map[string]json.RawMessage, bool) { decoder := json.NewDecoder(bytes.NewReader(raw)) token, err := decoder.Token() if err != nil || token != json.Delim('{') { return nil, false } fields := make(map[string]json.RawMessage, len(names)) for decoder.More() { token, err = decoder.Token() if err != nil { return nil, false } key, ok := token.(string) if !ok { return nil, false } allowed := false for _, name := range names { allowed = allowed || name == key } if !allowed { return nil, false } if _, exists := fields[key]; exists { return nil, false } var value json.RawMessage if decoder.Decode(&value) != nil || bytes.Equal(bytes.TrimSpace(value), []byte("null")) { return nil, false } fields[key] = value } if _, err = decoder.Token(); err != nil { return nil, false } var tail any return fields, len(fields) == len(names) && decoder.Decode(&tail) == io.EOF } func decodePayload(raw json.RawMessage) (workflowPayload, bool) { fields, ok := exactFields(raw, "run_id", "sequence") var out workflowPayload if !ok || json.Unmarshal(fields["run_id"], &out.RunID) != nil || json.Unmarshal(fields["sequence"], &out.Sequence) != nil { return out, false } return out, true } func matchesOutput(raw json.RawMessage, runID string, sequence int) bool { fields, ok := exactFields(raw, "left", "right") if !ok { return false } left, ok := decodePayload(fields["left"]) right, ok2 := decodePayload(fields["right"]) return ok && ok2 && left == (workflowPayload{RunID: runID, Sequence: sequence}) && right == left }