import copy import importlib.util import sys import unittest from pathlib import Path from unittest.mock import Mock, patch SCRIPTS = Path(__file__).resolve().parents[1] / "scripts" sys.path.insert(0, str(SCRIPTS)) spec = importlib.util.spec_from_file_location("resources", SCRIPTS / "application_recovery_resources.py") m = importlib.util.module_from_spec(spec) spec.loader.exec_module(m) class ResourcesTests(unittest.TestCase): def setUp(self): self.apps = {r: "synthetic-" + r for r in ("bootstrap", "reader", "custodian", "publisher")} def grants(self, prefix, role): policy = m.policy("synthetic-bucket", prefix, self.apps, "synthetic-owner") return [s for s in policy["Statement"] if s["Principal"]["SCW"] == "application_id:" + self.apps[role]] def test_reader_only_prefixed_read_and_list(self): rows = self.grants("kits", "reader") actions = {a for r in rows for a in r["Action"]} self.assertTrue({"s3:GetObject", "s3:GetObjectVersion", "s3:ListBucketVersions"} <= actions) self.assertFalse(any("Put" in a or "Delete" in a or a == "s3:*" for a in actions)) objects = [r for r in rows if "s3:GetObject" in r["Action"]] self.assertEqual(objects[0]["Resource"], "synthetic-bucket/kits/*") listing = next(r for r in rows if "s3:ListBucket" in r["Action"]) self.assertEqual(listing["Condition"]["StringLike"]["s3:prefix"], ["kits/", "kits/*"]) def test_publisher_has_no_kit_grant(self): self.assertEqual(self.grants("kits", "publisher"), []) def test_publisher_can_abort_without_delete(self): rows = self.grants("archives", "publisher") actions = {a for r in rows for a in r["Action"]} self.assertIn("s3:AbortMultipartUpload", actions) self.assertIn("s3:PutObject", actions) self.assertFalse(any("Delete" in a or "Policy" in a for a in actions)) def test_custodian_no_retained_delete_or_administration(self): rows = self.grants("kits", "custodian") actions = {a for r in rows for a in r["Action"]} self.assertIn("s3:PutObject", actions) self.assertFalse(any("Delete" in a or "Policy" in a or a == "s3:*" for a in actions)) def test_denial_requires_403_not_404_or_transport_error(self): def failing(code): raise m.NativeError(code) self.assertTrue(m.denied(lambda: failing(403))["denied"]) for code in (400, 401, 404, 500): with self.assertRaises(m.Refused): m.denied(lambda code=code: failing(code)) with self.assertRaises(m.Refused): m.denied(dict) def test_bucket_policy_preserves_owner_and_temporary_constructor(self): p = m.policy("b", "kits", self.apps, "o") self.assertEqual(p["Version"], "2023-04-17") self.assertEqual(p["Statement"][0]["Principal"], {"SCW": "user_id:o"}) self.assertTrue(all(s["Effect"] == "Allow" for s in p["Statement"])) def test_archive_policy_respects_native_ten_statement_limit(self): p = m.policy("b", "archives", self.apps, "o") self.assertLessEqual(len(p["Statement"]), 10) shared = next(s for s in p["Statement"] if s["Sid"] == "ArchiveMetadata") self.assertEqual(set(shared["Principal"]["SCW"]), {"application_id:" + self.apps[r] for r in ("reader", "custodian", "publisher")}) self.assertTrue(all(a.startswith("s3:Get") and "Object" not in a for a in shared["Action"])) def test_provider_policy_reordering_allowed_but_extra_permission_refused(self): original = m.policy("b", "archives", self.apps, "o") returned = copy.deepcopy(original) returned["Statement"].reverse() for row in returned["Statement"]: if isinstance(row["Action"], list): row["Action"].reverse() self.assertEqual(m.canonical_policy(original), m.canonical_policy(returned)) returned["Statement"][0]["Action"].append("s3:DeleteObject") self.assertNotEqual(m.canonical_policy(original), m.canonical_policy(returned)) def test_negative_probe_uses_and_closes_its_own_transport(self): resource = object.__new__(m.Resources) resource.pairs, resource.project = {"reader": {}}, "synthetic-project" client = Mock() client.put_object.side_effect = m.NativeError(403) with patch.object(m, "s3", return_value=client) as factory: self.assertTrue(resource.deny_s3("reader", "put_object", Bucket="synthetic")["denied"]) factory.assert_called_once_with({}, "synthetic-project") client.close.assert_called_once() if __name__ == "__main__": unittest.main()