@@ -33,6 +33,30 @@ async fn native_wasm_access_decision_denies_before_upstream() {
3333 assert ! ( response. ends_with( "wasm access denied\n " ) ) ;
3434}
3535
36+ #[ tokio:: test]
37+ async fn native_wasm_irules_policy_example_allows_public_and_denies_admin ( ) {
38+ let fixture =
39+ WasmRouteFixture :: new ( & [ ( "irules_policy" , WasmPluginBody :: IrulesAccessPolicyExample ) ] ) ;
40+ let upstream = super :: upstream_expect_path ( "/public" , "public origin" ) . await ;
41+ let mut config = fixture. config_with_attachments (
42+ upstream,
43+ vec ! [ wasm_attachment( "irules_policy" , "admin" , 100 ) ] ,
44+ ) ;
45+ config. vhosts [ 0 ] . routes [ 0 ] . name = "admin" . to_owned ( ) ;
46+ config. vhosts [ 0 ] . routes [ 0 ] . path_exact = Some ( "/admin" . to_owned ( ) ) ;
47+ let router =
48+ NativeHttp1HostRouter :: from_config ( & config, DownstreamHttp1Policy :: default ( ) , 0 ) . unwrap ( ) ;
49+ let proxy = router_listener ( router) . await ;
50+
51+ let allowed = downstream_get ( proxy, "/public" ) . await ;
52+ assert ! ( allowed. starts_with( "HTTP/1.1 200 OK\r \n " ) ) ;
53+ assert ! ( allowed. ends_with( "public origin" ) ) ;
54+
55+ let denied = downstream_get ( proxy, "/admin" ) . await ;
56+ assert ! ( denied. starts_with( "HTTP/1.1 403 Forbidden\r \n " ) ) ;
57+ assert ! ( denied. ends_with( "wasm access denied\n " ) ) ;
58+ }
59+
3660#[ tokio:: test]
3761async fn native_wasm_access_decision_uses_first_deny_in_priority_order ( ) {
3862 let fixture = WasmRouteFixture :: new ( & [
@@ -1875,6 +1899,7 @@ impl WasmRouteFixture {
18751899#[ derive( Clone , Copy ) ]
18761900enum WasmPluginBody {
18771901 Decision ( i32 ) ,
1902+ IrulesAccessPolicyExample ,
18781903 HeaderPolicy ,
18791904 ForbiddenHeader ,
18801905 RouteDecision ,
@@ -1897,8 +1922,11 @@ enum WasmPluginBody {
18971922 Trap ,
18981923 #[ cfg( feature = "wasm-proxy-abi" ) ]
18991924 ProxyPreviewLogCall ,
1925+ #[ cfg( feature = "wasm-wasi" ) ]
19001926 WasiRandomGranted ,
1927+ #[ cfg( feature = "wasm-wasi" ) ]
19011928 WasiRandomDenied ,
1929+ #[ cfg( feature = "wasm-wasi" ) ]
19021930 WasiForbiddenFdWrite ,
19031931 BusyLoop ,
19041932}
@@ -1911,6 +1939,9 @@ impl WasmPluginBody {
19111939 r#"(module (func (export "fluxheim_access_decision") (result i32) i32.const {decision}))"#
19121940 )
19131941 }
1942+ Self :: IrulesAccessPolicyExample => {
1943+ include_str ! ( "../../../../examples/wasm/irules-access-policy.wat" ) . to_owned ( )
1944+ }
19141945 Self :: HeaderPolicy => {
19151946 r#"
19161947 (module
@@ -2203,6 +2234,7 @@ impl WasmPluginBody {
22032234 "#
22042235 . to_owned ( )
22052236 }
2237+ #[ cfg( feature = "wasm-wasi" ) ]
22062238 Self :: WasiRandomGranted | Self :: WasiRandomDenied => {
22072239 r#"
22082240 (module
@@ -2216,6 +2248,7 @@ impl WasmPluginBody {
22162248 "#
22172249 . to_owned ( )
22182250 }
2251+ #[ cfg( feature = "wasm-wasi" ) ]
22192252 Self :: WasiForbiddenFdWrite => {
22202253 r#"
22212254 (module
@@ -2264,12 +2297,15 @@ fn wasm_plugin(root: &Path, name: &str, body: WasmPluginBody) -> fluxheim_config
22642297 let proxy_preview = matches ! ( body, WasmPluginBody :: ProxyPreviewLogCall ) ;
22652298 #[ cfg( not( feature = "wasm-proxy-abi" ) ) ]
22662299 let proxy_preview = false ;
2300+ #[ cfg( feature = "wasm-wasi" ) ]
22672301 let wasi_preview = matches ! (
22682302 body,
22692303 WasmPluginBody :: WasiRandomGranted
22702304 | WasmPluginBody :: WasiRandomDenied
22712305 | WasmPluginBody :: WasiForbiddenFdWrite
22722306 ) ;
2307+ #[ cfg( not( feature = "wasm-wasi" ) ) ]
2308+ let wasi_preview = false ;
22732309 fluxheim_config:: WasmPluginConfig {
22742310 name : name. to_owned ( ) ,
22752311 path,
@@ -2289,11 +2325,29 @@ fn wasm_plugin(root: &Path, name: &str, body: WasmPluginBody) -> fluxheim_config
22892325 fluxheim_config:: WasmHostCallNamespace :: FluxheimPolicyV1
22902326 } ,
22912327 wasi : fluxheim_config:: WasmWasiCapabilitiesConfig {
2292- clocks : matches ! ( body, WasmPluginBody :: WasiForbiddenFdWrite ) ,
2293- randomness : matches ! (
2294- body,
2295- WasmPluginBody :: WasiRandomGranted | WasmPluginBody :: WasiForbiddenFdWrite
2296- ) ,
2328+ clocks : {
2329+ #[ cfg( feature = "wasm-wasi" ) ]
2330+ {
2331+ matches ! ( body, WasmPluginBody :: WasiForbiddenFdWrite )
2332+ }
2333+ #[ cfg( not( feature = "wasm-wasi" ) ) ]
2334+ {
2335+ false
2336+ }
2337+ } ,
2338+ randomness : {
2339+ #[ cfg( feature = "wasm-wasi" ) ]
2340+ {
2341+ matches ! (
2342+ body,
2343+ WasmPluginBody :: WasiRandomGranted | WasmPluginBody :: WasiForbiddenFdWrite
2344+ )
2345+ }
2346+ #[ cfg( not( feature = "wasm-wasi" ) ) ]
2347+ {
2348+ false
2349+ }
2350+ } ,
22972351 } ,
22982352 phases : wasm_plugin_phases ( body) ,
22992353 fail_mode : fluxheim_config:: WasmPluginFailMode :: FailClosed ,
@@ -2337,11 +2391,15 @@ fn wasm_plugin_phases(body: WasmPluginBody) -> Vec<fluxheim_config::WasmPluginPh
23372391 vec ! [ fluxheim_config:: WasmPluginPhase :: CacheStore ]
23382392 }
23392393 WasmPluginBody :: Decision ( _)
2394+ | WasmPluginBody :: IrulesAccessPolicyExample
23402395 | WasmPluginBody :: Trap
2341- | WasmPluginBody :: WasiRandomGranted
2342- | WasmPluginBody :: WasiRandomDenied
2343- | WasmPluginBody :: WasiForbiddenFdWrite
23442396 | WasmPluginBody :: BusyLoop => vec ! [ fluxheim_config:: WasmPluginPhase :: AccessDecision ] ,
2397+ #[ cfg( feature = "wasm-wasi" ) ]
2398+ WasmPluginBody :: WasiRandomGranted
2399+ | WasmPluginBody :: WasiRandomDenied
2400+ | WasmPluginBody :: WasiForbiddenFdWrite => {
2401+ vec ! [ fluxheim_config:: WasmPluginPhase :: AccessDecision ]
2402+ }
23452403 #[ cfg( feature = "wasm-proxy-abi" ) ]
23462404 WasmPluginBody :: ProxyPreviewLogCall => {
23472405 vec ! [ fluxheim_config:: WasmPluginPhase :: AccessDecision ]
0 commit comments