From 7ae4cd924ef7412ec17cfc129f24b962499de565 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Mon, 1 Apr 2024 18:02:07 +0200 Subject: [PATCH] Parse credentials from files/dirs during parsing instead of afterwards --- mkosi/config.py | 38 ++++++++++++++++++++++++-------------- mkosi/resources/mkosi.md | 14 +++++++++++--- 2 files changed, 35 insertions(+), 17 deletions(-) diff --git a/mkosi/config.py b/mkosi/config.py index 7df0a5d2f..aa8696957 100644 --- a/mkosi/config.py +++ b/mkosi/config.py @@ -794,6 +794,7 @@ def config_make_dict_parser(delimiter: str, *, parse: Callable[[str], tuple[str, Any]], unescape: bool = False, + allow_paths: bool = False, reset: bool = True) -> ConfigParseCallback: def config_parse_dict(value: Optional[str], old: Optional[dict[str, Any]]) -> Optional[dict[str, Any]]: new = old.copy() if old else {} @@ -801,6 +802,24 @@ def config_make_dict_parser(delimiter: str, if value is None: return {} + if allow_paths and "=" not in value: + if Path(value).is_dir(): + for p in Path(value).iterdir(): + if p.is_dir(): + continue + + if os.access(p, os.X_OK): + new[p.name] = run([p], stdout=subprocess.PIPE, env=os.environ).stdout + else: + new[p.name] = p.read_text() + elif (p := Path(value)).exists(): + if os.access(p, os.X_OK): + new[p.name] = run([p], stdout=subprocess.PIPE, env=os.environ).stdout + else: + new[p.name] = p.read_text() + else: + die(f"{p} does not exist") + if unescape: lex = shlex.shlex(value, posix=True) lex.whitespace_split = True @@ -2621,8 +2640,10 @@ SETTINGS = ( long="--credential", metavar="NAME=VALUE", section="Host", - parse=config_make_dict_parser(delimiter=" ", parse=parse_credential, unescape=True), + parse=config_make_dict_parser(delimiter=" ", parse=parse_credential, allow_paths=True, unescape=True), help="Pass a systemd credential to systemd-nspawn or qemu", + paths=("mkosi.credentials",), + path_default=False, ), ConfigSetting( dest="kernel_command_line_extra", @@ -3496,18 +3517,10 @@ def load_credentials(args: argparse.Namespace) -> dict[str, str]: creds = { "agetty.autologin": "root", "login.noauth": "yes", + "firstboot.locale": "C.UTF-8", + **args.credentials, } - d = Path("mkosi.credentials") - if args.directory is not None and d.is_dir(): - for e in d.iterdir(): - if os.access(e, os.X_OK): - creds[e.name] = run([e], stdout=subprocess.PIPE, env=os.environ).stdout - else: - creds[e.name] = e.read_text() - - creds |= args.credentials - if "firstboot.timezone" not in creds: if find_binary("timedatectl"): tz = run( @@ -3520,9 +3533,6 @@ def load_credentials(args: argparse.Namespace) -> dict[str, str]: creds["firstboot.timezone"] = tz - if "firstboot.locale" not in creds: - creds["firstboot.locale"] = "C.UTF-8" - if "ssh.authorized_keys.root" not in creds: if args.ssh_certificate: pubkey = run(["openssl", "x509", "-in", args.ssh_certificate, "-pubkey", "-noout"], diff --git a/mkosi/resources/mkosi.md b/mkosi/resources/mkosi.md index c7aac8a5e..f3e1d55ed 100644 --- a/mkosi/resources/mkosi.md +++ b/mkosi/resources/mkosi.md @@ -1636,9 +1636,17 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`, `Credentials=`, `--credential=` -: Set credentials to be passed to systemd-nspawn or qemu respectively when - `mkosi shell/boot` or `mkosi qemu` are used. This option takes a space separated - list of key=value assignments. +: Set credentials to be passed to systemd-nspawn or qemu respectively + when `mkosi shell/boot` or `mkosi qemu` are used. This option takes a + space separated list of values which can be either key=value pairs or + paths. If a path is provided, if it is a file, the credential name + will be the name of the file. If the file is executable, the + credential value will be the output of executing the file. Otherwise, + the credential value will be the contents of the file. If the path is + a directory, the same logic applies to each file in the directory. + +: Note that values will only be treated as paths if they do not contain + the delimiter (`=`). `KernelCommandLineExtra=`, `--kernel-command-line-extra=` -- 2.47.2