Skip to main content

cc_lb_plugin_wire/
limits.rs

1//! Guardrail constants for WASM plugin handshake protocol.
2//!
3//! This module centralizes all numeric and structural limits to prevent drift
4//! between host and guest implementations. All constants are compile-time only;
5//! runtime overrides are not supported.
6
7// Custom section
8pub const CUSTOM_SECTION_MAX_SIZE: usize = 64 * 1024;
9pub const CUSTOM_SECTION_FIELD_COUNT: usize = 4;
10
11// Handshake
12pub const HANDSHAKE_WALL_MS: u64 = 200;
13pub const HANDSHAKE_FUEL: u64 = 10_000_000;
14pub const HANDSHAKE_OUTPUT_MAX_BYTES: usize = 32 * 1024;
15
16// Self-check
17pub const SELF_CHECK_WALL_MS: u64 = 200;
18pub const SELF_CHECK_FUEL: u64 = 10_000_000;
19pub const SELF_CHECK_OUTPUT_MAX_BYTES: usize = 8 * 1024;
20
21// Function/capability counts
22pub const FUNCTION_VERSIONS_KEYS_MAX: usize = 32;
23pub const FUNCTION_VERSIONS_PER_FN_MAX: usize = 16;
24pub const CAPABILITIES_MAX_COUNT: usize = 32;
25pub const CAPABILITY_NAME_MAX_BYTES: usize = 64;
26pub const IMPLEMENTED_FUNCTIONS_MAX: usize = 16;
27
28// Plugin metadata
29pub const PLUGIN_NAME_MAX_BYTES: usize = 64;
30pub const PLUGIN_VERSION_MAX_BYTES: usize = 32;
31
32// Versions
33pub const VERSION_MIN: u32 = 1;
34pub const VERSION_MAX: u32 = u16::MAX as u32;
35
36// Augmented metadata
37pub const AUGMENTED_METADATA_MAX_BYTES: usize = 256 * 1024;
38
39// Registry
40pub const REGISTRY_ROW_COUNT_SOFT_WARN: usize = 1_000;
41pub const REGISTRY_ROW_COUNT_HARD_REJECT: usize = 10_000;
42
43// Startup re-handshake
44pub const STARTUP_HANDSHAKE_TOTAL_BUDGET_MS: u64 = 60_000;
45pub const STARTUP_HANDSHAKE_PARALLEL_MAX: usize = 8;
46pub const SKIP_HANDSHAKE_IF_FRESH_TTL_SECS: u64 = 7 * 24 * 3600;
47
48// Regex patterns (compile-time strings)
49pub const PLUGIN_NAME_PATTERN: &str = r"^[a-z][a-z0-9_-]*$";
50pub const CAPABILITY_PATTERN: &str = r"^[a-z][a-z0-9_]*(?::[a-z][a-z0-9_]*)*$";
51
52#[cfg(test)]
53#[allow(clippy::assertions_on_constants)]
54mod tests {
55    use super::*;
56
57    #[test]
58    fn version_bounds_make_sense() {
59        assert!(VERSION_MIN < VERSION_MAX);
60        assert_eq!(VERSION_MIN, 1);
61        assert_eq!(VERSION_MAX, u16::MAX as u32);
62    }
63
64    #[test]
65    fn handshake_bounds_sensible() {
66        assert!(HANDSHAKE_WALL_MS > 0);
67        assert!(HANDSHAKE_FUEL > 0);
68        assert!(HANDSHAKE_OUTPUT_MAX_BYTES > 0);
69        assert!(HANDSHAKE_OUTPUT_MAX_BYTES < CUSTOM_SECTION_MAX_SIZE);
70    }
71
72    #[test]
73    fn self_check_bounds_sensible() {
74        assert!(SELF_CHECK_WALL_MS > 0);
75        assert!(SELF_CHECK_FUEL > 0);
76        assert!(SELF_CHECK_OUTPUT_MAX_BYTES > 0);
77        assert!(SELF_CHECK_OUTPUT_MAX_BYTES < HANDSHAKE_OUTPUT_MAX_BYTES);
78    }
79
80    #[test]
81    fn function_counts_consistent() {
82        assert!(FUNCTION_VERSIONS_KEYS_MAX > 0);
83        assert!(FUNCTION_VERSIONS_PER_FN_MAX > 0);
84        assert!(IMPLEMENTED_FUNCTIONS_MAX <= FUNCTION_VERSIONS_KEYS_MAX);
85    }
86
87    #[test]
88    fn capability_counts_sensible() {
89        assert!(CAPABILITIES_MAX_COUNT > 0);
90        assert!(CAPABILITY_NAME_MAX_BYTES > 0);
91    }
92
93    #[test]
94    fn metadata_size_bounds_sensible() {
95        assert!(PLUGIN_NAME_MAX_BYTES > 0);
96        assert!(PLUGIN_VERSION_MAX_BYTES > 0);
97        assert!(AUGMENTED_METADATA_MAX_BYTES > CUSTOM_SECTION_MAX_SIZE);
98    }
99
100    #[test]
101    fn custom_section_field_count_matches_identity() {
102        // PluginIdentity has: magic, abi_envelope, plugin_name, plugin_version = 4 fields
103        assert_eq!(CUSTOM_SECTION_FIELD_COUNT, 4);
104    }
105
106    #[test]
107    fn registry_rejection_above_warning() {
108        assert!(REGISTRY_ROW_COUNT_SOFT_WARN < REGISTRY_ROW_COUNT_HARD_REJECT);
109    }
110
111    #[test]
112    fn startup_budget_reasonable() {
113        assert!(STARTUP_HANDSHAKE_TOTAL_BUDGET_MS >= 60_000);
114        assert!(STARTUP_HANDSHAKE_PARALLEL_MAX > 0);
115        assert!(STARTUP_HANDSHAKE_PARALLEL_MAX <= 16);
116    }
117
118    #[test]
119    fn ttl_is_one_week() {
120        assert_eq!(SKIP_HANDSHAKE_IF_FRESH_TTL_SECS, 7 * 24 * 3600);
121    }
122
123    #[test]
124    fn wall_times_equal_across_phases() {
125        // Both handshake and self-check have same timeout window
126        assert_eq!(HANDSHAKE_WALL_MS, SELF_CHECK_WALL_MS);
127    }
128
129    #[test]
130    fn fuel_equal_across_phases() {
131        // Both handshake and self-check have same fuel budget
132        assert_eq!(HANDSHAKE_FUEL, SELF_CHECK_FUEL);
133    }
134}