]> git.ipfire.org Git - thirdparty/mkosi.git/commitdiff
util: make name and home of INVOKING_USER methods that cache their results
authorJoerg Behrmann <behrmann@physik.fu-berlin.de>
Tue, 21 Nov 2023 09:47:41 +0000 (10:47 +0100)
committerJoerg Behrmann <behrmann@physik.fu-berlin.de>
Wed, 29 Nov 2023 10:17:49 +0000 (11:17 +0100)
At test time, e.g. during reproducible builds, usernames are not guaranteed to
be resolvable, because NSS is deliberately broken. Hence, only try to resolve
either only if needed and cache the result, so it stays the same across
invocations.

This unfortunately can no longer be achieved by combining @classmethod with
@property, since the combination, which had only been allowed since Python 3.9,
was deprecated again in Python 3.11.

Fixes: #2081
mkosi/__init__.py
mkosi/__main__.py
mkosi/config.py
mkosi/mounts.py
mkosi/util.py

index 19350f34db3cf8645595991c9c1ce3d2c5c5b567..4b25c2861788220fe365fde1d60d996561ee3456 100644 (file)
@@ -2604,7 +2604,7 @@ def show_docs(args: MkosiArgs) -> None:
 
 
 def expand_specifier(s: str) -> str:
-    return s.replace("%u", INVOKING_USER.name)
+    return s.replace("%u", INVOKING_USER.name())
 
 
 def needs_build(args: MkosiArgs, config: MkosiConfig) -> bool:
index 2572bf4243acd99536ae4bf964c6ce5ffd3ae072..8239bd7855728ab02ddde504e40560f212680557 100644 (file)
@@ -13,6 +13,7 @@ from mkosi import run_verb
 from mkosi.config import parse_config
 from mkosi.log import ARG_DEBUG, log_setup
 from mkosi.run import ensure_exc_info, run
+from mkosi.util import INVOKING_USER
 
 
 @contextlib.contextmanager
@@ -43,6 +44,8 @@ def propagate_failed_return() -> Iterator[None]:
 @propagate_failed_return()
 def main() -> None:
     log_setup()
+    # Ensure that the name and home of the user we are running as are resolved as early as possible.
+    INVOKING_USER.init()
     args, images = parse_config(sys.argv[1:])
 
     if args.debug:
index da3a3b5a02ad482161c4736d9e649007ac2e0491..a41cd4852b093fd378f43d16ed25490182bb169d 100644 (file)
@@ -219,7 +219,7 @@ def parse_path(value: str,
 
     if expanduser:
         if path.is_relative_to("~") and not INVOKING_USER.is_running_user():
-            path = INVOKING_USER.home / path.relative_to("~")
+            path = INVOKING_USER.home() / path.relative_to("~")
         path = path.expanduser()
 
     if required and not path.exists():
@@ -955,14 +955,14 @@ class MkosiConfig:
         # directory in /home as well as /home might be on a separate partition or subvolume which means that to take
         # advantage of reflinks and such, the workspace directory has to be on the same partition/subvolume.
         if (
-            Path.cwd().is_relative_to(INVOKING_USER.home) and
-            (INVOKING_USER.home / ".cache").exists() and
+            Path.cwd().is_relative_to(INVOKING_USER.home()) and
+            (INVOKING_USER.home() / ".cache").exists() and
             (
-                self.cache_dir and self.cache_dir.is_relative_to(INVOKING_USER.home) or
-                self.output_dir and self.output_dir.is_relative_to(INVOKING_USER.home)
+                self.cache_dir and self.cache_dir.is_relative_to(INVOKING_USER.home()) or
+                self.output_dir and self.output_dir.is_relative_to(INVOKING_USER.home())
             )
         ):
-            return INVOKING_USER.home / ".cache"
+            return INVOKING_USER.home() / ".cache"
 
         return Path("/var/tmp")
 
index ed0a740984d8ea9005e8c019d2cb871f0417573a..61e687790c69e43e68f10534b653f39de72f0256 100644 (file)
@@ -156,7 +156,7 @@ def mount_passwd(root: Path = Path("/")) -> Iterator[None]:
     with tempfile.NamedTemporaryFile(prefix="mkosi.passwd", mode="w") as passwd:
         passwd.write("root:x:0:0:root:/root:/bin/sh\n")
         if INVOKING_USER.uid != 0:
-            name = INVOKING_USER.name
+            name = INVOKING_USER.name()
             passwd.write(f"{name}:x:{INVOKING_USER.uid}:{INVOKING_USER.gid}:{name}:/home/{name}:/bin/sh\n")
         passwd.flush()
         os.fchown(passwd.file.fileno(), INVOKING_USER.uid, INVOKING_USER.gid)
index 6521e6b1369ba9a1458c867292e90aedd4335eca..64284974ebe821588eea5cb4d2b8c0f3d4ea1307 100644 (file)
@@ -77,14 +77,28 @@ def flatten(lists: Iterable[Iterable[T]]) -> list[T]:
 class INVOKING_USER:
     uid = int(os.getenv("SUDO_UID") or os.getenv("PKEXEC_UID") or os.getuid())
     gid = int(os.getenv("SUDO_GID") or os.getgid())
-    name = pwd.getpwuid(uid).pw_name
-    home = Path(f"~{name}").expanduser()
     invoked_as_root = (uid == 0)
 
+    @classmethod
+    def init(cls) -> None:
+        name = cls.name()
+        home = cls.home()
+        logging.debug(f"Running as user '{name}' ({cls.uid}:{cls.gid}) with home {home}.")
+
     @classmethod
     def is_running_user(cls) -> bool:
         return cls.uid == os.getuid()
 
+    @classmethod
+    @functools.lru_cache(maxsize=1)
+    def name(cls) -> str:
+        return pwd.getpwuid(cls.uid).pw_name
+
+    @classmethod
+    @functools.lru_cache(maxsize=1)
+    def home(cls) -> Path:
+        return Path(f"~{cls.name()}").expanduser()
+
 
 @contextlib.contextmanager
 def chdir(directory: PathString) -> Iterator[None]: