asupersync 0.3.4

Spec-first, cancel-correct, capability-secure async runtime for Rust.
Documentation
//! OTLP-Trace exporter trace_state vendor escaping audit.
//!
//! **Audit Question**: When serializing spans with trace_state values containing special
//! characters (commas, equals, semicolons), does our W3C trace context implementation
//! correctly escape these per the specification or treat them as opaque strings?
//!
//! **W3C Specification**: Per W3C trace-context spec, trace_state values may contain
//! special characters that must be properly escaped during serialization to prevent
//! parsing ambiguity. Characters like commas (,), equals (=), and semicolons (;) have
//! syntactic meaning and require escaping in values.
//!
//! **Expected Behavior**: Values containing special characters should be escaped during
//! serialization and unescaped during parsing to ensure round-trip fidelity.

#[cfg(test)]
mod tests {
    use std::collections::HashMap;

    /// Trace context fixture for testing special character escaping.
    #[derive(Debug, Clone, PartialEq)]
    pub struct TestTraceContext {
        pub trace_id: String,
        pub span_id: String,
        pub parent_span_id: Option<String>,
        pub flags: u8,
        pub tracestate: Option<String>,
    }

    impl TestTraceContext {
        pub fn new() -> Self {
            Self {
                trace_id: "4bf92f3577b34da6a3ce929d0e0e4736".to_string(),
                span_id: "00f067aa0ba902b7".to_string(),
                parent_span_id: None,
                flags: 0x01, // sampled
                tracestate: None,
            }
        }

        pub fn with_tracestate(mut self, tracestate: &str) -> Self {
            self.tracestate = Some(tracestate.to_string());
            self
        }

        pub fn to_headers(&self) -> HashMap<String, String> {
            let mut headers = HashMap::new();
            headers.insert(
                "traceparent".to_string(),
                format!("00-{}-{}-{:02x}", self.trace_id, self.span_id, self.flags),
            );
            if let Some(ref tracestate) = self.tracestate {
                headers.insert("tracestate".to_string(), tracestate.clone());
            }
            headers
        }
    }

    /// Current W3C trace context implementation (from w3c_trace_context.rs).
    ///
    /// **POTENTIAL DEFECT**: Treats tracestate as opaque string without escaping.
    fn current_w3c_extract_tracestate(headers: &HashMap<String, String>) -> Option<String> {
        // This simulates the current implementation from w3c_trace_context.rs lines 284-288
        headers.get("tracestate").cloned()
    }

    /// Current W3C trace context injection (from w3c_trace_context.rs).
    ///
    /// **POTENTIAL DEFECT**: Directly injects tracestate without escaping validation.
    fn current_w3c_inject_tracestate(tracestate: &str, headers: &mut HashMap<String, String>) {
        // This simulates the current implementation from w3c_trace_context.rs lines 297-299
        headers.insert("tracestate".to_string(), tracestate.to_string());
    }

    /// Hypothetical W3C-compliant tracestate parser with proper escaping.
    ///
    /// **CORRECT**: Would parse and escape special characters per W3C spec.
    #[allow(dead_code)]
    fn w3c_compliant_parse_tracestate(tracestate: &str) -> Vec<(String, String)> {
        // This is what a proper implementation might look like
        let mut entries = Vec::new();
        let parts: Vec<&str> = tracestate.split(',').collect();

        for part in parts {
            if let Some((key, value)) = part.split_once('=') {
                // In a real implementation, this would:
                // 1. Validate key format (vendor identifier rules)
                // 2. Unescape special characters in value
                // 3. Handle quoted values if specified by W3C
                entries.push((key.to_string(), value.to_string()));
            }
        }
        entries
    }

    /// Hypothetical W3C-compliant tracestate serializer with proper escaping.
    ///
    /// **CORRECT**: Would escape special characters in values per W3C spec.
    #[allow(dead_code)]
    fn w3c_compliant_serialize_tracestate(entries: &[(String, String)]) -> String {
        entries
            .iter()
            .map(|(key, value)| {
                // In a real implementation, this would:
                // 1. Escape commas, equals, semicolons in value
                // 2. Apply quoting if needed per W3C spec
                // 3. Validate key format
                format!("{}={}", key, value) // Simplified - real version would escape
            })
            .collect::<Vec<_>>()
            .join(",")
    }

    #[test]
    fn otlp_trace_state_escaping_audit() {
        eprintln!("\n🔍 OTLP TRACE_STATE VENDOR ESCAPING AUDIT");
        eprintln!("========================================");

        eprintln!("\n📋 W3C Trace-Context Specification:");
        eprintln!("  â€ĸ trace_state format: vendor1=value1,vendor2=value2,...");
        eprintln!("  â€ĸ Special characters in values may need escaping");
        eprintln!("  â€ĸ Commas (,) separate vendor entries");
        eprintln!("  â€ĸ Equals (=) separates vendor keys from values");
        eprintln!("  â€ĸ Semicolons (;) may have special meaning in some vendor values");
        eprintln!("  â€ĸ Values containing these characters require proper escaping");

        // Test cases with special characters in tracestate values
        let test_cases = vec![
            (
                "simple_value",
                "vendor=simple_value",
                "vendor=simple_value",
                true,
                "No special characters - should work"
            ),
            (
                "value_with_commas",
                "vendor=val,with,commas",
                "vendor=val,with,commas",
                false, // POTENTIAL ISSUE: Commas may be interpreted as separators
                "Value contains commas - may confuse parser"
            ),
            (
                "value_with_equals",
                "vendor=val=with=equals",
                "vendor=val=with=equals",
                false, // POTENTIAL ISSUE: Additional equals may confuse parser
                "Value contains equals - may confuse key=value parsing"
            ),
            (
                "value_with_semicolons",
                "vendor=val;with;semicolons",
                "vendor=val;with;semicolons",
                false, // POTENTIAL ISSUE: Semicolons may have vendor-specific meaning
                "Value contains semicolons - may have vendor-specific meaning"
            ),
            (
                "multiple_vendors_clean",
                "vendor1=clean1,vendor2=clean2",
                "vendor1=clean1,vendor2=clean2",
                true,
                "Multiple vendors with clean values"
            ),
            (
                "multiple_vendors_with_commas",
                "vendor1=val,with,commas,vendor2=clean",
                "vendor1=val,with,commas,vendor2=clean",
                false, // CRITICAL ISSUE: Parser may split incorrectly
                "Multiple vendors where first value contains commas"
            ),
        ];

        eprintln!("\n📊 Testing tracestate round-trip with special characters:");

        for (test_name, input_tracestate, expected_output, should_work_correctly, description) in test_cases {
            eprintln!("\n  📋 Test: {}", test_name);
            eprintln!("    Input:  '{}'", input_tracestate);
            eprintln!("    Expect: '{}'", expected_output);
            eprintln!("    Description: {}", description);

            // Simulate HTTP request with tracestate
            let context = TestTraceContext::new()
                .with_tracestate(input_tracestate);
            let headers = context.to_headers();

            // Test current implementation extraction
            let extracted_tracestate = current_w3c_extract_tracestate(&headers);
            eprintln!("    Current extraction: {:?}", extracted_tracestate);

            // Test round-trip through injection
            if let Some(tracestate) = extracted_tracestate {
                let mut injected_headers = HashMap::new();
                current_w3c_inject_tracestate(&tracestate, &mut injected_headers);
                let round_trip_result = injected_headers.get("tracestate");
                eprintln!("    Round-trip result: {:?}", round_trip_result);

                // Verify round-trip fidelity
                let round_trip_matches = round_trip_result == Some(&expected_output.to_string());
                eprintln!("    Round-trip match: {} {}",
                    round_trip_matches,
                    if should_work_correctly && round_trip_matches { "✅ EXPECTED" }
                    else if !should_work_correctly && round_trip_matches { "âš ī¸ POTENTIAL ISSUE" }
                    else { "❌ UNEXPECTED" }
                );

                if !should_work_correctly && round_trip_matches {
                    eprintln!("      âš ī¸  Current implementation treats as opaque string");
                    eprintln!("      âš ī¸  May cause parsing issues with W3C-compliant receivers");
                }
            }
        }

        eprintln!("\n🔍 CURRENT IMPLEMENTATION ANALYSIS:");
        eprintln!("===================================");
        eprintln!("✅ OPAQUE STRING HANDLING:");
        eprintln!("   â€ĸ Current implementation treats tracestate as opaque string");
        eprintln!("   â€ĸ Direct clone from extraction to injection");
        eprintln!("   â€ĸ No parsing or escaping of special characters");
        eprintln!("   â€ĸ Round-trip fidelity preserved for string content");

        eprintln!("\nâš ī¸  POTENTIAL W3C COMPLIANCE ISSUES:");
        eprintln!("   â€ĸ Values containing commas may confuse downstream parsers");
        eprintln!("   â€ĸ Additional equals signs may break key=value parsing");
        eprintln!("   â€ĸ No validation of W3C tracestate format rules");
        eprintln!("   â€ĸ No escaping mechanism for special characters");

        eprintln!("\nđŸŽ¯ RISK ASSESSMENT:");
        eprintln!("   LOW IMPACT: Opaque string handling preserves data");
        eprintln!("   MEDIUM RISK: May cause interoperability issues");
        eprintln!("   RECOMMENDATION: Monitor for downstream parsing failures");
    }

    #[test]
    fn w3c_tracestate_format_specification_analysis() {
        eprintln!("\n📖 W3C TRACESTATE FORMAT SPECIFICATION ANALYSIS");
        eprintln!("================================================");

        eprintln!("📋 W3C Trace-Context Specification Requirements:");
        eprintln!("   â€ĸ Format: vendor-key1=value1,vendor-key2=value2");
        eprintln!("   â€ĸ Keys: Must follow vendor identifier format");
        eprintln!("   â€ĸ Values: May contain arbitrary data (with escaping rules)");
        eprintln!("   â€ĸ Separators: Commas separate entries, equals separate key=value");
        eprintln!("   â€ĸ Escaping: Special characters in values should be escaped");

        eprintln!("\n🔍 Current Implementation Behavior:");
        let problematic_tracestate = "vendor1=value,with,commas,vendor2=normal";
        eprintln!("   Input: '{}'", problematic_tracestate);

        // Simulate current behavior
        let headers = TestTraceContext::new()
            .with_tracestate(problematic_tracestate)
            .to_headers();

        let extracted = current_w3c_extract_tracestate(&headers);
        eprintln!("   Current extraction: {:?}", extracted);

        eprintln!("\n📊 Parsing Ambiguity Analysis:");
        eprintln!("   A W3C-compliant parser might interpret:");
        eprintln!("   â€ĸ 'vendor1=value' (first entry)");
        eprintln!("   â€ĸ 'with' (malformed - no equals)");
        eprintln!("   â€ĸ 'commas' (malformed - no equals)");
        eprintln!("   â€ĸ 'vendor2=normal' (second entry)");
        eprintln!("   → This would result in parsing errors or data loss");

        eprintln!("\n💡 W3C-Compliant Solution Would:");
        eprintln!("   â€ĸ Escape commas in values: vendor1=value%2Cwith%2Ccommas");
        eprintln!("   â€ĸ Or use quoted values: vendor1=\"value,with,commas\"");
        eprintln!("   â€ĸ Parse and validate during extraction");
        eprintln!("   â€ĸ Serialize with proper escaping during injection");

        eprintln!("\nâš–ī¸  Trade-off Analysis:");
        eprintln!("   CURRENT (opaque string):");
        eprintln!("     ✅ Simple implementation");
        eprintln!("     ✅ Preserves arbitrary data");
        eprintln!("     ❌ May break W3C-compliant parsers");
        eprintln!("   ");
        eprintln!("   W3C-COMPLIANT (parsed + escaped):");
        eprintln!("     ✅ Interoperable with all W3C implementations");
        eprintln!("     ✅ Prevents parsing ambiguity");
        eprintln!("     ❌ More complex implementation");
        eprintln!("     ❌ Risk of escaping/unescaping bugs");
    }

    #[test]
    fn demonstrate_current_opaque_string_behavior() {
        eprintln!("\n✅ DEMONSTRATING CURRENT OPAQUE STRING BEHAVIOR");
        eprintln!("===============================================");

        // Test with various problematic inputs that should demonstrate the current behavior
        let test_inputs = vec![
            "simple=value",
            "complex=value,with,commas",
            "equals=value=with=equals",
            "semicolon=value;with;semicolons",
            "mixed=value,with=mixed;separators",
            "vendor1=clean,vendor2=value,with,embedded,commas,vendor3=clean",
        ];

        eprintln!("Current implementation behavior with special characters:");

        for input in test_inputs {
            let headers = TestTraceContext::new()
                .with_tracestate(input)
                .to_headers();

            let extracted = current_w3c_extract_tracestate(&headers);
            let mut round_trip_headers = HashMap::new();

            if let Some(tracestate) = extracted {
                current_w3c_inject_tracestate(&tracestate, &mut round_trip_headers);
                let result = round_trip_headers.get("tracestate");

                let preserved = result == Some(&input.to_string());
                eprintln!("  '{}' → {} {}",
                    input,
                    if preserved { "PRESERVED" } else { "MODIFIED" },
                    if preserved { "✅" } else { "❌" }
                );
            }
        }

        eprintln!("\nđŸŽ¯ CURRENT BEHAVIOR ASSESSMENT:");
        eprintln!("  ✅ SOUND for opaque string preservation");
        eprintln!("  ✅ No data loss during round-trip");
        eprintln!("  âš ī¸  May cause interoperability issues with strict W3C parsers");
        eprintln!("  â„šī¸  Acceptable if downstream systems handle tracestate as opaque");
    }

    /// Test edge cases for tracestate handling.
    #[test]
    fn tracestate_edge_cases() {
        eprintln!("\nđŸ”Ŧ TRACESTATE EDGE CASES");
        eprintln!("=======================");

        let edge_cases = vec![
            ("", "Empty tracestate"),
            ("=value", "Missing vendor key"),
            ("vendor=", "Empty value"),
            ("vendor", "Missing equals separator"),
            ("vendor=value=", "Trailing equals"),
            (",vendor=value", "Leading comma"),
            ("vendor=value,", "Trailing comma"),
            ("vendor=value,,vendor2=value2", "Double comma"),
            ("vendor===value", "Triple equals"),
            ("vendor=value===", "Multiple trailing equals"),
        ];

        eprintln!("Testing edge cases with current opaque string implementation:");

        for (input, description) in edge_cases {
            let headers = TestTraceContext::new()
                .with_tracestate(input)
                .to_headers();

            let extracted = current_w3c_extract_tracestate(&headers);
            let preserved = extracted.as_deref() == Some(input);

            eprintln!("  {} → {} ({})",
                description,
                if preserved { "PRESERVED ✅" } else { "MODIFIED ❌" },
                input
            );
        }

        eprintln!("\n💡 Edge Case Handling:");
        eprintln!("  â€ĸ Current implementation preserves all edge cases as-is");
        eprintln!("  â€ĸ No validation or normalization performed");
        eprintln!("  â€ĸ Downstream systems responsible for handling malformed data");
    }
}