@@ -583,6 +583,28 @@ def test_stock_list_fetch_api_blocks_metadata_endpoint(
583583 mock_urlopen .assert_not_called ()
584584 self .assertEqual (config .stock_list , ["000001" , "300750" ])
585585
586+ @patch ("src.config.setup_env" )
587+ @patch ("src.config.urllib.request.urlopen" )
588+ @patch .object (Config , "_parse_litellm_yaml" , return_value = [])
589+ def test_stock_list_fetch_api_blocks_ipv6_metadata_endpoint (
590+ self ,
591+ _mock_parse_yaml ,
592+ mock_urlopen ,
593+ _mock_setup_env ,
594+ ) -> None :
595+ with patch .dict (
596+ os .environ ,
597+ {
598+ "STOCK_LIST" : "000001,300750" ,
599+ "STOCK_LIST_FETCH_API" : "http://[fd00:ec2::254]/latest/meta-data" ,
600+ },
601+ clear = True ,
602+ ):
603+ config = Config ._load_from_env ()
604+
605+ mock_urlopen .assert_not_called ()
606+ self .assertEqual (config .stock_list , ["000001" , "300750" ])
607+
586608 @patch ("src.config.setup_env" )
587609 @patch ("src.config.urllib.request.urlopen" )
588610 @patch .object (Config , "_parse_litellm_yaml" , return_value = [])
@@ -615,6 +637,38 @@ def test_stock_list_fetch_api_blocks_hostname_resolving_to_metadata_ip(
615637 mock_urlopen .assert_not_called ()
616638 self .assertEqual (config .stock_list , ["000001" , "300750" ])
617639
640+ @patch ("src.config.setup_env" )
641+ @patch ("src.config.urllib.request.urlopen" )
642+ @patch .object (Config , "_parse_litellm_yaml" , return_value = [])
643+ def test_stock_list_fetch_api_blocks_hostname_resolving_to_ipv6_private_ip (
644+ self ,
645+ _mock_parse_yaml ,
646+ mock_urlopen ,
647+ _mock_setup_env ,
648+ ) -> None :
649+ self .mock_getaddrinfo .return_value = [
650+ (
651+ socket .AF_INET6 ,
652+ socket .SOCK_STREAM ,
653+ socket .IPPROTO_TCP ,
654+ "" ,
655+ ("fd00:ec2::254" , 443 ),
656+ )
657+ ]
658+
659+ with patch .dict (
660+ os .environ ,
661+ {
662+ "STOCK_LIST" : "000001,300750" ,
663+ "STOCK_LIST_FETCH_API" : "https://watchlist.example/stocks.json" ,
664+ },
665+ clear = True ,
666+ ):
667+ config = Config ._load_from_env ()
668+
669+ mock_urlopen .assert_not_called ()
670+ self .assertEqual (config .stock_list , ["000001" , "300750" ])
671+
618672 @patch ("src.config.setup_env" )
619673 @patch ("src.config.urllib.request.urlopen" )
620674 @patch .object (Config , "_parse_litellm_yaml" , return_value = [])
@@ -644,6 +698,35 @@ def test_stock_list_fetch_api_blocks_metadata_redirect_before_reading_response(
644698 self .assertFalse (response .read_called )
645699 self .assertEqual (config .stock_list , ["000001" , "300750" ])
646700
701+ @patch ("src.config.setup_env" )
702+ @patch ("src.config.urllib.request.urlopen" )
703+ @patch .object (Config , "_parse_litellm_yaml" , return_value = [])
704+ def test_stock_list_fetch_api_blocks_ipv6_metadata_redirect_before_reading_response (
705+ self ,
706+ _mock_parse_yaml ,
707+ mock_urlopen ,
708+ _mock_setup_env ,
709+ ) -> None :
710+ response = _FakeUrlopenResponse (
711+ '["600519"]' ,
712+ final_url = "http://[fd00:ec2::254]/latest/meta-data" ,
713+ )
714+ mock_urlopen .return_value = response
715+
716+ with patch .dict (
717+ os .environ ,
718+ {
719+ "STOCK_LIST" : "000001,300750" ,
720+ "STOCK_LIST_FETCH_API" : "https://example.com/stocks.json" ,
721+ },
722+ clear = True ,
723+ ):
724+ config = Config ._load_from_env ()
725+
726+ mock_urlopen .assert_called_once ()
727+ self .assertFalse (response .read_called )
728+ self .assertEqual (config .stock_list , ["000001" , "300750" ])
729+
647730 @patch ("src.config.setup_env" )
648731 @patch ("src.config.urllib.request.urlopen" )
649732 @patch .object (Config , "_parse_litellm_yaml" , return_value = [])
0 commit comments