Pin S3 and SMB connector peers

This commit is contained in:
2026-08-04 10:40:46 +02:00
parent 0c68e904cf
commit 92e649477f
15 changed files with 840 additions and 112 deletions
+50 -40
View File
@@ -5,7 +5,7 @@ from datetime import UTC, datetime
from unittest.mock import patch
from govoplan_files.backend.storage.connector_browse import ConnectorBrowseError, _smb_location, browse_connector_profile
from govoplan_files.backend.storage.connector_imports import ConnectorImportError, read_connector_file
from govoplan_files.backend.storage.connector_imports import read_connector_file
from govoplan_files.backend.storage.connector_profiles import ConnectorProfile, connector_profiles_from_payload
from govoplan_files.backend.storage.connector_providers import connector_provider_descriptors
@@ -23,6 +23,10 @@ class FakeS3Client:
self.list_objects_request: dict[str, object] | None = None
self.head_request: dict[str, object] | None = None
self.get_request: dict[str, object] | None = None
self.closed = False
def close(self) -> None:
self.closed = True
def list_objects_v2(self, **kwargs: object) -> dict[str, object]:
self.list_objects_request = dict(kwargs)
@@ -75,42 +79,39 @@ def s3_profile(**overrides: object) -> ConnectorProfile:
class ConnectorProviderTests(unittest.TestCase):
def test_smb_sdk_transport_fails_closed_before_client_creation_in_all_modes(self) -> None:
def test_smb_browse_uses_the_files_owned_pinned_connection_cache(self) -> None:
profile = ConnectorProfile(
id="smb",
label="SMB",
provider="smb",
endpoint_url="smb://files.example.test/share",
)
for allow_private, address in ((False, "93.184.216.34"), (True, "10.0.0.5")):
with self.subTest(allow_private=allow_private), patch.dict(
"os.environ",
{
"APP_ENV": "production",
"GOVOPLAN_CONNECTOR_ALLOW_PRIVATE_NETWORKS": str(allow_private).lower(),
},
), patch(
"govoplan_core.security.outbound_http.socket.getaddrinfo",
return_value=[(2, 1, 6, "", (address, 445))],
), patch("govoplan_files.backend.storage.connector_browse._smbclient_module") as sdk, self.assertRaisesRegex(
ConnectorBrowseError,
"redirects/referrals.*DNS/IP pinning",
):
browse_connector_profile(profile, path="")
sdk.assert_not_called()
with patch.dict(
"os.environ",
{"APP_ENV": "production", "GOVOPLAN_CONNECTOR_ALLOW_PRIVATE_NETWORKS": "false"},
), patch(
"govoplan_core.security.outbound_http.socket.getaddrinfo",
return_value=[(2, 1, 6, "", ("93.184.216.34", 445))],
), patch("govoplan_files.backend.storage.connector_browse._smbclient_module") as sdk:
sdk.return_value.scandir.return_value.__enter__.return_value = iter(())
self.assertEqual([], browse_connector_profile(profile, path=""))
def test_smb_explicit_ip_still_fails_closed_because_the_sdk_may_follow_referrals(self) -> None:
kwargs = sdk.return_value.scandir.call_args.kwargs
self.assertIsInstance(kwargs["connection_cache"], dict)
self.assertTrue(kwargs["require_signing"])
def test_smb_endpoint_preflight_applies_private_network_policy(self) -> None:
profile = ConnectorProfile(id="smb", label="SMB", provider="smb", endpoint_url="smb://10.0.0.5/share")
with patch.dict(
"os.environ",
{"APP_ENV": "production", "GOVOPLAN_CONNECTOR_ALLOW_PRIVATE_NETWORKS": "true"},
{"APP_ENV": "production", "GOVOPLAN_CONNECTOR_ALLOW_PRIVATE_NETWORKS": "false"},
), patch(
"govoplan_core.security.outbound_http.socket.getaddrinfo",
return_value=[(2, 1, 6, "", ("10.0.0.5", 445))],
), self.assertRaisesRegex(ConnectorBrowseError, "redirects/referrals.*DNS/IP pinning"):
), self.assertRaisesRegex(ConnectorBrowseError, "non-public network"):
_smb_location(profile)
def test_smb_import_surfaces_fail_closed_policy_as_an_import_error(self) -> None:
def test_smb_import_uses_the_same_pinned_connection_cache(self) -> None:
profile = ConnectorProfile(id="smb", label="SMB", provider="smb", endpoint_url="smb://10.0.0.5/share")
with patch.dict(
"os.environ",
@@ -118,12 +119,13 @@ class ConnectorProviderTests(unittest.TestCase):
), patch(
"govoplan_core.security.outbound_http.socket.getaddrinfo",
return_value=[(2, 1, 6, "", ("10.0.0.5", 445))],
), patch("govoplan_files.backend.storage.connector_imports._smbclient_module") as sdk, self.assertRaisesRegex(
ConnectorImportError,
"redirects/referrals.*DNS/IP pinning",
):
read_connector_file(profile, library_id="", path="notice.txt", max_bytes=1024)
sdk.assert_not_called()
), patch("govoplan_files.backend.storage.connector_imports._smbclient_module") as sdk:
sdk.return_value.stat.return_value.st_size = 4
sdk.return_value.open_file.return_value.__enter__.return_value.read.return_value = b"test"
downloaded = read_connector_file(profile, library_id="", path="notice.txt", max_bytes=1024)
self.assertEqual(b"test", downloaded.data)
self.assertIsInstance(sdk.return_value.stat.call_args.kwargs["connection_cache"], dict)
def test_provider_descriptors_include_s3_and_reserved_microsoft_providers(self) -> None:
descriptors = {descriptor.provider: descriptor for descriptor in connector_provider_descriptors()}
@@ -172,6 +174,7 @@ class ConnectorProviderTests(unittest.TestCase):
self.assertEqual("govoplan:root/report.xlsx", items[1].external_id)
self.assertEqual("root/report.xlsx", items[1].metadata["key"])
self.assertEqual("next-page", items[1].metadata["next_continuation_token"])
self.assertTrue(client.closed)
def test_s3_browse_lists_buckets_when_profile_has_no_bucket(self) -> None:
client = FakeS3Client()
@@ -181,27 +184,33 @@ class ConnectorProviderTests(unittest.TestCase):
self.assertEqual(["archive"], [item.path for item in items])
def test_s3_sdk_transport_fails_closed_before_client_creation_in_private_mode(self) -> None:
def test_s3_client_is_constructed_through_the_pinned_transport(self) -> None:
with patch.dict(
"os.environ",
{"APP_ENV": "production", "GOVOPLAN_CONNECTOR_ALLOW_PRIVATE_NETWORKS": "true"},
), patch(
"govoplan_core.security.outbound_http.socket.getaddrinfo",
return_value=[(2, 1, 6, "", ("127.0.0.1", 9000))],
), patch("govoplan_files.backend.storage.connector_browse.import_module") as importer, self.assertRaisesRegex(
ConnectorBrowseError,
"until that transport supports.*DNS/IP pinning",
):
), patch(
"govoplan_files.backend.storage.connector_browse.create_pinned_s3_client",
return_value=FakeS3Client(),
) as factory:
browse_connector_profile(s3_profile(), path="")
importer.assert_not_called()
def test_s3_sdk_endpoint_discovery_fails_closed(self) -> None:
with patch("govoplan_files.backend.storage.connector_browse.import_module") as importer, self.assertRaisesRegex(
ConnectorBrowseError,
"endpoint discovery.*cannot guarantee.*DNS/IP pinning",
):
kwargs = factory.call_args.kwargs
self.assertEqual("http://127.0.0.1:9000", kwargs["endpoint_url"])
self.assertEqual("access-key", kwargs["aws_access_key_id"])
self.assertEqual("secret-key", kwargs["aws_secret_access_key"])
self.assertEqual({}, kwargs["config"].proxies)
def test_s3_endpoint_discovery_uses_the_same_pinned_transport(self) -> None:
with patch(
"govoplan_files.backend.storage.connector_browse.create_pinned_s3_client",
return_value=FakeS3Client(),
) as factory:
browse_connector_profile(s3_profile(endpoint_url=None), path="")
importer.assert_not_called()
self.assertNotIn("endpoint_url", factory.call_args.kwargs)
def test_s3_import_downloads_object_and_preserves_remote_identity(self) -> None:
client = FakeS3Client()
@@ -217,6 +226,7 @@ class ConnectorProviderTests(unittest.TestCase):
self.assertEqual("govoplan:root/report.txt", downloaded.external_id)
self.assertEqual("s3://govoplan/root/report.txt", downloaded.external_url)
self.assertEqual("checksum", downloaded.metadata["checksum_sha256"])
self.assertTrue(client.closed)
if __name__ == "__main__":