Publish curated ITWorx-ModelForge source from 990401737f96c8d46a9f7b0d84994516cadcb6a0
This commit is contained in:
1 parent
7082ab955a
commit
848f0d8f8a
434 files changed
+67298
-4315
No files matched your search
@@ -0,0 +1,215 @@
|
||||
"""Unit tests for the fail-closed P12 RC isolation preflight."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import importlib.util
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
SPEC = importlib.util.spec_from_file_location("rc_isolation_preflight", ROOT / "scripts" / "rc_isolation_preflight.py")
|
||||
assert SPEC is not None and SPEC.loader is not None
|
||||
preflight = importlib.util.module_from_spec(SPEC)
|
||||
SPEC.loader.exec_module(preflight)
|
||||
|
||||
|
||||
PROJECT = "modelforge-validation-p12a"
|
||||
|
||||
|
||||
def compose_plan(root: Path) -> dict[str, object]:
|
||||
return {
|
||||
"services": {
|
||||
"api": {
|
||||
"networks": ["default"],
|
||||
"volumes": [
|
||||
{"type": "volume", "source": "postgres-data", "target": "/data"},
|
||||
{"type": "bind", "source": str(root / "config"), "target": "/app/config", "read_only": True},
|
||||
],
|
||||
"ports": [{"host_ip": "127.0.0.1", "published": "0", "target": 8000}],
|
||||
},
|
||||
"node-agent": {
|
||||
"networks": ["default"],
|
||||
"volumes": [{"type": "volume", "source": "node-state", "target": "/data/state"}],
|
||||
},
|
||||
},
|
||||
"volumes": {
|
||||
"postgres-data": {"name": f"{PROJECT}_postgres-data"},
|
||||
"node-state": {"name": f"{PROJECT}_node-state"},
|
||||
},
|
||||
"networks": {"default": {"name": f"{PROJECT}_default"}},
|
||||
}
|
||||
|
||||
|
||||
class RcIsolationPreflightTests(unittest.TestCase):
|
||||
def plan_root(self, *, with_manifest: bool = True) -> tempfile.TemporaryDirectory[str]:
|
||||
temporary = tempfile.TemporaryDirectory()
|
||||
config = Path(temporary.name, "config")
|
||||
config.mkdir()
|
||||
if with_manifest:
|
||||
manifest = config / "models" / "initial-candidates.yaml"
|
||||
manifest.parent.mkdir()
|
||||
manifest.write_text("candidates: []\n", encoding="utf-8")
|
||||
self.addCleanup(temporary.cleanup)
|
||||
return temporary
|
||||
|
||||
def validate(
|
||||
self,
|
||||
plan: dict[str, object],
|
||||
root: Path,
|
||||
*,
|
||||
ports: set[int] | None = None,
|
||||
names: set[str] | None = None,
|
||||
) -> dict[str, object]:
|
||||
return preflight.validate_compose(
|
||||
plan,
|
||||
project=PROJECT,
|
||||
candidate_root=root,
|
||||
protected_ports=ports or set(),
|
||||
protected_resource_names=names or set(),
|
||||
)
|
||||
|
||||
def test_valid_validation_compose_plan_is_accepted(self) -> None:
|
||||
temporary = self.plan_root()
|
||||
root = Path(temporary.name)
|
||||
result = self.validate(
|
||||
compose_plan(root), root, ports={18000, 13000}, names={"modelforge-postgres-1"}
|
||||
)
|
||||
self.assertEqual(result["project"], PROJECT)
|
||||
self.assertEqual(result["published_ports"], [])
|
||||
|
||||
def test_project_validation_rejects_production_and_legacy_rc_names(self) -> None:
|
||||
for project in (
|
||||
"modelforge",
|
||||
"modelforge-rc-p12a",
|
||||
"modelforge-validation-",
|
||||
"modelforge-validation-prod-",
|
||||
):
|
||||
with self.subTest(project=project), self.assertRaises(preflight.IsolationError):
|
||||
preflight.validate_project(project)
|
||||
|
||||
def test_missing_bind_source_is_rejected(self) -> None:
|
||||
temporary = self.plan_root(with_manifest=False)
|
||||
root = Path(temporary.name)
|
||||
plan = compose_plan(root)
|
||||
(root / "config").rmdir()
|
||||
with self.assertRaisesRegex(preflight.IsolationError, "missing bind source"):
|
||||
self.validate(plan, root)
|
||||
|
||||
def test_config_manifest_must_exist_under_exact_bind_source(self) -> None:
|
||||
temporary = self.plan_root(with_manifest=False)
|
||||
root = Path(temporary.name)
|
||||
plan = compose_plan(root)
|
||||
# A manifest elsewhere in the candidate tree cannot satisfy this bind's contract.
|
||||
manifest = root / "models" / "initial-candidates.yaml"
|
||||
manifest.parent.mkdir()
|
||||
manifest.write_text("candidates: []\n", encoding="utf-8")
|
||||
with self.assertRaisesRegex(preflight.IsolationError, "missing models/initial-candidates.yaml under its source"):
|
||||
self.validate(plan, root)
|
||||
|
||||
def test_rendered_compose_network_mapping_is_accepted(self) -> None:
|
||||
temporary = self.plan_root()
|
||||
root = Path(temporary.name)
|
||||
plan = compose_plan(root)
|
||||
plan["services"]["api"]["networks"] = {"default": None} # type: ignore[index]
|
||||
self.assertEqual(self.validate(plan, root)["declared_networks"], ["default"])
|
||||
|
||||
def test_unsafe_compose_plans_are_rejected(self) -> None:
|
||||
cases = [
|
||||
(lambda plan: plan["services"]["api"].update(network_mode="host"), "host network"),
|
||||
(lambda plan: plan["services"]["api"].update(container_name="modelforge-api-1"), "global container name"),
|
||||
(lambda plan: plan["services"]["api"]["ports"].__setitem__(0, {"host_ip": "0.0.0.0", "published": "19000", "target": 8000}), "non-loopback"),
|
||||
(lambda plan: plan["services"]["api"]["ports"].__setitem__(0, {"host_ip": "127.0.0.1", "published": "18000", "target": 8000}), "protected host port"),
|
||||
(lambda plan: plan["services"]["api"]["volumes"].__setitem__(1, {"type": "bind", "source": "/mnt/user/appdata/modelforge", "target": "/data", "read_only": True}), "escapes the candidate root"),
|
||||
(lambda plan: plan["services"]["api"]["volumes"].__setitem__(1, {"type": "bind", "source": "config", "target": "/app/config", "read_only": False}), "writable bind mount"),
|
||||
(lambda plan: plan["volumes"]["postgres-data"].update(external=True), "is external"),
|
||||
(lambda plan: plan["networks"]["default"].update(name="modelforge_default"), "non-project name"),
|
||||
]
|
||||
for mutate, message in cases:
|
||||
with self.subTest(message=message):
|
||||
temporary = self.plan_root()
|
||||
root = Path(temporary.name)
|
||||
plan = compose_plan(root)
|
||||
mutate(plan)
|
||||
with self.assertRaisesRegex(preflight.IsolationError, message):
|
||||
self.validate(plan, root, ports={18000})
|
||||
|
||||
def test_protected_resource_reference_is_rejected(self) -> None:
|
||||
temporary = self.plan_root()
|
||||
root = Path(temporary.name)
|
||||
plan = compose_plan(root)
|
||||
plan["services"]["api"]["environment"] = {"UNSAFE": "modelforge-postgres-1"} # type: ignore[index]
|
||||
with self.assertRaisesRegex(preflight.IsolationError, "protected resources"):
|
||||
self.validate(plan, root, names={"modelforge-postgres-1"})
|
||||
|
||||
def test_only_isolated_tls_service_can_publish_test_port(self) -> None:
|
||||
temporary = self.plan_root()
|
||||
root = Path(temporary.name)
|
||||
source = root / "source" / "deploy" / "validation"
|
||||
source.mkdir(parents=True)
|
||||
(source / "Caddyfile").write_text("https://modelforge.example.com:8443 {}\n", encoding="utf-8")
|
||||
certificates = root / "tls"
|
||||
certificates.mkdir()
|
||||
(certificates / "fullchain.pem").write_text("certificate", encoding="utf-8")
|
||||
(certificates / "privkey.pem").write_text("key", encoding="utf-8")
|
||||
plan = compose_plan(root)
|
||||
plan["networks"]["ingress"] = {"name": f"{PROJECT}_ingress"}
|
||||
plan["services"]["tls"] = {
|
||||
"image": "caddy:2.10-alpine@sha256:4c6e91c6ed0e2fa03efd5b44747b625fec79bc9cd06ac5235a779726618e530d",
|
||||
"networks": ["ingress"], "read_only": True, "cap_drop": ["ALL"],
|
||||
"security_opt": ["no-new-privileges:true"],
|
||||
"volumes": [
|
||||
{"type": "bind", "source": str(source / "Caddyfile"), "target": "/etc/caddy/Caddyfile", "read_only": True},
|
||||
{"type": "bind", "source": str(certificates / "fullchain.pem"), "target": "/run/tls/fullchain.pem", "read_only": True},
|
||||
{"type": "bind", "source": str(certificates / "privkey.pem"), "target": "/run/tls/privkey.pem", "read_only": True},
|
||||
],
|
||||
"ports": [{"host_ip": "0.0.0.0", "published": "18444", "target": 8443, "protocol": "tcp"}],
|
||||
}
|
||||
with self.assertRaisesRegex(preflight.IsolationError, "non-loopback"):
|
||||
self.validate(plan, root)
|
||||
self.assertEqual(preflight.validate_compose(
|
||||
plan, project=PROJECT, candidate_root=root,
|
||||
protected_ports={443, 8443}, protected_resource_names=set(), public_tls_port=18444,
|
||||
)["published_ports"], [18444])
|
||||
plan["services"]["api"]["ports"][0] = {"host_ip": "0.0.0.0", "published": "18444", "target": 8000}
|
||||
with self.assertRaisesRegex(preflight.IsolationError, "non-loopback"):
|
||||
preflight.validate_compose(
|
||||
plan, project=PROJECT, candidate_root=root,
|
||||
protected_ports=set(), protected_resource_names=set(), public_tls_port=18444,
|
||||
)
|
||||
|
||||
def test_observed_resources_require_exact_labels_and_project_names(self) -> None:
|
||||
observed = {
|
||||
"containers": [{"name": f"{PROJECT}-api-1", "labels": {"com.docker.compose.project": PROJECT}}],
|
||||
"volumes": [{"name": f"{PROJECT}_postgres-data", "labels": {"com.docker.compose.project": PROJECT}}],
|
||||
"networks": [{"name": f"{PROJECT}_default", "labels": {"com.docker.compose.project": PROJECT}}],
|
||||
}
|
||||
self.assertEqual(preflight.validate_observed_resources(observed, project=PROJECT)["containers"], [f"{PROJECT}-api-1"])
|
||||
observed["volumes"][0]["labels"] = {}
|
||||
with self.assertRaisesRegex(preflight.IsolationError, "no exact project label"):
|
||||
preflight.validate_observed_resources(observed, project=PROJECT)
|
||||
|
||||
def test_docker_resource_collection_uses_exact_inspection(self) -> None:
|
||||
label = {"com.docker.compose.project": PROJECT}
|
||||
responses = {
|
||||
("container", "ls", "--all", "--quiet", "--filter", f"label=com.docker.compose.project={PROJECT}"): "container-id\n",
|
||||
("volume", "ls", "--quiet", "--filter", f"label=com.docker.compose.project={PROJECT}"): "volume-id\n",
|
||||
("network", "ls", "--quiet", "--filter", f"label=com.docker.compose.project={PROJECT}"): "network-id\n",
|
||||
("container", "inspect", "container-id"): '[{"Name":"/' + PROJECT + '-api-1","Config":{"Labels":{"com.docker.compose.project":"' + PROJECT + '"}}}]',
|
||||
("volume", "inspect", "volume-id"): '[{"Name":"' + PROJECT + '_data","Labels":{"com.docker.compose.project":"' + PROJECT + '"}}]',
|
||||
("network", "inspect", "network-id"): '[{"Name":"' + PROJECT + '_default","Labels":{"com.docker.compose.project":"' + PROJECT + '"}}]',
|
||||
}
|
||||
|
||||
def run(command, **_kwargs):
|
||||
self.assertEqual(command[0], "docker")
|
||||
return type("Result", (), {"returncode": 0, "stdout": responses[tuple(command[1:])]})()
|
||||
|
||||
with patch.object(preflight.subprocess, "run", run):
|
||||
observed = preflight.collect_observed_resources(PROJECT)
|
||||
self.assertEqual(observed["containers"][0]["labels"], label)
|
||||
self.assertEqual(
|
||||
preflight.validate_observed_resources(observed, project=PROJECT)["networks"],
|
||||
[f"{PROJECT}_default"],
|
||||
)
|
||||
Reference in new issue
Block a user