test_url_safety.py 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. """Unit tests for the shared SSRF-data primitives (#1333).
  2. These primitives are imported by both ``_spoolman_helpers.assert_safe_spoolman_url``
  3. and ``_oidc_helpers.assert_safe_public_https_url``. Test them in isolation
  4. so a future change to one consumer doesn't accidentally drift the data.
  5. """
  6. import ipaddress
  7. import pytest
  8. from backend.app.api.routes._url_safety import (
  9. CLOUD_METADATA_HOSTNAMES,
  10. CLOUD_METADATA_IPS,
  11. is_numeric_encoded_ip,
  12. unwrap_ipv4_mapped,
  13. )
  14. def test_cloud_metadata_set_contains_known_endpoints():
  15. # Both v4 and v6 IMDS endpoints, plus Alibaba's variant.
  16. assert ipaddress.ip_address("169.254.169.254") in CLOUD_METADATA_IPS
  17. assert ipaddress.ip_address("100.100.100.200") in CLOUD_METADATA_IPS
  18. assert ipaddress.ip_address("fd00:ec2::254") in CLOUD_METADATA_IPS
  19. def test_cloud_metadata_set_is_frozen():
  20. # frozenset is the right immutable container — protects against
  21. # accidental mutation in tests/imports.
  22. assert isinstance(CLOUD_METADATA_IPS, frozenset)
  23. @pytest.mark.parametrize(
  24. "candidate",
  25. [
  26. "2130706433", # decimal-encoded 127.0.0.1
  27. "0x7f000001", # hex-encoded 127.0.0.1
  28. "0xFFFFFFFF", # uppercase hex
  29. "0",
  30. "4294967295", # max uint32
  31. "0xa9.0xfe.0xa9.0xfe", # dotted hex
  32. "169.254.43518", # short form
  33. "0251.0376.0251.0376", # dotted octal
  34. "0169.254.169.254", # a leading zero
  35. ],
  36. )
  37. def test_numeric_encoded_forms_are_recognised(candidate):
  38. assert is_numeric_encoded_ip(candidate) is True
  39. @pytest.mark.parametrize(
  40. "candidate",
  41. [
  42. "127.0.0.1", # dotted-decimal — not "numeric-encoded"
  43. "example.com",
  44. "spoolman.lan",
  45. "::1",
  46. "localhost",
  47. "3dprinter.lan",
  48. "node-01",
  49. ],
  50. )
  51. def test_normal_forms_are_not_numeric_encoded(candidate):
  52. assert is_numeric_encoded_ip(candidate) is False
  53. def test_unwrap_ipv4_mapped_unwraps_mapped_address():
  54. mapped = ipaddress.ip_address("::ffff:127.0.0.1")
  55. result = unwrap_ipv4_mapped(mapped)
  56. assert result == ipaddress.ip_address("127.0.0.1")
  57. assert isinstance(result, ipaddress.IPv4Address)
  58. def test_unwrap_ipv4_mapped_passes_through_pure_ipv4():
  59. addr = ipaddress.ip_address("8.8.8.8")
  60. assert unwrap_ipv4_mapped(addr) is addr
  61. def test_unwrap_ipv4_mapped_passes_through_pure_ipv6():
  62. addr = ipaddress.ip_address("2001:db8::1")
  63. assert unwrap_ipv4_mapped(addr) is addr
  64. def test_unwrap_drops_a_zone_id():
  65. """Ignored on connect to an address that is not link-local: the address
  66. reached is the one without it."""
  67. result = unwrap_ipv4_mapped(ipaddress.ip_address("fd00:ec2::254%251"))
  68. assert result == ipaddress.ip_address("fd00:ec2::254")
  69. assert result in CLOUD_METADATA_IPS
  70. def test_cloud_metadata_names_include_the_short_and_alias_forms():
  71. assert {"metadata", "metadata.google", "instance-data", "instance-data.ec2.internal"} <= CLOUD_METADATA_HOSTNAMES