Authored-By: OpenAI (GPT-5) <noreply@openai.com>
This commit is contained in:
+106
-2
@@ -230,6 +230,16 @@ class ConfigContractTests(unittest.TestCase):
|
||||
with self.assertRaisesRegex(ConfigError, "build input contains symlink"):
|
||||
validate_artifact_inputs(root, cfg)
|
||||
|
||||
def test_artifact_root_symlink_is_rejected_before_resolution(self):
|
||||
cfg = normalize_site_config(self.raw, "baseline.fritzlab.net")
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
root = Path(tmp)
|
||||
(root / "dist-real").mkdir()
|
||||
(root / "dist").symlink_to(root / "dist-real")
|
||||
(root / "portal" / "build").mkdir(parents=True)
|
||||
with self.assertRaisesRegex(ConfigError, "content_dir contains symlink component"):
|
||||
validate_artifact_inputs(root, cfg)
|
||||
|
||||
|
||||
class GenerationTests(unittest.TestCase):
|
||||
def render(self, raw):
|
||||
@@ -263,6 +273,17 @@ class GenerationTests(unittest.TestCase):
|
||||
self.assertNotIn("passhostheader", files["manifests/ingress-portal.yaml"])
|
||||
self.assertIn("baseline-dist.web.sjc001.fritzlab.net", files["manifests/service-distributions.yaml"])
|
||||
|
||||
def test_yaml_ambiguous_artifact_name_stays_a_string_annotation(self):
|
||||
raw = fixture("split-site.yaml")
|
||||
raw["artifacts"][0]["name"] = "yes"
|
||||
raw["routes"][0]["artifact"] = "yes"
|
||||
tmp, _, files = self.render(raw)
|
||||
self.addCleanup(tmp.cleanup)
|
||||
ingress = yaml.safe_load(files["manifests/ingress-portal.yaml"])
|
||||
self.assertEqual(
|
||||
"yes", ingress["metadata"]["annotations"]["site-publish.fritzlab.net/artifact"],
|
||||
)
|
||||
|
||||
def test_generation_is_deterministic_when_input_lists_are_reversed(self):
|
||||
raw = fixture("split-site.yaml")
|
||||
first_tmp, _, first = self.render(raw)
|
||||
@@ -286,12 +307,14 @@ class GenerationTests(unittest.TestCase):
|
||||
self.assertFalse(stale.exists())
|
||||
|
||||
def test_legacy_names_and_garage_s3_target_are_preserved(self):
|
||||
tmp, _, files = self.render(fixture("legacy-site.yaml"))
|
||||
tmp, app_dir, files = self.render(fixture("legacy-site.yaml"))
|
||||
self.addCleanup(tmp.cleanup)
|
||||
self.assertIn("manifests/service.yaml", files)
|
||||
self.assertIn("manifests/ingress.yaml", files)
|
||||
self.assertIn("garage-s3.storage.svc.k8s.sjc001.fritzlab.net", files["manifests/service.yaml"])
|
||||
self.assertNotIn("passhostheader", files["manifests/ingress.yaml"])
|
||||
self.assertNotIn("site-publish.fritzlab.net", files["manifests/ingress.yaml"])
|
||||
self.assertEqual({}, deploy.previous_route_contracts(app_dir))
|
||||
|
||||
|
||||
class BuildTests(unittest.TestCase):
|
||||
@@ -429,12 +452,93 @@ class PublishingTests(unittest.TestCase):
|
||||
immutable_publish.call_args.args[2]["cache_control"],
|
||||
)
|
||||
|
||||
def test_root_move_preserves_only_actual_retired_immutable_prefix(self):
|
||||
cfg = normalize_site_config(fixture("split-site.yaml"), "baseline.fritzlab.net")
|
||||
artifact = next(item for item in cfg["artifacts"] if item["name"] == "distributions")
|
||||
route = {**next(item for item in cfg["routes"] if item["artifact"] == "distributions"),
|
||||
"path": "/"}
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
root = Path(tmp)
|
||||
html = root / artifact["build_dir"]
|
||||
(html / "releases").mkdir(parents=True)
|
||||
(html / "channels").mkdir()
|
||||
(html / "docs" / "releases").mkdir(parents=True)
|
||||
(html / "channels" / "stable.json").write_text("channel")
|
||||
(html / "docs" / "releases" / "index.html").write_text("mutable")
|
||||
commands = []
|
||||
with patch.dict(os.environ, {
|
||||
"DIST_S3_ACCESS_KEY": "dist-key", "DIST_S3_SECRET_KEY": "dist-secret"
|
||||
}, clear=False), patch.object(
|
||||
deploy, "run", side_effect=lambda command, **_: commands.append(command)
|
||||
):
|
||||
deploy.s3_sync(artifact, route, root, previous_contract={
|
||||
"path": "/foo", "access": "public", "artifact": "distributions",
|
||||
"immutable_paths": ["releases"],
|
||||
})
|
||||
rendered = [" ".join(command) for command in commands]
|
||||
self.assertTrue(all("foo/releases/*" in command for command in rendered[:2]))
|
||||
self.assertTrue(all("*/releases/*" not in command for command in rendered))
|
||||
|
||||
def test_protected_bucket_cannot_become_public_across_deployments(self):
|
||||
cfg = normalize_site_config(fixture("split-site.yaml"), "baseline.fritzlab.net")
|
||||
previous = {
|
||||
"baseline-dist": {
|
||||
"path": "/dist", "access": "protected", "artifact": "old-name",
|
||||
"immutable_paths": ["releases"],
|
||||
}
|
||||
}
|
||||
with self.assertRaisesRegex(RuntimeError, "cannot become public while reusing protected"):
|
||||
deploy.validate_route_migrations(cfg, previous)
|
||||
renamed = copy.deepcopy(cfg)
|
||||
artifact = next(item for item in renamed["artifacts"] if item["name"] == "distributions")
|
||||
artifact["name"] = "downloads"
|
||||
route = next(item for item in renamed["routes"] if item["artifact"] == "distributions")
|
||||
route["artifact"] = "downloads"
|
||||
with self.assertRaisesRegex(RuntimeError, "cannot become public while reusing protected"):
|
||||
deploy.validate_route_migrations(renamed, previous)
|
||||
previous = {"retired-protected-bucket": previous["baseline-dist"]}
|
||||
deploy.validate_route_migrations(cfg, previous)
|
||||
|
||||
def test_protected_split_bucket_cannot_become_legacy_public(self):
|
||||
cfg = normalize_site_config(fixture("legacy-site.yaml"), "baseline.fritzlab.net")
|
||||
previous = {
|
||||
"baseline.fritzlab.net": {
|
||||
"path": "/portal", "access": "protected", "artifact": "portal",
|
||||
"immutable_paths": [],
|
||||
}
|
||||
}
|
||||
with self.assertRaisesRegex(RuntimeError, "cannot become public while reusing protected"):
|
||||
deploy.validate_route_migrations(cfg, previous)
|
||||
|
||||
def test_removed_immutable_rule_preserves_prior_keys(self):
|
||||
cfg = normalize_site_config(fixture("split-site.yaml"), "baseline.fritzlab.net")
|
||||
artifact = next(item for item in cfg["artifacts"] if item["name"] == "distributions")
|
||||
artifact["cache_rules"] = [
|
||||
rule for rule in artifact["cache_rules"] if rule["path"] != "releases"
|
||||
]
|
||||
route = next(item for item in cfg["routes"] if item["artifact"] == "distributions")
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
html = Path(tmp)
|
||||
filters = deploy.retired_immutable_filters(artifact, route, html, {
|
||||
"path": "/dist", "access": "public", "artifact": "distributions",
|
||||
"immutable_paths": ["releases"],
|
||||
})
|
||||
self.assertEqual(["--exclude", "releases/*"], filters)
|
||||
(html / "releases").mkdir()
|
||||
(html / "releases" / "replacement.js").write_text("mutable")
|
||||
with self.assertRaisesRegex(RuntimeError, "collides with retired immutable"):
|
||||
deploy.retired_immutable_filters(artifact, route, html, {
|
||||
"path": "/dist", "access": "public", "artifact": "distributions",
|
||||
"immutable_paths": ["releases"],
|
||||
})
|
||||
|
||||
def test_later_route_immutable_failure_stops_all_mutable_publication(self):
|
||||
cfg = normalize_site_config(fixture("split-site.yaml"), "baseline.fritzlab.net")
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
root = Path(tmp)
|
||||
with patch.object(deploy, "validate_publication_environment"), \
|
||||
patch.object(deploy, "validate_artifact_output"), patch.object(
|
||||
patch.object(deploy, "validate_artifact_output"), \
|
||||
patch.object(deploy, "clone_apps", return_value=root / "apps"), patch.object(
|
||||
deploy, "publish_route_immutables",
|
||||
side_effect=[None, RuntimeError("immutable failed")],
|
||||
) as immutable_publish, patch.object(deploy, "s3_sync") as mutable_sync, \
|
||||
|
||||
Reference in New Issue
Block a user