mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-09-29 03:16:51 +03:00
* Create frigate and go2rtc runtime users in the image * Add single fix-ownership helper for volume permission migration * Add init-usermod oneshot for PUID and PGID remapping * Chown newly created runtime directories to the frigate user * Run sentinel-guarded ownership sweep during prepare * Add host-side volume permission migration script * Guard log directory ownership for user-mode startup * Fall back to plain s6-log when running without root * Assert PUID remapping and sweep sentinel in CI smoke test * Skip the ownership sweep in the devcontainer * Pin FRIGATE_RUN_AS_ROOT in ownership tests * Do not record the sweep as complete when a chown failed * Validate PUID and PGID in the migration script * Treat a failed ownership scan as an incomplete sweep * Reject PUID and PGID of 0 during remapping * Handle symlinks, dry runs, and sentinel write failures in the sweep * Treat an absent sweep root as an incomplete sweep
60 lines
2.3 KiB
Python
60 lines
2.3 KiB
Python
"""Tests for runtime ownership helpers."""
|
|
|
|
import unittest
|
|
from unittest.mock import patch
|
|
|
|
from frigate.util import ownership
|
|
|
|
|
|
class FakePwEntry:
|
|
pw_uid = 1500
|
|
pw_gid = 1500
|
|
|
|
|
|
# The devcontainer image exports FRIGATE_RUN_AS_ROOT, so any test that has to
|
|
# reach past the escape-hatch check pins the variable instead of inheriting it.
|
|
class TestGetRuntimeIds(unittest.TestCase):
|
|
@patch("frigate.util.ownership.os.geteuid", return_value=1000)
|
|
def test_returns_none_when_not_root(self, _):
|
|
assert ownership.get_runtime_ids() is None
|
|
|
|
@patch.dict("os.environ", {"FRIGATE_RUN_AS_ROOT": "true"})
|
|
@patch("frigate.util.ownership.os.geteuid", return_value=0)
|
|
def test_returns_none_with_escape_hatch(self, _):
|
|
assert ownership.get_runtime_ids() is None
|
|
|
|
@patch.dict("os.environ", {"FRIGATE_RUN_AS_ROOT": "false"})
|
|
@patch("frigate.util.ownership.pwd.getpwnam", side_effect=KeyError)
|
|
@patch("frigate.util.ownership.os.geteuid", return_value=0)
|
|
def test_returns_none_outside_frigate_image(self, *_):
|
|
assert ownership.get_runtime_ids() is None
|
|
|
|
@patch.dict("os.environ", {"FRIGATE_RUN_AS_ROOT": "false"})
|
|
@patch("frigate.util.ownership.pwd.getpwnam", return_value=FakePwEntry())
|
|
@patch("frigate.util.ownership.os.geteuid", return_value=0)
|
|
def test_returns_frigate_ids_as_root(self, *_):
|
|
assert ownership.get_runtime_ids() == (1500, 1500)
|
|
|
|
|
|
class TestChownToRuntime(unittest.TestCase):
|
|
@patch("frigate.util.ownership.os.chown")
|
|
@patch("frigate.util.ownership.get_runtime_ids", return_value=None)
|
|
def test_noop_when_no_runtime_ids(self, _, chown):
|
|
ownership.chown_to_runtime("/config/test")
|
|
chown.assert_not_called()
|
|
|
|
@patch("frigate.util.ownership.os.chown")
|
|
@patch("frigate.util.ownership.get_runtime_ids", return_value=(1500, 1500))
|
|
def test_chowns_to_runtime_ids(self, _, chown):
|
|
ownership.chown_to_runtime("/config/test")
|
|
chown.assert_called_once_with("/config/test", 1500, 1500)
|
|
|
|
@patch("frigate.util.ownership.os.chown", side_effect=OSError("ro fs"))
|
|
@patch("frigate.util.ownership.get_runtime_ids", return_value=(1500, 1500))
|
|
def test_swallows_oserror(self, *_):
|
|
ownership.chown_to_runtime("/config/test") # must not raise
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|