@@ -465,12 +465,14 @@ impl AllowedHostsConfig {
465465 pub fn parse < S : AsRef < str > > (
466466 hosts : & [ S ] ,
467467 resolver : & spin_expressions:: PreparedResolver ,
468+ component_ids : & [ String ] ,
468469 ) -> anyhow:: Result < AllowedHostsConfig > {
469470 let partial = Self :: parse_partial ( hosts) ?;
470471 let allowed = partial
471472 . into_iter ( )
472473 . map ( |p| p. resolve ( resolver) )
473474 . collect :: < anyhow:: Result < Vec < _ > > > ( ) ?;
475+ let allowed = Self :: expand_wildcard_service_chaining ( allowed, component_ids) ;
474476 Ok ( Self :: SpecificHosts ( allowed) )
475477 }
476478
@@ -502,6 +504,28 @@ impl AllowedHostsConfig {
502504 Ok ( allowed)
503505 }
504506
507+ fn expand_wildcard_service_chaining (
508+ hosts : Vec < AllowedHostConfig > ,
509+ component_ids : & [ String ] ,
510+ ) -> Vec < AllowedHostConfig > {
511+ let expand_one = |host : AllowedHostConfig | match host. host ( ) {
512+ HostConfig :: AnySubdomain ( domain) if domain == SERVICE_CHAINING_DOMAIN_SUFFIX => {
513+ let expanded_domains = component_ids
514+ . iter ( )
515+ . map ( |c| format ! ( "{c}{SERVICE_CHAINING_DOMAIN_SUFFIX}" ) ) ;
516+ let expanded_hosts = expanded_domains. map ( |d| {
517+ let mut hh = host. clone ( ) ;
518+ hh. host = HostConfig :: Literal ( url:: Host :: Domain ( d) ) ;
519+ hh
520+ } ) ;
521+ expanded_hosts. collect ( )
522+ }
523+ _ => vec ! [ host] ,
524+ } ;
525+
526+ hosts. into_iter ( ) . flat_map ( expand_one) . collect ( )
527+ }
528+
505529 /// Returns true if the given url is allowed.
506530 pub fn allows ( & self , url : & OutboundUrl ) -> bool {
507531 match self {
@@ -901,10 +925,13 @@ mod test {
901925
902926 #[ test]
903927 fn test_allowed_hosts_respects_allow_all ( ) {
904- assert ! ( AllowedHostsConfig :: parse( & [ "insecure:allow-all" ] , & dummy_resolver( ) ) . is_err( ) ) ;
928+ assert ! (
929+ AllowedHostsConfig :: parse( & [ "insecure:allow-all" ] , & dummy_resolver( ) , & [ ] ) . is_err( )
930+ ) ;
905931 assert ! ( AllowedHostsConfig :: parse(
906932 & [ "spin.fermyon.dev" , "insecure:allow-all" ] ,
907- & dummy_resolver( )
933+ & dummy_resolver( ) ,
934+ & [ ]
908935 )
909936 . is_err( ) ) ;
910937 }
@@ -927,6 +954,7 @@ mod test {
927954 let allowed = AllowedHostsConfig :: parse (
928955 & [ "*://spin.fermyon.dev:443" , "http://example.com:8383" ] ,
929956 & dummy_resolver ( ) ,
957+ & [ ] ,
930958 )
931959 . unwrap ( ) ;
932960 assert ! (
@@ -944,7 +972,7 @@ mod test {
944972 #[ test]
945973 fn test_allowed_hosts_with_trailing_slash ( ) {
946974 let allowed =
947- AllowedHostsConfig :: parse ( & [ "https://my.api.com/" ] , & dummy_resolver ( ) ) . unwrap ( ) ;
975+ AllowedHostsConfig :: parse ( & [ "https://my.api.com/" ] , & dummy_resolver ( ) , & [ ] ) . unwrap ( ) ;
948976 assert ! ( allowed. allows( & OutboundUrl :: parse( "https://my.api.com" , "https" ) . unwrap( ) ) ) ;
949977 assert ! ( allowed. allows( & OutboundUrl :: parse( "https://my.api.com/" , "https" ) . unwrap( ) ) ) ;
950978 }
@@ -954,6 +982,7 @@ mod test {
954982 let allowed = AllowedHostsConfig :: parse (
955983 & [ "http://*.example.com" , "http://*.example2.com:8383" ] ,
956984 & dummy_resolver ( ) ,
985+ & [ ] ,
957986 )
958987 . unwrap ( ) ;
959988 assert ! (
@@ -976,7 +1005,8 @@ mod test {
9761005
9771006 #[ test]
9781007 fn test_hash_char_in_db_password ( ) {
979- let allowed = AllowedHostsConfig :: parse ( & [ "mysql://xyz.com" ] , & dummy_resolver ( ) ) . unwrap ( ) ;
1008+ let allowed =
1009+ AllowedHostsConfig :: parse ( & [ "mysql://xyz.com" ] , & dummy_resolver ( ) , & [ ] ) . unwrap ( ) ;
9801010 assert ! (
9811011 allowed
. allows
( & OutboundUrl :: parse
( "mysql://user:pass#[email protected] " , "mysql" ) . unwrap
( ) ) 9821012 ) ;
@@ -988,7 +1018,66 @@ mod test {
9881018 #[ test]
9891019 fn test_cidr ( ) {
9901020 let allowed =
991- AllowedHostsConfig :: parse ( & [ "*://127.0.0.1/24:63551" ] , & dummy_resolver ( ) ) . unwrap ( ) ;
1021+ AllowedHostsConfig :: parse ( & [ "*://127.0.0.1/24:63551" ] , & dummy_resolver ( ) , & [ ] ) . unwrap ( ) ;
9921022 assert ! ( allowed. allows( & OutboundUrl :: parse( "tcp://127.0.0.1:63551" , "tcp" ) . unwrap( ) ) ) ;
9931023 }
1024+
1025+ fn exact_host ( ahc : & AllowedHostConfig ) -> String {
1026+ match ahc. host ( ) {
1027+ HostConfig :: Literal ( host) => host. to_string ( ) ,
1028+ _ => panic ! ( "expected host {:?} to be a literal" , ahc. host( ) ) ,
1029+ }
1030+ }
1031+
1032+ #[ test]
1033+ fn expand_wildcard_service_chaining_lists_all_components ( ) {
1034+ let component_ids = [ "first" , "second" , "third" ]
1035+ . iter ( )
1036+ . map ( |s| s. to_string ( ) )
1037+ . collect :: < Vec < _ > > ( ) ;
1038+ let allowed = AllowedHostsConfig :: parse (
1039+ & [ "http://*.spin.internal" ] ,
1040+ & dummy_resolver ( ) ,
1041+ & component_ids,
1042+ )
1043+ . unwrap ( ) ;
1044+ let AllowedHostsConfig :: SpecificHosts ( allowed) = allowed else {
1045+ panic ! ( "expanded AllowedHostsConfig should be specific hosts" ) ;
1046+ } ;
1047+
1048+ assert_eq ! ( 3 , allowed. len( ) ) ;
1049+
1050+ assert_eq ! ( "first.spin.internal" , exact_host( & allowed[ 0 ] ) ) ;
1051+ assert_eq ! ( "second.spin.internal" , exact_host( & allowed[ 1 ] ) ) ;
1052+ assert_eq ! ( "third.spin.internal" , exact_host( & allowed[ 2 ] ) ) ;
1053+ }
1054+
1055+ #[ test]
1056+ fn expand_wildcard_service_chaining_leaves_others_untouched ( ) {
1057+ let component_ids = [ "first" , "second" , "third" ]
1058+ . iter ( )
1059+ . map ( |s| s. to_string ( ) )
1060+ . collect :: < Vec < _ > > ( ) ;
1061+ let allowed = AllowedHostsConfig :: parse (
1062+ & [
1063+ "pg://localhost:5656" ,
1064+ "http://*.spin.internal" ,
1065+ "https://spinframework.dev" ,
1066+ ] ,
1067+ & dummy_resolver ( ) ,
1068+ & component_ids,
1069+ )
1070+ . unwrap ( ) ;
1071+ let AllowedHostsConfig :: SpecificHosts ( allowed) = allowed else {
1072+ panic ! ( "expanded AllowedHostsConfig should be specific hosts" ) ;
1073+ } ;
1074+
1075+ assert_eq ! ( 5 , allowed. len( ) ) ;
1076+
1077+ assert_eq ! ( "localhost" , exact_host( & allowed[ 0 ] ) ) ;
1078+ assert_eq ! ( "first.spin.internal" , exact_host( & allowed[ 1 ] ) ) ;
1079+ assert_eq ! ( "second.spin.internal" , exact_host( & allowed[ 2 ] ) ) ;
1080+ assert_eq ! ( "third.spin.internal" , exact_host( & allowed[ 3 ] ) ) ;
1081+ assert_eq ! ( "spinframework.dev" , exact_host( & allowed[ 4 ] ) ) ;
1082+ }
9941083}
0 commit comments