diff --git a/guest/README.md b/guest/README.md index 5825f2c9..c903fc51 100644 --- a/guest/README.md +++ b/guest/README.md @@ -62,6 +62,14 @@ direct-boot kernel and matching headers are held, while the packaged repository. A separate migration channel is required before those Try-Omarchy-specific revisions can advance on an existing disk without reset. +The factory includes the pinned upstream `omarchy-dns` and +`omarchy-theme-browser` sudoers drop-ins, owned by `try-omarchy-runtime` with +root ownership and mode `0440`. These grant wheel users passwordless access +only to the upstream DNS presets and browser theme-color helper, so those menu +actions do not fall back to a polkit password prompt. Other sudo operations +retain their existing password or opt-in Touch ID authentication. As with other +factory changes, replacing the Mac app does not add these files to an existing VM. + The default Tokyo Night wallpaper is seeded as a per-user background at `native-overlay/etc/skel/.config/omarchy/backgrounds/tokyo-night/try-omarchy-wallpaper.jpg`. Omarchy checks that directory before the packaged theme backgrounds during diff --git a/guest/scripts/finalize-rootfs.sh b/guest/scripts/finalize-rootfs.sh index 6b68895e..ecf6df5e 100755 --- a/guest/scripts/finalize-rootfs.sh +++ b/guest/scripts/finalize-rootfs.sh @@ -21,6 +21,20 @@ read_spec() { locale-gen passwd --lock root >/dev/null +# Check the effective sudoers policy and the package-owned menu grants before +# publishing an image. Materialization runs as root in the ARM64 builder. +visudo --check +for name in omarchy-dns omarchy-theme-browser; do + policy="/etc/sudoers.d/$name" + [[ $(stat -c '%u:%g:%a' "$policy") == 0:0:440 ]] || { + echo "Unsafe ownership or permissions on $policy" >&2 + exit 1 + } + [[ $(pacman -Qoq "$policy") == try-omarchy-runtime ]] || { + echo "Menu sudoers policy is not owned by the Omarchy runtime: $policy" >&2 + exit 1 + } +done systemctl enable NetworkManager.service systemctl enable systemd-resolved.service systemctl enable systemd-timesyncd.service diff --git a/guest/scripts/materialize-omarchy.sh b/guest/scripts/materialize-omarchy.sh index c985b678..cdd1ac96 100755 --- a/guest/scripts/materialize-omarchy.sh +++ b/guest/scripts/materialize-omarchy.sh @@ -192,6 +192,12 @@ install_file 0644 "$source_dir/etc/xdg/kitty/kitty.conf" "$root/etc/xdg/kitty/ki install_file 0644 "$source_dir/etc/tmpfiles.d/omarchy-nopasswd-sudo.conf" \ "$root/usr/lib/tmpfiles.d/omarchy-nopasswd-sudo.conf" +# Let the menu's DNS and browser-theme helpers use their narrowly scoped +# upstream passwordless grants instead of falling back to a polkit prompt. +for name in omarchy-dns omarchy-theme-browser; do + install_file 0440 "$source_dir/etc/sudoers.d/$name" "$root/etc/sudoers.d/$name" +done + # Preserve the application metadata and artwork used by Quickshell's real app # provider. Normalize display-style artwork names to the lowercase, hyphenated # icon identifiers used by the desktop files and accepted by GTK's icon cache. diff --git a/guest/scripts/register-omarchy-runtime.sh b/guest/scripts/register-omarchy-runtime.sh index abbaee1d..8a863138 100755 --- a/guest/scripts/register-omarchy-runtime.sh +++ b/guest/scripts/register-omarchy-runtime.sh @@ -114,6 +114,11 @@ for relative in etc/xdg/kitty/kitty.conf usr/lib/tmpfiles.d/omarchy-nopasswd-sud install -Dm0644 "$root/$relative" "$stage/$relative" done +# Keep the upstream menu helpers' scoped passwordless grants package-owned. +for name in omarchy-dns omarchy-theme-browser; do + install -Dm0440 "$root/etc/sudoers.d/$name" "$stage/etc/sudoers.d/$name" +done + # The VM-specific screensaver override is one of the packaged Omarchy commands # below. Keep its cursor-policy helper in the same package so reinstalling or # verifying the runtime cannot leave that command with an unowned dependency. diff --git a/guest/spec.json b/guest/spec.json index 8b02ac07..29f47854 100644 --- a/guest/spec.json +++ b/guest/spec.json @@ -512,6 +512,8 @@ "default/themed/shell.toml.tpl", "default/uwsm/env.d/10-omarchy", "default/wayland-sessions/omarchy.desktop", + "etc/sudoers.d/omarchy-dns", + "etc/sudoers.d/omarchy-theme-browser", "install/provisioning/omarchy-provision-owner.service", "install/provisioning/setup-form.sh", "install/user/all.sh", diff --git a/guest/tests/verify.py b/guest/tests/verify.py index 26786140..ff3d7ecb 100755 --- a/guest/tests/verify.py +++ b/guest/tests/verify.py @@ -1719,6 +1719,16 @@ def main() -> None: capture_output=True, ) staged_icons = staged_root / "usr/share/icons/hicolor/256x256/apps" + for name in ("omarchy-dns", "omarchy-theme-browser"): + relative = Path("etc/sudoers.d") / name + policy = staged_root / relative + check( + policy.is_file() + and not policy.is_symlink() + and policy.read_bytes() == (source / relative).read_bytes() + and stat.S_IMODE(policy.stat().st_mode) == 0o440, + f"menu sudoers policy preserves upstream grants with mode 0440: {name}", + ) for upstream_path, installed_path in ( ("etc/xdg/kitty/kitty.conf", "etc/xdg/kitty/kitty.conf"), ("etc/tmpfiles.d/omarchy-nopasswd-sudo.conf", "usr/lib/tmpfiles.d/omarchy-nopasswd-sudo.conf"),