@@ -465,12 +465,14 @@ impl AllowedHostsConfig {
465
465
pub fn parse < S : AsRef < str > > (
466
466
hosts : & [ S ] ,
467
467
resolver : & spin_expressions:: PreparedResolver ,
468
+ component_ids : & [ String ] ,
468
469
) -> anyhow:: Result < AllowedHostsConfig > {
469
470
let partial = Self :: parse_partial ( hosts) ?;
470
471
let allowed = partial
471
472
. into_iter ( )
472
473
. map ( |p| p. resolve ( resolver) )
473
474
. collect :: < anyhow:: Result < Vec < _ > > > ( ) ?;
475
+ let allowed = Self :: expand_wildcard_service_chaining ( allowed, component_ids) ;
474
476
Ok ( Self :: SpecificHosts ( allowed) )
475
477
}
476
478
@@ -502,6 +504,28 @@ impl AllowedHostsConfig {
502
504
Ok ( allowed)
503
505
}
504
506
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
+
505
529
/// Returns true if the given url is allowed.
506
530
pub fn allows ( & self , url : & OutboundUrl ) -> bool {
507
531
match self {
@@ -901,10 +925,13 @@ mod test {
901
925
902
926
#[ test]
903
927
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
+ ) ;
905
931
assert ! ( AllowedHostsConfig :: parse(
906
932
& [ "spin.fermyon.dev" , "insecure:allow-all" ] ,
907
- & dummy_resolver( )
933
+ & dummy_resolver( ) ,
934
+ & [ ]
908
935
)
909
936
. is_err( ) ) ;
910
937
}
@@ -927,6 +954,7 @@ mod test {
927
954
let allowed = AllowedHostsConfig :: parse (
928
955
& [ "*://spin.fermyon.dev:443" , "http://example.com:8383" ] ,
929
956
& dummy_resolver ( ) ,
957
+ & [ ] ,
930
958
)
931
959
. unwrap ( ) ;
932
960
assert ! (
@@ -944,7 +972,7 @@ mod test {
944
972
#[ test]
945
973
fn test_allowed_hosts_with_trailing_slash ( ) {
946
974
let allowed =
947
- AllowedHostsConfig :: parse ( & [ "https://my.api.com/" ] , & dummy_resolver ( ) ) . unwrap ( ) ;
975
+ AllowedHostsConfig :: parse ( & [ "https://my.api.com/" ] , & dummy_resolver ( ) , & [ ] ) . unwrap ( ) ;
948
976
assert ! ( allowed. allows( & OutboundUrl :: parse( "https://my.api.com" , "https" ) . unwrap( ) ) ) ;
949
977
assert ! ( allowed. allows( & OutboundUrl :: parse( "https://my.api.com/" , "https" ) . unwrap( ) ) ) ;
950
978
}
@@ -954,6 +982,7 @@ mod test {
954
982
let allowed = AllowedHostsConfig :: parse (
955
983
& [ "http://*.example.com" , "http://*.example2.com:8383" ] ,
956
984
& dummy_resolver ( ) ,
985
+ & [ ] ,
957
986
)
958
987
. unwrap ( ) ;
959
988
assert ! (
@@ -976,7 +1005,8 @@ mod test {
976
1005
977
1006
#[ test]
978
1007
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 ( ) ;
980
1010
assert ! (
981
1011
allowed
. allows
( & OutboundUrl :: parse
( "mysql://user:pass#[email protected] " , "mysql" ) . unwrap
( ) )
982
1012
) ;
@@ -988,7 +1018,66 @@ mod test {
988
1018
#[ test]
989
1019
fn test_cidr ( ) {
990
1020
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 ( ) ;
992
1022
assert ! ( allowed. allows( & OutboundUrl :: parse( "tcp://127.0.0.1:63551" , "tcp" ) . unwrap( ) ) ) ;
993
1023
}
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
+ }
994
1083
}
0 commit comments