feat(oci): offer access to an existing host directory and gather the file-sharing applications

feat(oci): offer access to a host directory that already exists
feat(oci): gather the file-sharing applications in Files & Sharing
fix(oci): ShareCoveX keeps its settings in a 1 GB volume, and the new translations are mended
This commit is contained in:
MacRimi
2026-10-08 22:28:53 +02:00
parent 1a5fec13ec
commit abf436c352
24 changed files with 350 additions and 145 deletions
+71
View File
@@ -2,7 +2,9 @@
installation, and its privileged profile is offered by the advanced one only."""
from pathlib import Path
import os
import sys
import tempfile
import unittest
from unittest.mock import patch
@@ -10,6 +12,7 @@ ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "src"))
sys.path.insert(0, str(Path(__file__).resolve().parent))
from proxmenux_oci import host
from proxmenux_oci.catalog import Catalog
from proxmenux_oci.installer import ADVANCED_MODE, DEFAULT_MODE, InstallError, build_deployment
from proxmenux_oci.recreation import edit_recreation
@@ -101,6 +104,10 @@ class SharedDirectoriesTests(unittest.TestCase):
self.assertFalse(any("ShareCoveX panel administrator" in text for text in ui.asked))
self.assertEqual([m["container_path"] for m in plan["mounts"]], ["/config", "/shares/media"])
self.assertEqual(plan["mounts"][1]["size_gb"], 32)
# The settings stay small: their volume is created at the size the policy states.
self.assertEqual(plan["mounts"][0]["size_gb"], 1)
other = self.catalog.compose("seerr")["container_contract"]["volumes"][0]["managed_volume"]
self.assertGreaterEqual(other["default_size_gb"], 16)
def test_only_the_advanced_installation_offers_nfsv4_and_it_makes_the_container_privileged(self, *_):
ui, _template, plan = self.build({NAME: ["media"]}, ADVANCED_MODE)
@@ -125,6 +132,70 @@ class SharedDirectoriesTests(unittest.TestCase):
with self.assertRaisesRegex(InstallError, "minimum number of characters is 8"):
self.build({NAME: ["media"], "(empty = generate)": ["short"]}, ADVANCED_MODE)
def test_an_existing_directory_the_application_cannot_write_to_offers_access(self, *_):
with tempfile.TemporaryDirectory() as directory:
answers = {NAME: ["media"], "Where to store /shares/media": ["host-bind"],
"Host path for /shares/media": [directory]}
with patch("proxmenux_oci.installer.host.can_write", return_value=False) as check:
ui, _template, plan = self.build(answers)
question = next(text for text in ui.asked if "Grant ShareCoveX access" in text)
# The identity is the one of the volumes, in the range of an unprivileged container.
check.assert_called_once_with(directory, 101000, 101000)
self.assertIn("UID 101000", question)
self.assertIn("changes owner or permissions", question)
self.assertIs(plan["mounts"][1]["grant_access"], True)
_ui, _template, declined = self.build({**answers, question: [False]})
self.assertNotIn("grant_access", declined["mounts"][1])
with patch("proxmenux_oci.installer.host.can_write", return_value=True):
ui, _template, plan = self.build(answers)
self.assertFalse(any("Grant ShareCoveX access" in text for text in ui.asked))
self.assertNotIn("grant_access", plan["mounts"][1])
# A privileged container writes with the identity as it is.
nfsv4 = "NFSv4 needs a privileged container"
with patch("proxmenux_oci.installer.host.can_write", return_value=False) as check:
ui = ScriptedUI(answers)
template = self.catalog.compose("sharecovex")
first = build_deployment(template, ui, ADVANCED_MODE)
prompt = next(text for text in ui.asked if nfsv4 in text)
check.reset_mock()
build_deployment(self.catalog.compose("sharecovex"), ScriptedUI({**answers, prompt: [True]}),
ADVANCED_MODE)
check.assert_called_once_with(directory, 1000, 1000)
self.assertIsNotNone(first)
def test_a_directory_that_does_not_exist_yet_is_created_for_the_application(self, *_):
with patch("proxmenux_oci.installer.host.can_write") as check:
ui, _template, plan = self.build({NAME: ["media"], "Where to store /shares/media": ["host-bind"],
"Host path for /shares/media": ["/nonexistent/proxmenux-test/media"]})
check.assert_not_called()
self.assertNotIn("grant_access", plan["mounts"][1])
self.assertIs(plan["mounts"][1]["create_if_missing"], True)
def test_write_access_is_read_from_the_mode_bits(self, *_):
with tempfile.TemporaryDirectory() as directory:
status = os.stat(directory)
os.chmod(directory, 0o750)
self.assertTrue(host.can_write(directory, status.st_uid, 99999))
self.assertFalse(host.can_write(directory, 99998, status.st_gid))
self.assertFalse(host.can_write(directory, 99998, 99999))
os.chmod(directory, 0o770)
self.assertTrue(host.can_write(directory, 99998, status.st_gid))
os.chmod(directory, 0o757)
self.assertTrue(host.can_write(directory, 99998, 99999))
os.chmod(directory, 0o700)
self.assertFalse(host.can_write("/nonexistent/proxmenux-test", 0, 0))
def test_the_installer_script_grants_access_only_when_asked(self, *_):
script = (ROOT / "remote/install_oci.sh").read_text()
self.assertIn("(.grant_access // false)] | @tsv", script)
self.assertIn('if [[ -d $SOURCE && $GRANT_ACCESS == true ]]; then', script)
# The owner is never changed, and the rule is not applied twice.
grant = script[script.index("grant_shared_access() {"):script.index("MOUNT_ENTRIES=")]
self.assertNotIn("chown", grant)
self.assertNotIn("chmod", grant)
self.assertIn('grep -q "^default:user:${HOST_BIND_UID}:rwx"', grant)
self.assertIn('setfacl -R -P -m "u:${HOST_BIND_UID}:rwX,g:${HOST_BIND_GID}:rwX"', grant)
def test_a_name_that_cannot_identify_a_share_is_refused(self, *_):
for name in ("Media", "my files", "9lives", "config", "", "a" * 33):
with self.assertRaisesRegex(ValueError, "lowercase"):