oci: fix low-port and generated secret profiles

This commit is contained in:
Jonatan
2026-10-26 09:06:56 +01:00
parent a4fb46f861
commit 975a3b99cf
10 changed files with 184 additions and 16 deletions
+52
View File
@@ -0,0 +1,52 @@
import json
import sys
import unittest
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "remote"))
import oci_runtime_settings
class PowerDNSRecursorProfileTest(unittest.TestCase):
def test_dns_port_is_available_to_the_non_root_image_only_inside_its_unprivileged_lxc(self):
curated = json.loads((ROOT / "catalog/curated/pdns-recursor.json").read_text())
app = json.loads((ROOT / "catalog/apps/pdns-recursor.json").read_text())
expected_sysctls = [{
"name": "net.ipv4.ip_unprivileged_port_start",
"value": "53",
}]
self.assertEqual(
curated["proxmox"]["installer_profile"]["security"]["sysctls"],
expected_sysctls,
)
self.assertEqual(
app["proxmox"]["installer_profile"]["security"]["sysctls"],
expected_sysctls,
)
self.assertTrue(curated["proxmox"]["defaults"]["unprivileged"])
self.assertNotIn(
"required_capabilities",
curated["proxmox"]["installer_profile"].get("security", {}),
)
self.assertEqual(
oci_runtime_settings.sysctl_content({"security": {"sysctls": expected_sysctls}}),
"lxc.sysctl.net.ipv4.ip_unprivileged_port_start = 53\n",
)
self.assertEqual(
oci_runtime_settings.include_path(111),
Path("/etc/pve/proxmenux/111.sysctls"),
)
installer = (ROOT / "remote/install_oci.sh").read_text()
self.assertIn('SYSCTL_INCLUDE="/etc/pve/proxmenux/${VMID}.sysctls"', installer)
self.assertIn('set_lxc_directive "lxc.include" "$SYSCTL_INCLUDE"', installer)
self.assertEqual(curated["compatibility"]["validated"], False)
self.assertEqual(curated["validation"]["clean_install"], "pending")
self.assertEqual(curated, app)
if __name__ == "__main__":
unittest.main()
@@ -0,0 +1,88 @@
import re
import sys
import unittest
from pathlib import Path
from unittest.mock import patch
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "src"))
from proxmenux_oci.catalog import Catalog
from proxmenux_oci.installer import DEFAULT_MODE, build_deployment
class RecordingUI:
def __init__(self):
self.asked = []
def ask(self, text, default=None, required=True):
self.asked.append(text)
return default if default not in (None, "") else "fixture-value"
def password(self, text, required=True):
self.asked.append(text)
return "fixture-password"
def choose(self, text, options, default=None):
self.asked.append(text)
return default
def confirm(self, text, default=False):
self.asked.append(text)
return default
def checklist(self, text, options, default=None):
self.asked.append(text)
return default
def info(self, text):
pass
def message(self, text):
pass
def _addresses(ui, bridge, names, *args):
return {name: "dhcp" for name in names}, None
class RequiredGeneratedEnvironmentTests(unittest.TestCase):
@patch("proxmenux_oci.i18n.language", return_value="en")
@patch("proxmenux_oci.installer.host.storages", return_value=[
{"storage": "local-lvm", "type": "lvmthin", "avail": 100 * 2**30}
])
@patch("proxmenux_oci.installer.host.bridges", return_value=[
{"iface": "vmbr0", "cidr": "192.0.2.10/24"}
])
@patch("proxmenux_oci.installer.host.timezone", return_value="Europe/Madrid")
@patch("proxmenux_oci.installer.host.gpus", return_value={"intel": [], "amd": [], "nvidia": False})
@patch("proxmenux_oci.installer.access.ask_ipv4", return_value=("dhcp", None))
@patch("proxmenux_oci.installer.access.ask_addresses", side_effect=_addresses)
@patch("proxmenux_oci.installer.secrets.token_hex", return_value="a1" * 24)
def test_database_secrets_are_generated_without_a_prompt_or_static_value(self, token_hex, *_):
requirements = {
"mysql": "MYSQL_ROOT_PASSWORD",
"clickhouse": "CLICKHOUSE_PASSWORD",
"typesense": "TYPESENSE_API_KEY",
}
catalog = Catalog(ROOT)
for app, name in requirements.items():
with self.subTest(app=app):
ui = RecordingUI()
template = catalog.compose(app)
plan = build_deployment(template, ui, DEFAULT_MODE)
variable = next(item for item in plan["environment"] if item["name"] == name)
self.assertTrue(variable["sensitive"])
self.assertRegex(variable["value"], re.compile(r"^[0-9a-f]{48}$"))
self.assertNotIn(name, " ".join(ui.asked))
contract = next(item for item in template["container_contract"]["environment"]
if item["name"] == name)
self.assertNotIn("prompt_user", contract)
token_hex.assert_called_with(24)
token_hex.reset_mock()
if __name__ == "__main__":
unittest.main()