Merge pull request #7972 from acrogenesis/harden-browser-policy-dirs

Stop world-writable browser policy directories
This commit is contained in:
Ryan Hughes
2026-08-28 18:00:20 -04:00
committed by GitHub
17 changed files with 968 additions and 49 deletions
+11 -17
View File
@@ -6,9 +6,10 @@
set -e
setup_policy_directory() {
sudo mkdir -p "$1"
sudo chmod a+rw "$1"
source "$OMARCHY_PATH/install/helpers/browser-policy.sh"
setup_chromium_policy_directory() {
browser_policy_setup_dir "$1"
}
announce_browser_installed() {
@@ -23,13 +24,6 @@ copy_chromium_flags() {
omarchy-install-chromium-ytdlp
}
setup_firefox_preferences() {
local distribution_dir="$1"
setup_policy_directory "$distribution_dir"
sudo cp -f "$OMARCHY_PATH/default/firefox/policies.json" "$distribution_dir/policies.json"
}
setup_firefox_wayland() {
mkdir -p ~/.config/environment.d
echo "MOZ_ENABLE_WAYLAND=1" > ~/.config/environment.d/omarchy-firefox-wayland.conf
@@ -40,7 +34,7 @@ chromium)
echo "Installing Chromium..."
omarchy-pkg-add chromium
setup_policy_directory /etc/chromium/policies/managed
setup_chromium_policy_directory /etc/chromium/policies/managed
copy_chromium_flags ~/.config/chromium-flags.conf
omarchy-theme-set-browser
announce_browser_installed "Chromium"
@@ -49,7 +43,7 @@ chrome)
echo "Installing Chrome..."
omarchy-pkg-aur-add google-chrome || exit 1
setup_policy_directory /etc/opt/chrome/policies/managed
setup_chromium_policy_directory /etc/opt/chrome/policies/managed
copy_chromium_flags ~/.config/chrome-flags.conf
omarchy-theme-set-browser
announce_browser_installed "Chrome"
@@ -58,7 +52,7 @@ edge)
echo "Installing Edge..."
omarchy-pkg-aur-add microsoft-edge-stable-bin || exit 1
setup_policy_directory /etc/opt/edge/policies/managed
setup_chromium_policy_directory /etc/opt/edge/policies/managed
copy_chromium_flags ~/.config/microsoft-edge-stable-flags.conf
omarchy-theme-set-browser
announce_browser_installed "Edge"
@@ -67,7 +61,7 @@ brave)
echo "Installing Brave..."
omarchy-pkg-aur-add brave-bin || exit 1
setup_policy_directory /etc/brave/policies/managed
setup_chromium_policy_directory /etc/brave/policies/managed
copy_chromium_flags ~/.config/brave-flags.conf
omarchy-theme-set-browser
announce_browser_installed "Brave"
@@ -76,7 +70,7 @@ brave-origin)
echo "Installing Brave Origin..."
omarchy-pkg-aur-add brave-origin-bin || exit 1
setup_policy_directory /etc/brave/policies/managed
setup_chromium_policy_directory /etc/brave/policies/managed
copy_chromium_flags ~/.config/brave-origin-flags.conf
omarchy-theme-set-browser
announce_browser_installed "Brave Origin"
@@ -85,7 +79,7 @@ firefox)
echo "Installing Firefox..."
omarchy-pkg-add firefox || exit 1
setup_firefox_preferences /usr/lib/firefox/distribution
browser_policy_setup_firefox_distribution /usr/lib/firefox/distribution
setup_firefox_wayland
announce_browser_installed "Firefox"
;;
@@ -93,7 +87,7 @@ zen)
echo "Installing Zen..."
omarchy-pkg-aur-add zen-browser-bin || exit 1
setup_firefox_preferences /opt/zen-browser/distribution
browser_policy_setup_firefox_distribution /opt/zen-browser/distribution
setup_firefox_wayland
announce_browser_installed "Zen"
;;
+6
View File
@@ -742,6 +742,12 @@ create_user() {
# for specific commands), and a duplicate grant is harmless.
echo "%wheel ALL=(ALL:ALL) ALL" >/etc/sudoers.d/00-omarchy-wheel
chmod 440 /etc/sudoers.d/00-omarchy-wheel
source "$OMARCHY_PATH/install/helpers/browser-policy.sh"
for dir in "${BROWSER_POLICY_MANAGED_DIRS[@]}"; do
[[ -d $dir || -L $dir ]] || continue
browser_policy_setup_dir "$dir"
done
}
install_authorized_keys() {
+9 -19
View File
@@ -3,23 +3,15 @@
# omarchy:summary=Apply the current theme color to Chromium, Chrome, Edge, and Brave
# omarchy:hidden=true
source "$OMARCHY_PATH/install/helpers/browser-policy.sh"
CHROMIUM_THEME=$HOME/.local/state/omarchy/current/theme/chromium.theme
THEME_HEX_COLOR=$BROWSER_POLICY_DEFAULT_COLOR
if [[ -f $CHROMIUM_THEME ]]; then
THEME_RGB_COLOR=$(<$CHROMIUM_THEME)
THEME_HEX_COLOR=$(printf '#%02x%02x%02x' ${THEME_RGB_COLOR//,/ })
else
# Use a default, neutral grey if theme doesn't have a color
THEME_HEX_COLOR="#1c2027"
THEME_HEX_COLOR=$(browser_policy_theme_hex "$(<$CHROMIUM_THEME)")
fi
set_browser_policy() {
local policy_dir="$1"
[[ -d $policy_dir ]] || return
echo "{\"BrowserThemeColor\": \"$THEME_HEX_COLOR\", \"BrowserColorScheme\": \"device\"}" | tee "$policy_dir/color.json" >/dev/null
}
refresh_running_browser() {
local process="$1"
local command="$2"
@@ -30,17 +22,15 @@ refresh_running_browser() {
fi
}
set_browser_policy /etc/chromium/policies/managed
failed=0
omarchy-theme-set-browser-policy "${THEME_HEX_COLOR#\#}" || failed=1
refresh_running_browser chromium chromium
set_browser_policy /etc/opt/chrome/policies/managed
refresh_running_browser chrome google-chrome-stable || refresh_running_browser chrome google-chrome
set_browser_policy /etc/opt/edge/policies/managed
refresh_running_browser msedge microsoft-edge-stable
set_browser_policy /etc/brave/policies/managed
refresh_running_browser brave brave
# Match on the binary path: the running process is named plain "brave", and a
# bare -f brave-origin pattern would also match the installer's own terminal.
refresh_running_browser /opt/brave-origin-bin/ brave-origin -f
exit "$failed"
+118
View File
@@ -0,0 +1,118 @@
#!/bin/bash
# omarchy:summary=Write the current theme color into the browser policy directories
# omarchy:args=<rrggbb>
# omarchy:hidden=true
set -euo pipefail
# Whenever this runs as root — invoked directly through the passwordless
# sudoers rule, or re-execed by require_root below — sudo's secure_path decides
# where a bare helper resolves, and a dev link (etc/sudoers.d/omarchy-dev-path)
# prepends a user-writable checkout bin/ to it. Every helper this script calls
# by bare name (printf's builtin aside: install, mktemp, rm) is a system tool,
# never an omarchy-* command, so pin PATH to trusted system directories and keep
# root from resolving one out of that checkout. The unprivileged wrapper phase
# keeps the caller's PATH so it can still find sudo/pkexec.
if (( EUID == 0 )); then
export PATH=/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/sbin:/bin:/sbin
fi
# Enterprise policy trust roots. The list is fixed here rather than taken from
# the caller: the caller chooses a color, never a path.
POLICY_DIRS=(
/etc/chromium/policies/managed
/etc/opt/chrome/policies/managed
/etc/opt/edge/policies/managed
/etc/brave/policies/managed
)
# The path etc/sudoers.d/omarchy-theme-browser names. The privileged half always
# runs from there rather than from whichever copy was invoked, so the rule
# matches even where $OMARCHY_PATH points at a checkout.
PACKAGED_PATH=/usr/bin/omarchy-theme-set-browser-policy
usage() {
echo "Usage: omarchy-theme-set-browser-policy <rrggbb>" >&2
}
if (( $# != 1 )); then
usage
exit 1
fi
color="$1"
# Six lowercase hex digits is the whole of what this accepts. The leading "#"
# is added when the JSON is written rather than passed in: "#" opens a comment
# in sudoers, and keeping it out of argv lets the sudoers rule spell the
# argument as a plain six-character glob.
if [[ ! $color =~ ^[0-9a-f]{6}$ ]]; then
echo "omarchy-theme-set-browser-policy: expected six lowercase hex digits, got '$color'" >&2
exit 1
fi
# True when sudo would run this exact command without stopping for a password.
# `sudo -l` on its own reports whether a command is permitted, which the blanket
# %wheel rule answers yes to for everything; the long listing prints the matched
# entry's tags, so !authenticate is the grant in
# etc/sudoers.d/omarchy-theme-browser and nothing else. Listing runs nothing
# and, under -n, prompts for nothing.
sudo_grants_passwordless() {
sudo -n -l -l "$PACKAGED_PATH" "$@" 2>/dev/null | grep -q '!authenticate'
}
require_root() {
if (( EUID == 0 )); then
return
elif [[ -t 0 ]] || sudo_grants_passwordless "$@"; then
exec sudo "$PACKAGED_PATH" "$@"
else
exec pkexec "$PACKAGED_PATH" "$@"
fi
}
require_root "$color"
failed=0
staged=""
cleanup() {
[[ -n $staged ]] && rm -f "$staged"
}
trap cleanup EXIT
for policy_dir in "${POLICY_DIRS[@]}"; do
# Only browsers Omarchy has installed have a policy directory. Creating one
# here would hand a browser a managed-policy root it does not otherwise have.
[[ -d $policy_dir && ! -L $policy_dir ]] || continue
dest=$policy_dir/color.json
staged=$(mktemp) || {
failed=1
continue
}
printf '{"BrowserThemeColor": "#%s", "BrowserColorScheme": "device"}\n' "$color" >"$staged"
if [[ -L $dest || -d $dest ]]; then
if ! rm -rf -- "$dest"; then
rm -f "$staged"
staged=""
echo "omarchy-theme-set-browser-policy: cannot replace $dest" >&2
failed=1
continue
fi
fi
if ! install -m 0644 -o root -g root -T "$staged" "$dest"; then
rm -f "$staged"
staged=""
echo "omarchy-theme-set-browser-policy: cannot write $dest" >&2
failed=1
continue
fi
rm -f "$staged"
staged=""
done
exit "$failed"
+20 -1
View File
@@ -1312,7 +1312,21 @@ apply_system_transition() {
/usr/share/icons/Yaru/scalable/actions/go-next-symbolic.svg
as_root gtk-update-icon-cache /usr/share/icons/Yaru >/dev/null 2>&1 || true
as_root install -d -m 0777 /etc/chromium/policies/managed
local browser_policy_helper=/usr/share/omarchy/install/helpers/browser-policy.sh
if ! as_root test -f "$browser_policy_helper"; then
warn "$browser_policy_helper is unavailable; Chromium policy directories were not hardened."
else
as_root env OMARCHY_PATH=/usr/share/omarchy \
bash -euo pipefail -c '
source "$OMARCHY_PATH/install/helpers/browser-policy.sh"
browser_policy_setup_dir /etc/chromium/policies/managed
for dir in "${BROWSER_POLICY_MANAGED_DIRS[@]}"; do
[[ $dir == "/etc/chromium/policies/managed" ]] && continue
[[ -d $dir || -L $dir ]] || continue
browser_policy_setup_dir "$dir"
done
'
fi
as_root install -d -m 0755 /usr/lib/chromium
printf '%s\n' '{"browser":{"theme":{"color_scheme":0,"color_scheme2":0}}}' | \
as_root tee /usr/lib/chromium/initial_preferences >/dev/null
@@ -2306,6 +2320,11 @@ refresh_current_theme_after_upgrade() {
# hooks because one of them runs `hyprctl reload`. Still poke terminal
# emulators so the active upgrade terminal picks up generated theme files.
run_as_user_omarchy omarchy-restart-terminal >/dev/null 2>&1 || true
# apply_system_transition purged user-owned color.json. Headless theme-set
# skipped omarchy-theme-set-browser, so rewrite the colour here.
run_as_user_omarchy omarchy-theme-set-browser >/dev/null 2>&1 ||
warn "Could not apply browser theme colour. Run 'omarchy theme set \"$theme_name\"' after reboot if Chromium's theme looks stale."
}
# Everything below mutates the system, so a non-zero exit from here on leaves a
+8
View File
@@ -0,0 +1,8 @@
# Theme switching is a menu action with no terminal to carry a password prompt,
# and it repaints the browser accent on every switch, so this one write must not
# stop for a password. The argument is spelled out as six hex digits rather than
# a wildcard: the grant covers a color and nothing else, and sudoers matches a
# command's arguments exactly, so it cannot be stretched into extra ones. The
# helper revalidates the same shape, since the terminal path does not come
# through this rule.
%wheel ALL=(root) NOPASSWD: /usr/bin/omarchy-theme-set-browser-policy [0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]
+1
View File
@@ -1,4 +1,5 @@
run_logged "$OMARCHY_INSTALL/config/theme-system.sh"
run_logged "$OMARCHY_INSTALL/config/browser-policy.sh"
run_logged "$OMARCHY_INSTALL/config/increase-lockout-limit.sh"
run_logged "$OMARCHY_INSTALL/config/lockscreen-pam.sh"
run_logged "$OMARCHY_INSTALL/config/fix-powerprofilesctl-shebang.sh"
+2
View File
@@ -0,0 +1,2 @@
source "$OMARCHY_PATH/install/helpers/browser-policy.sh"
browser_policy_setup_dir /etc/chromium/policies/managed
-4
View File
@@ -6,10 +6,6 @@ ln -snf /usr/share/icons/Adwaita/symbolic/actions/go-next-symbolic.svg \
/usr/share/icons/Yaru/scalable/actions/go-next-symbolic.svg
gtk-update-icon-cache /usr/share/icons/Yaru &>/dev/null || true
# Chromium policy directory for theme
mkdir -p /etc/chromium/policies/managed
chmod a+rw /etc/chromium/policies/managed
# Default Chromium to follow system appearance ("device") instead of dark
mkdir -p /usr/lib/chromium
echo '{"browser":{"theme":{"color_scheme":0,"color_scheme2":0}}}' > \
+7
View File
@@ -0,0 +1,7 @@
as_root() {
if (( EUID == 0 )); then
"$@"
else
sudo "$@"
fi
}
+168
View File
@@ -0,0 +1,168 @@
# Chromium-family machine policy is mandatory for every profile. Directories
# stay 0755 root:root; omarchy-theme-set-browser-policy is the privileged
# write for color.json.
source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/as-root.sh"
BROWSER_POLICY_MANAGED_DIRS=(
/etc/chromium/policies/managed
/etc/opt/chrome/policies/managed
/etc/opt/edge/policies/managed
/etc/brave/policies/managed
)
# Ancestors of the managed dirs, shortest first. A writable or attacker-owned
# parent can rename the leaf aside; install -d follows a planted symlink.
BROWSER_POLICY_PARENT_DIRS=(
/etc/chromium
/etc/chromium/policies
/etc/opt/chrome
/etc/opt/chrome/policies
/etc/opt/edge
/etc/opt/edge/policies
/etc/brave
/etc/brave/policies
)
BROWSER_POLICY_FIREFOX_DIRS=(
/usr/lib/firefox/distribution
/opt/zen-browser/distribution
)
BROWSER_POLICY_DEFAULT_COLOR="#1c2027"
browser_policy_purge_dir() {
local dir=$1
as_root find "$dir" -mindepth 1 -maxdepth 1 ! -user root -exec rm -rf -- {} +
}
browser_policy_parent_hardened() {
local dir=$1
[[ -d $dir && ! -L $dir ]] || return 1
[[ $(stat -c '%a' "$dir") == "755" ]] || return 1
[[ $(stat -c '%U' "$dir") == "root" ]] || return 1
}
browser_policy_dir_hardened() {
browser_policy_parent_hardened "$1"
}
browser_policy_parents_hardened() {
local dir=$1
local parent
for parent in "${BROWSER_POLICY_PARENT_DIRS[@]}"; do
[[ $dir == "$parent"/* ]] || continue
[[ -e $parent || -L $parent ]] || continue
browser_policy_parent_hardened "$parent" || return 1
done
}
browser_policy_setup_parent() {
local dir=$1
if [[ -L $dir || ( -e $dir && ! -d $dir ) ]]; then
as_root rm -rf -- "$dir"
fi
as_root install -d -m 0755 -o root -g root "$dir"
}
browser_policy_setup_parents_for() {
local dir=$1
local parent
for parent in "${BROWSER_POLICY_PARENT_DIRS[@]}"; do
[[ $dir == "$parent"/* ]] || continue
browser_policy_setup_parent "$parent"
done
}
browser_policy_setup_dir() {
local dir=$1
browser_policy_setup_parents_for "$dir"
browser_policy_setup_parent "$dir"
browser_policy_purge_dir "$dir"
}
# Themes are user-installed. Accept only three 0-255 components.
browser_policy_theme_hex() {
local theme_rgb=$1
if [[ $theme_rgb =~ ^[[:space:]]*([0-9]{1,3})[[:space:]]*,[[:space:]]*([0-9]{1,3})[[:space:]]*,[[:space:]]*([0-9]{1,3})[[:space:]]*$ ]] &&
(( 10#${BASH_REMATCH[1]} < 256 && 10#${BASH_REMATCH[2]} < 256 && 10#${BASH_REMATCH[3]} < 256 )); then
printf '#%02x%02x%02x' "$((10#${BASH_REMATCH[1]}))" "$((10#${BASH_REMATCH[2]}))" "$((10#${BASH_REMATCH[3]}))"
return
fi
printf '%s' "$BROWSER_POLICY_DEFAULT_COLOR"
}
browser_policy_install_color() {
local policy_dir=$1
local hex=$2
local dest=$policy_dir/color.json
local tmp
[[ -d $policy_dir && ! -L $policy_dir ]] || return 0
[[ $hex =~ ^#[0-9a-f]{6}$ ]] || return 1
tmp=$(mktemp) || return 1
printf '{"BrowserThemeColor": "%s", "BrowserColorScheme": "device"}\n' "$hex" >"$tmp"
if [[ -L $dest || -d $dest ]]; then
if ! rm -rf -- "$dest" 2>/dev/null; then
rm -f "$tmp"
return 1
fi
fi
if install -m 0644 -T "$tmp" "$dest" 2>/dev/null; then
rm -f "$tmp"
return 0
fi
rm -f "$tmp"
return 1
}
browser_policy_firefox_policy_file_ok() {
local file=$1
local mode
local group_write
local other_write
[[ -f $file && ! -L $file ]] || return 1
[[ $(stat -c '%U' "$file") == "root" ]] || return 1
mode=$(stat -c '%a' "$file")
group_write=$((8#${mode: -2:1}))
other_write=$((8#${mode: -1}))
(( (group_write & 2) == 0 && (other_write & 2) == 0 ))
}
browser_policy_firefox_hardened() {
local dir=$1
[[ -d $dir && ! -L $dir ]] || return 1
[[ $(stat -c '%a' "$dir") == "755" ]] || return 1
[[ $(stat -c '%U' "$dir") == "root" ]] || return 1
browser_policy_firefox_policy_file_ok "$dir/policies.json"
}
browser_policy_install_firefox_policies() {
local distribution_dir=$1
local policies=${2:-$OMARCHY_PATH/default/firefox/policies.json}
as_root install -m 644 -o root -g root -T "$policies" "$distribution_dir/policies.json"
}
browser_policy_setup_firefox_distribution() {
local distribution_dir=$1
local policies=${2:-$OMARCHY_PATH/default/firefox/policies.json}
browser_policy_setup_parent "$distribution_dir"
browser_policy_purge_dir "$distribution_dir"
browser_policy_install_firefox_policies "$distribution_dir" "$policies"
}
+27
View File
@@ -0,0 +1,27 @@
echo "Stop world-writable Chromium and Firefox policy directories"
source "$OMARCHY_PATH/install/helpers/browser-policy.sh"
repaired=0
for dir in "${BROWSER_POLICY_MANAGED_DIRS[@]}"; do
[[ -d $dir || -L $dir ]] || continue
browser_policy_setup_dir "$dir"
repaired=1
done
if (( repaired )); then
omarchy-theme-set-browser
fi
for dir in "${BROWSER_POLICY_FIREFOX_DIRS[@]}"; do
[[ -d $dir || -L $dir ]] || continue
if browser_policy_firefox_hardened "$dir"; then
browser_policy_purge_dir "$dir"
continue
fi
browser_policy_setup_parent "$dir"
browser_policy_purge_dir "$dir"
if ! browser_policy_firefox_policy_file_ok "$dir/policies.json"; then
browser_policy_install_firefox_policies "$dir"
fi
done
+311
View File
@@ -0,0 +1,311 @@
#!/bin/bash
set -euo pipefail
source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh"
test_tmp=$(mktemp -d)
trap 'rm -rf "$test_tmp"' EXIT
export OMARCHY_PATH="$ROOT"
export OMARCHY_PROVISIONING_DIR="$test_tmp/provisioning"
source "$ROOT/install/helpers/browser-policy.sh"
# Temp dirs are user-owned; drop -o/-g so install(1) can run unprivileged.
unprivileged_as_root() {
if [[ $1 == "install" ]]; then
shift
local args=()
local skip=0
local arg
for arg in "$@"; do
if (( skip )); then
skip=0
continue
fi
case $arg in
-o|-g) skip=1 ;;
*) args+=("$arg") ;;
esac
done
command install "${args[@]}"
else
"$@"
fi
}
write_dir=$test_tmp/writable
mkdir -p "$write_dir"
browser_policy_install_color "$write_dir" "#aabbcc" ||
fail "theme colour writes into a writable policy directory"
grep -F '"BrowserThemeColor": "#aabbcc"' "$write_dir/color.json" >/dev/null ||
fail "theme colour writes BrowserThemeColor"
mode=$(stat -c '%a' "$write_dir/color.json")
[[ $mode == "644" ]] || fail "theme colour creates a root-mode policy file" "mode=$mode"
pass "theme colour writes a 0644 color.json"
if (( EUID == 0 )); then
pass "running as root; skipping the mktemp-failure check"
else
chmod u+w "$write_dir"
export TMPDIR=$test_tmp/missing-tmp
if browser_policy_install_color "$write_dir" "#dead00" 2>/dev/null; then
fail "theme colour fails when mktemp cannot create a file"
fi
unset TMPDIR
grep -F '"BrowserThemeColor": "#aabbcc"' "$write_dir/color.json" >/dev/null ||
fail "a failed mktemp leaves an existing color.json intact"
pass "a failed mktemp does not truncate color.json"
fi
printf 'original\n' >"$test_tmp/pwn"
rm -f "$write_dir/color.json"
ln -s "$test_tmp/pwn" "$write_dir/color.json"
browser_policy_install_color "$write_dir" "#aabbcc" ||
fail "theme colour replaces a planted color.json symlink"
[[ -f $write_dir/color.json && ! -L $write_dir/color.json ]] ||
fail "theme colour unlinks a planted color.json symlink instead of writing through it"
grep -Fxq 'original' "$test_tmp/pwn" || fail "theme colour leaves the symlink target unchanged"
pass "theme colour does not follow a planted color.json symlink"
plant_write=$test_tmp/plant-dir
mkdir -p "$plant_write/color.json/nested"
printf 'inside\n' >"$plant_write/color.json/nested/x"
browser_policy_install_color "$plant_write" "#aabbcc" ||
fail "theme colour replaces a planted color.json directory"
[[ -f $plant_write/color.json && ! -d $plant_write/color.json ]] ||
fail "theme colour does not write into a planted color.json directory"
pass "theme colour does not write into a planted color.json directory"
missing_dir=$test_tmp/missing
browser_policy_install_color "$missing_dir" "#aabbcc" ||
fail "theme colour skips a policy directory that does not exist"
[[ ! -e $missing_dir ]] || fail "theme colour does not create a missing policy directory"
pass "theme colour skips a missing policy directory"
if browser_policy_install_color "$write_dir" "aabbcc" 2>/dev/null; then
fail "theme colour rejects hex without a leading #"
fi
if browser_policy_install_color "$write_dir" "#AABBCC" 2>/dev/null; then
fail "theme colour rejects uppercase hex"
fi
pass "theme colour accepts only # plus six lowercase hex digits"
planted_dir=$test_tmp/planted
mkdir -p "$planted_dir/evil"
printf 'evil\n' >"$planted_dir/evil/f"
printf 'old\n' >"$planted_dir/color.json"
as_root() { unprivileged_as_root "$@"; }
browser_policy_setup_dir "$planted_dir"
[[ ! -e $planted_dir/evil ]] || fail "policy setup drops a non-empty non-root subdirectory"
[[ ! -e $planted_dir/color.json ]] || fail "policy setup drops a non-root color.json"
[[ -d $planted_dir ]] || fail "policy setup leaves the managed directory in place"
mode=$(stat -c '%a' "$planted_dir")
[[ $mode == "755" ]] || fail "policy setup leaves the managed directory 0755" "mode=$mode"
pass "policy setup drops non-root files and non-empty subdirectories"
owned=$test_tmp/not-root
mkdir -p "$owned"
chmod 755 "$owned"
if browser_policy_dir_hardened "$owned"; then
fail "a user-owned 0755 directory is not treated as hardened"
fi
pass "a hardened directory must be root-owned"
saved_parent_dirs=("${BROWSER_POLICY_PARENT_DIRS[@]}")
parent_root=$test_tmp/parents
mkdir -p "$parent_root/etc/chromium/policies/managed/keep"
printf 'keep\n' >"$parent_root/etc/chromium/policies/managed/keep/x"
chmod 0777 "$parent_root/etc/chromium" "$parent_root/etc/chromium/policies"
chmod 755 "$parent_root/etc/chromium/policies/managed"
BROWSER_POLICY_PARENT_DIRS=(
"$parent_root/etc/chromium"
"$parent_root/etc/chromium/policies"
)
as_root() { unprivileged_as_root "$@"; }
if browser_policy_parents_hardened "$parent_root/etc/chromium/policies/managed"; then
fail "a world-writable policy parent is not treated as hardened"
fi
browser_policy_setup_parents_for "$parent_root/etc/chromium/policies/managed"
mode=$(stat -c '%a' "$parent_root/etc/chromium")
[[ $mode == "755" ]] || fail "setup tightens /etc/chromium" "mode=$mode"
mode=$(stat -c '%a' "$parent_root/etc/chromium/policies")
[[ $mode == "755" ]] || fail "setup tightens /etc/chromium/policies" "mode=$mode"
[[ -d $parent_root/etc/chromium/policies/managed/keep ]] ||
fail "parent repair does not purge the managed directory"
pass "policy parent directories are tightened to 0755 without purging the leaf"
symlink_root=$test_tmp/symlink-parents
mkdir -p "$symlink_root/etc" "$symlink_root/attacker/policies/managed"
printf 'planted\n' >"$symlink_root/attacker/policies/managed/evil.json"
ln -s "$symlink_root/attacker" "$symlink_root/etc/chromium"
BROWSER_POLICY_PARENT_DIRS=(
"$symlink_root/etc/chromium"
"$symlink_root/etc/chromium/policies"
)
as_root() { unprivileged_as_root "$@"; }
browser_policy_setup_dir "$symlink_root/etc/chromium/policies/managed"
[[ ! -L $symlink_root/etc/chromium ]] || fail "setup replaces a planted /etc/chromium symlink"
[[ -d $symlink_root/etc/chromium && ! -L $symlink_root/etc/chromium ]] ||
fail "setup recreates /etc/chromium as a real directory"
[[ -d $symlink_root/etc/chromium/policies && ! -L $symlink_root/etc/chromium/policies ]] ||
fail "setup recreates /etc/chromium/policies as a real directory"
[[ ! -e $symlink_root/etc/chromium/policies/managed/evil.json ]] ||
fail "setup does not keep policy that lived behind a planted parent symlink"
grep -Fxq 'planted' "$symlink_root/attacker/policies/managed/evil.json" ||
fail "replacing a parent symlink does not delete the symlink target"
BROWSER_POLICY_PARENT_DIRS=("${saved_parent_dirs[@]}")
pass "policy setup does not follow a planted parent symlink"
leaf_link_root=$test_tmp/leaf-link
mkdir -p "$leaf_link_root/etc/chromium/policies" "$leaf_link_root/attacker"
printf 'planted\n' >"$leaf_link_root/attacker/evil.json"
chmod 755 "$leaf_link_root/etc/chromium" "$leaf_link_root/etc/chromium/policies"
ln -s "$leaf_link_root/attacker" "$leaf_link_root/etc/chromium/policies/managed"
BROWSER_POLICY_PARENT_DIRS=(
"$leaf_link_root/etc/chromium"
"$leaf_link_root/etc/chromium/policies"
)
as_root() { unprivileged_as_root "$@"; }
if browser_policy_dir_hardened "$leaf_link_root/etc/chromium/policies/managed"; then
fail "a planted managed symlink is not treated as hardened"
fi
browser_policy_setup_dir "$leaf_link_root/etc/chromium/policies/managed"
[[ ! -L $leaf_link_root/etc/chromium/policies/managed ]] ||
fail "setup replaces a planted managed symlink"
[[ -d $leaf_link_root/etc/chromium/policies/managed && ! -L $leaf_link_root/etc/chromium/policies/managed ]] ||
fail "setup recreates managed as a real directory"
[[ ! -e $leaf_link_root/etc/chromium/policies/managed/evil.json ]] ||
fail "setup does not keep policy that lived behind a planted managed symlink"
grep -Fxq 'planted' "$leaf_link_root/attacker/evil.json" ||
fail "replacing a managed symlink does not delete the symlink target"
BROWSER_POLICY_PARENT_DIRS=("${saved_parent_dirs[@]}")
pass "policy setup does not follow a planted managed symlink"
fx_link_root=$test_tmp/fx-link
mkdir -p "$fx_link_root/attacker" "$fx_link_root/opt"
printf 'planted\n' >"$fx_link_root/attacker/policies.json"
ln -s "$fx_link_root/attacker" "$fx_link_root/opt/zen"
as_root() { unprivileged_as_root "$@"; }
if browser_policy_firefox_hardened "$fx_link_root/opt/zen"; then
fail "a planted Firefox distribution symlink is not treated as hardened"
fi
browser_policy_setup_firefox_distribution "$fx_link_root/opt/zen" ||
fail "Firefox setup replaces a planted distribution symlink"
[[ ! -L $fx_link_root/opt/zen ]] || fail "Firefox setup unlinks a planted distribution symlink"
[[ -d $fx_link_root/opt/zen && ! -L $fx_link_root/opt/zen ]] ||
fail "Firefox setup recreates the distribution directory"
[[ -f $fx_link_root/opt/zen/policies.json && ! -L $fx_link_root/opt/zen/policies.json ]] ||
fail "Firefox setup writes policies.json into the recreated directory"
grep -Fxq 'planted' "$fx_link_root/attacker/policies.json" ||
fail "replacing a Firefox distribution symlink does not delete the symlink target"
pass "Firefox setup does not follow a planted distribution symlink"
[[ $(browser_policy_theme_hex "242,240,229") == "#f2f0e5" ]] ||
fail "theme colour converts an RGB triple to hex"
[[ $(browser_policy_theme_hex $'14,31,41\n') == "#0e1f29" ]] ||
fail "theme colour accepts a trailing newline"
[[ $(browser_policy_theme_hex "0,0,0") == "#000000" ]] ||
fail "theme colour pads single-digit components"
[[ $(browser_policy_theme_hex " 12 , 11 , 12 ") == "#0c0b0c" ]] ||
fail "theme colour tolerates surrounding whitespace"
[[ $(browser_policy_theme_hex "08,09,10") == "#08090a" ]] ||
fail "theme colour treats leading zeros as decimal"
for malformed in "" "not,a,color" "1,2" "1,2,3,4" "256,0,0" "999,999,999" "-1,0,0" \
"1,2,3;id" '1,2,$(id)' "0x10,0,0" "1,2,3 4,5,6"; do
[[ $(browser_policy_theme_hex "$malformed") == "#1c2027" ]] ||
fail "theme colour falls back to the stock grey for '$malformed'"
done
pass "theme colour is six hex digits or the stock grey"
for theme in "$ROOT"/themes/*/chromium.theme; do
[[ -f $theme ]] || continue
rgb=$(<$theme)
hex=$(browser_policy_theme_hex "$rgb")
[[ $hex =~ ^#[0-9a-f]{6}$ ]] ||
fail "shipped $(basename "$(dirname "$theme")") chromium.theme parses as hex" "got: $hex from $(printf %q "$rgb")"
if [[ $hex == "#1c2027" && ! $rgb =~ ^[[:space:]]*28[[:space:]]*,[[:space:]]*32[[:space:]]*,[[:space:]]*39[[:space:]]*$ ]]; then
fail "shipped $(basename "$(dirname "$theme")") chromium.theme is a valid RGB triple" "got: $(printf %q "$rgb")"
fi
done
pass "shipped chromium.theme files parse as RGB triples"
grep -F 'browser_policy_theme_hex' "$ROOT/bin/omarchy-theme-set-browser" >/dev/null ||
fail "omarchy-theme-set-browser parses chromium.theme through browser_policy_theme_hex"
grep -F 'omarchy-theme-set-browser-policy' "$ROOT/bin/omarchy-theme-set-browser" >/dev/null ||
fail "omarchy-theme-set-browser writes colour through omarchy-theme-set-browser-policy"
if grep -E 'printf.*THEME_RGB_COLOR' "$ROOT/bin/omarchy-theme-set-browser" >/dev/null; then
fail "omarchy-theme-set-browser does not hand unvetted theme words to printf"
fi
pass "omarchy-theme-set-browser validates the theme colour"
fx_policy=$test_tmp/policies.json
printf '%s\n' '{"policies":{}}' >"$fx_policy"
chmod 644 "$fx_policy"
if browser_policy_firefox_policy_file_ok "$fx_policy"; then
fail "a user-owned policies.json is not treated as hardened"
fi
ln -sf "$fx_policy" "$test_tmp/policies-link.json"
if browser_policy_firefox_policy_file_ok "$test_tmp/policies-link.json"; then
fail "a policies.json symlink is not treated as hardened"
fi
pass "Firefox policy files must be root-owned regular files without group or other write"
dist=$test_tmp/distribution
mkdir -p "$dist"
printf 'original\n' >"$test_tmp/firefox-pwn"
ln -s "$test_tmp/firefox-pwn" "$dist/policies.json"
as_root() { unprivileged_as_root "$@"; }
browser_policy_install_firefox_policies "$dist" ||
fail "Firefox policy install replaces a planted policies.json symlink"
[[ -f $dist/policies.json && ! -L $dist/policies.json ]] ||
fail "Firefox policy install unlinks a planted policies.json symlink instead of writing through it"
grep -Fxq 'original' "$test_tmp/firefox-pwn" || fail "Firefox policy install leaves the symlink target unchanged"
grep -q '"policies"' "$dist/policies.json" || fail "Firefox policy install writes the stock policies"
pass "Firefox policy install does not follow a planted policies.json symlink"
dir_dist=$test_tmp/distribution-dir
mkdir -p "$dir_dist"
mkdir "$dir_dist/policies.json"
as_root() { unprivileged_as_root "$@"; }
if browser_policy_install_firefox_policies "$dir_dist" 2>/dev/null; then
fail "Firefox policy install refuses a planted policies.json directory"
fi
[[ -d $dir_dist/policies.json ]] || fail "Firefox policy install leaves a planted policies.json directory in place"
pass "Firefox policy install does not write into a planted policies.json directory"
grep -F 'exit "$failed"' "$ROOT/bin/omarchy-theme-set-browser" >/dev/null ||
fail "omarchy-theme-set-browser exits non-zero when a policy write fails"
pass "omarchy-theme-set-browser exits non-zero when a policy write fails"
policy_files=(
"$ROOT/bin/omarchy-install-browser"
"$ROOT/bin/omarchy-provision-owner"
"$ROOT/bin/omarchy-theme-set-browser"
"$ROOT/bin/omarchy-theme-set-browser-policy"
"$ROOT/bin/omarchy-upgrade-to-quattro"
"$ROOT/install/config/theme-system.sh"
"$ROOT/install/config/browser-policy.sh"
"$ROOT/install/helpers/browser-policy.sh"
"$ROOT/migrations/1787515927.sh"
)
if grep -nE 'chmod a\+rwx\b|chmod a\+rw\b|chmod a\+w\b|chmod o\+w|chmod ugo\+w|chmod 2775\b|chmod 2777\b|chmod 0777\b|chmod 777\b|install -d -m 0?[27]?777|omarchy-browser-policy' "${policy_files[@]}" >/dev/null; then
fail "browser policy setup is not world-writable and does not use omarchy-browser-policy"
fi
pass "browser policy setup is not world-writable"
mapfile -t migrations < <(rg -l 'Stop world-writable Chromium and Firefox policy directories' "$ROOT/migrations")
(( ${#migrations[@]} == 1 )) || fail "exactly one migration locks existing policy directories" "${migrations[*]}"
grep -F 'browser_policy_setup_dir' "${migrations[0]}" >/dev/null ||
fail "the policy-directory migration repairs managed directories"
if grep -F 'browser_policy_grant_user' "${migrations[0]}" >/dev/null; then
fail "the policy-directory migration does not grant a browser-policy group"
fi
grep -F 'BROWSER_POLICY_FIREFOX_DIRS' "${migrations[0]}" >/dev/null ||
fail "the policy-directory migration covers Firefox and Zen"
grep -F 'browser_policy_firefox_policy_file_ok' "${migrations[0]}" >/dev/null ||
fail "the policy-directory migration keeps a trusted Firefox policies.json"
grep -F '/opt/zen-browser/distribution' "$ROOT/install/helpers/browser-policy.sh" >/dev/null ||
fail "the shared helper names the Zen distribution directory"
pass "a migration locks existing policy directories"
+184
View File
@@ -0,0 +1,184 @@
#!/bin/bash
set -euo pipefail
source "$(dirname "$0")/base-test.sh"
helper="$ROOT/bin/omarchy-theme-set-browser-policy"
setter="$ROOT/bin/omarchy-theme-set-browser"
sudoers_file="$ROOT/etc/sudoers.d/omarchy-theme-browser"
rule='%wheel ALL=(root) NOPASSWD: /usr/bin/omarchy-theme-set-browser-policy [0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
# Exactly one rule, matched whole. Dropping the argument -- which sudoers reads
# as "any arguments" -- or widening the glob to `*` would let the grant carry
# something other than a color while leaving this line looking right.
rules=$(grep -vE '^[[:space:]]*(#|$)' "$sudoers_file")
[[ $rules == "$rule" ]] ||
fail "browser policy sudoers file carries exactly the six-hex-digit rule and nothing else" "got: $rules"
if command -v visudo >/dev/null; then
visudo -cf "$sudoers_file" >/dev/null || fail "browser policy sudoers rule parses"
fi
grep -Fx 'PACKAGED_PATH=/usr/bin/omarchy-theme-set-browser-policy' "$helper" >/dev/null ||
fail "omarchy-theme-set-browser-policy elevates the path the sudoers rule names"
grep -E 'sudo -n -l -l' "$helper" >/dev/null ||
fail "omarchy-theme-set-browser-policy reads the grant from the long sudo listing"
grep -Eq '^\s*export PATH=/usr/local/sbin:/usr/local/bin:/usr/bin' "$helper" ||
fail "omarchy-theme-set-browser-policy pins PATH to trusted system directories when it holds root"
gated=$(grep -A1 -E '^if \(\( EUID == 0 \)\); then$' "$helper" || true)
[[ $gated == *"export PATH=/usr/local/sbin:/usr/local/bin:/usr/bin"* ]] ||
fail "omarchy-theme-set-browser-policy gates the trusted-PATH pin on holding root"
pass "browser policy sudoers rule is scoped to a single color argument"
for dir in /etc/chromium/policies/managed /etc/opt/chrome/policies/managed \
/etc/opt/edge/policies/managed /etc/brave/policies/managed; do
grep -Fx " $dir" "$helper" >/dev/null ||
fail "omarchy-theme-set-browser-policy names $dir in its fixed policy directory list"
done
policy_dir_count=$(sed -n '/^POLICY_DIRS=(/,/^)/p' "$helper" | grep -c '^ /')
((policy_dir_count == 4)) ||
fail "omarchy-theme-set-browser-policy writes only the four known policy directories" \
"got: $policy_dir_count"
grep -F 'install -m 0644 -o root -g root -T' "$helper" >/dev/null ||
fail "omarchy-theme-set-browser-policy installs color.json with install -T"
if grep -E 'mv -f' "$helper" >/dev/null; then
fail "omarchy-theme-set-browser-policy does not mv into a planted color.json directory"
fi
pass "browser policy helper writes a fixed set of policy directories"
test_tmp=$(mktemp -d)
trap 'rm -rf "$test_tmp"' EXIT
stub_bin="$test_tmp/bin"
mkdir -p "$stub_bin"
cat >"$stub_bin/pkexec" <<'SH'
#!/bin/bash
printf 'pkexec %s\n' "$*" >"$ELEVATION_LOG"
SH
chmod +x "$stub_bin/pkexec"
# STUB_GRANTED empty stands for an install whose omarchy-settings predates the
# sudoers file. The default is granted, matching a current Omarchy.
cat >"$stub_bin/sudo" <<'SH'
#!/bin/bash
if [[ $1 == -n && $2 == -l ]]; then
if [[ ${STUB_GRANTED-granted} == "granted" ]]; then
echo " Options: !authenticate"
else
echo " Matched: ${!#}"
fi
exit 0
fi
printf 'sudo %s\n' "$*" >"$ELEVATION_LOG"
SH
chmod +x "$stub_bin/sudo"
if ((EUID == 0)); then
pass "running as root; skipping the elevation checks, which would rewrite this machine's browser policy"
else
elevation_for() {
: >"$test_tmp/elevation"
ELEVATION_LOG="$test_tmp/elevation" \
PATH="$stub_bin:$PATH" \
bash "$helper" "$@" </dev/null >/dev/null 2>&1 || true
cat "$test_tmp/elevation"
}
elevation=$(elevation_for 1c2027)
[[ $elevation == "sudo /usr/bin/omarchy-theme-set-browser-policy 1c2027" ]] ||
fail "omarchy-theme-set-browser-policy takes the passwordless sudo grant without a terminal" \
"got: $elevation"
dev_linked=$(OMARCHY_PATH="$test_tmp/checkout" elevation_for 1c2027)
[[ $dev_linked == "sudo /usr/bin/omarchy-theme-set-browser-policy 1c2027" ]] ||
fail "omarchy-theme-set-browser-policy elevates the system install wherever OMARCHY_PATH points" \
"got: $dev_linked"
pass "browser policy helper elevates a valid color through the sudo grant"
ungranted=$(STUB_GRANTED="" elevation_for 1c2027)
[[ $ungranted == "pkexec /usr/bin/omarchy-theme-set-browser-policy 1c2027" ]] ||
fail "omarchy-theme-set-browser-policy falls back to polkit where the grant does not reach" \
"got: $ungranted"
pass "browser policy helper falls back to polkit wherever the grant does not reach"
for bad in "" "1C2027" "abc12" "abc1234" "1c202g" "../../etc/passwd" "1c2027 1c2027" \
'$(id)' "1c2027;id" "#1c2027"; do
if PATH="$stub_bin:$PATH" ELEVATION_LOG="$test_tmp/elevation" \
bash "$helper" "$bad" </dev/null >/dev/null 2>&1; then
fail "omarchy-theme-set-browser-policy rejects '$bad'"
fi
rejected=$(elevation_for "$bad")
[[ -z $rejected ]] ||
fail "omarchy-theme-set-browser-policy rejects '$bad' before elevating" "got: $rejected"
done
if PATH="$stub_bin:$PATH" bash "$helper" 1c2027 ffffff </dev/null >/dev/null 2>&1; then
fail "omarchy-theme-set-browser-policy rejects more than one argument"
fi
pass "browser policy helper accepts nothing but six lowercase hex digits"
fi
setter_bin="$test_tmp/setter-bin"
mkdir -p "$setter_bin"
cat >"$setter_bin/omarchy-theme-set-browser-policy" <<'SH'
#!/bin/bash
printf '%s\n' "$*" >"$COLOR_LOG"
SH
chmod +x "$setter_bin/omarchy-theme-set-browser-policy"
cat >"$setter_bin/omarchy-cmd-present" <<'SH'
#!/bin/bash
exit 1
SH
chmod +x "$setter_bin/omarchy-cmd-present"
setter_home="$test_tmp/home"
theme_dir="$setter_home/.local/state/omarchy/current/theme"
mkdir -p "$theme_dir"
color_for_theme() {
: >"$test_tmp/color"
if [[ $# -gt 0 ]]; then
printf '%s' "$1" >"$theme_dir/chromium.theme"
else
rm -f "$theme_dir/chromium.theme"
fi
HOME="$setter_home" COLOR_LOG="$test_tmp/color" PATH="$setter_bin:$stub_bin:$PATH" \
OMARCHY_PATH="$ROOT" bash "$setter" </dev/null >/dev/null 2>&1 || true
cat "$test_tmp/color"
}
[[ $(color_for_theme "242,240,229") == "f2f0e5" ]] ||
fail "omarchy-theme-set-browser converts an RGB triple to six hex digits"
[[ $(color_for_theme $'14,31,41\n') == "0e1f29" ]] ||
fail "omarchy-theme-set-browser accepts a trailing newline"
[[ $(color_for_theme "0,0,0") == "000000" ]] ||
fail "omarchy-theme-set-browser pads single-digit components"
[[ $(color_for_theme " 12 , 11 , 12 ") == "0c0b0c" ]] ||
fail "omarchy-theme-set-browser tolerates surrounding whitespace"
for malformed in "" "not,a,color" "1,2" "1,2,3,4" "256,0,0" "999,999,999" "-1,0,0" \
"1,2,3;id" '1,2,$(id)' "0x10,0,0" "1,2,3 4,5,6"; do
color=$(color_for_theme "$malformed")
[[ $color == "1c2027" ]] ||
fail "omarchy-theme-set-browser falls back to the stock colour for '$malformed'" "got: $color"
done
[[ $(color_for_theme) == "1c2027" ]] ||
fail "omarchy-theme-set-browser falls back to the stock colour with no theme file"
pass "browser theme color is derived as six hex digits or falls back to the stock grey"
+45 -5
View File
@@ -61,11 +61,13 @@ if [[ $installer == "omarchy-install-browser" && ${OMARCHY_TEST_REAL_BROWSER_INS
fi
case $installer in
omarchy-pkg-add)
omarchy-pkg-add|omarchy-pkg-aur-add)
package=$1
printf 'pkg:%s\n' "$package" >>"$OMARCHY_TEST_INSTALL_LOG"
case $package in
chromium) command=chromium ;;
firefox) command=firefox ;;
zen-browser-bin) command=zen-browser ;;
cursor-bin) command=cursor ;;
sublime-text-4) command=sublime_text ;;
vim) command=vim ;;
@@ -107,6 +109,7 @@ SH
for installer in \
omarchy-pkg-add \
omarchy-pkg-aur-add \
omarchy-install-browser \
omarchy-install-terminal \
omarchy-install-editor-vscode \
@@ -205,10 +208,17 @@ OMARCHY_TEST_REAL_BROWSER_INSTALL=true omarchy-default-browser --install chromiu
[[ $(omarchy-default-browser) == "chromium" ]] || fail "Chromium becomes the default after its full installer succeeds"
cmp -s "$ROOT/config/chromium-flags.conf" "$test_home/.config/chromium-flags.conf" ||
fail "Chromium browser installer copies the default flags"
grep -Fxq 'sudo:mkdir -p /etc/chromium/policies/managed' "$setup_log" ||
fail "Chromium browser installer creates its policy directory"
grep -Fxq 'sudo:chmod a+rw /etc/chromium/policies/managed' "$setup_log" ||
fail "Chromium browser installer makes its policy directory writable"
grep -Fxq 'sudo:install -d -m 0755 -o root -g root /etc/chromium' "$setup_log" ||
fail "Chromium browser installer creates a root-owned Chromium policy parent"
grep -Fxq 'sudo:install -d -m 0755 -o root -g root /etc/chromium/policies' "$setup_log" ||
fail "Chromium browser installer creates a root-owned Chromium policies parent"
grep -Fxq 'sudo:install -d -m 0755 -o root -g root /etc/chromium/policies/managed' "$setup_log" ||
fail "Chromium browser installer creates a root-owned managed policy directory"
grep -Fxq 'sudo:find /etc/chromium/policies/managed -mindepth 1 -maxdepth 1 ! -user root -exec rm -rf -- {} +' "$setup_log" ||
fail "Chromium browser installer drops non-root files from its policy directory"
if grep -E 'groupadd|usermod|omarchy-browser-policy' "$setup_log" >/dev/null; then
fail "Chromium browser installer does not create a browser-policy group" "$(cat "$setup_log")"
fi
grep -Fxq 'omarchy-install-chromium-copy-url:' "$setup_log" ||
fail "Chromium browser installer registers the Copy URL host"
grep -Fxq 'omarchy-install-chromium-ytdlp:' "$setup_log" ||
@@ -217,6 +227,36 @@ grep -Fxq 'omarchy-theme-set-browser:' "$setup_log" ||
fail "Chromium browser installer applies the current theme"
pass "Chromium browser installer restores the complete Omarchy setup"
: >"$install_log"
: >"$setup_log"
rm -f "$installed_dir/firefox"
OMARCHY_TEST_REAL_BROWSER_INSTALL=true omarchy-default-browser --install firefox >/dev/null
[[ $(<"$install_log") == "pkg:firefox" ]] || fail "Firefox browser installer installs the package"
[[ $(omarchy-default-browser) == "firefox" ]] || fail "Firefox becomes the default after its full installer succeeds"
grep -Fxq 'sudo:install -d -m 0755 -o root -g root /usr/lib/firefox/distribution' "$setup_log" ||
fail "Firefox browser installer creates its distribution directory"
grep -Fxq 'sudo:find /usr/lib/firefox/distribution -mindepth 1 -maxdepth 1 ! -user root -exec rm -rf -- {} +' "$setup_log" ||
fail "Firefox browser installer drops non-root files from its distribution directory"
grep -Fxq "sudo:install -m 644 -o root -g root -T $ROOT/default/firefox/policies.json /usr/lib/firefox/distribution/policies.json" "$setup_log" ||
fail "Firefox browser installer copies policies.json without following a destination symlink"
[[ -e $installed_dir/firefox ]] || fail "Firefox browser installer marks firefox installed"
pass "Firefox browser installer restores the complete Omarchy setup"
: >"$install_log"
: >"$setup_log"
rm -f "$installed_dir/zen-browser"
OMARCHY_TEST_REAL_BROWSER_INSTALL=true omarchy-default-browser --install zen >/dev/null
[[ $(<"$install_log") == "pkg:zen-browser-bin" ]] || fail "Zen browser installer installs the package"
[[ $(omarchy-default-browser) == "zen" ]] || fail "Zen becomes the default after its full installer succeeds"
grep -Fxq 'sudo:install -d -m 0755 -o root -g root /opt/zen-browser/distribution' "$setup_log" ||
fail "Zen browser installer creates its distribution directory"
grep -Fxq 'sudo:find /opt/zen-browser/distribution -mindepth 1 -maxdepth 1 ! -user root -exec rm -rf -- {} +' "$setup_log" ||
fail "Zen browser installer drops non-root files from its distribution directory"
grep -Fxq "sudo:install -m 644 -o root -g root -T $ROOT/default/firefox/policies.json /opt/zen-browser/distribution/policies.json" "$setup_log" ||
fail "Zen browser installer copies policies.json without following a destination symlink"
[[ -e $installed_dir/zen-browser ]] || fail "Zen browser installer marks zen-browser installed"
pass "Zen browser installer restores the complete Omarchy setup"
omarchy-default-browser zen
rm -f "$installed_dir/chromium"
if OMARCHY_TEST_REAL_BROWSER_INSTALL=true OMARCHY_TEST_INSTALL_FAIL=true \
+33 -3
View File
@@ -27,16 +27,41 @@ cat >"$TMPDIR/bin/usermod" <<STUB
#!/bin/bash
echo "\$@" >>"$TMPDIR/usermod.calls"
STUB
chmod +x "$TMPDIR/bin/getent" "$TMPDIR/bin/usermod"
cat >"$TMPDIR/bin/groupadd" <<STUB
#!/bin/bash
echo "\$@" >>"$TMPDIR/groupadd.calls"
STUB
cat >"$TMPDIR/bin/install" <<STUB
#!/bin/bash
echo "\$@" >>"$TMPDIR/install.calls"
STUB
cat >"$TMPDIR/bin/find" <<STUB
#!/bin/bash
echo "\$@" >>"$TMPDIR/find.calls"
STUB
cat >"$TMPDIR/bin/sudo" <<STUB
#!/bin/bash
echo "\$@" >>"$TMPDIR/sudo.calls"
exec "\$@"
STUB
chmod +x "$TMPDIR/bin"/{getent,usermod,groupadd,install,find,sudo}
export PATH="$TMPDIR/bin:$PATH"
export OMARCHY_PATH="$ROOT"
# No install user (deferred-provisioning install): input recorded, usermod not called.
# No install user (deferred-provisioning install): groups recorded, usermod not called.
OMARCHY_INSTALL_USER="" bash -eE "$ROOT/install/config/docker.sh"
OMARCHY_INSTALL_USER="" bash -eE "$ROOT/install/hardware/input-group.sh"
OMARCHY_INSTALL_USER="" bash -eE "$ROOT/install/config/browser-policy.sh"
[[ -f $OMARCHY_PROVISIONING_DIR/groups ]] || fail "groups file written without an install user"
grep -qxF input "$OMARCHY_PROVISIONING_DIR/groups" || fail "input group recorded"
! grep -qxF omarchy-browser-policy "$OMARCHY_PROVISIONING_DIR/groups" ||
fail "browser-policy group must not be recorded"
[[ ! -f $TMPDIR/usermod.calls ]] || fail "usermod not called without an install user"
[[ ! -f $TMPDIR/groupadd.calls ]] || ! grep -F omarchy-browser-policy "$TMPDIR/groupadd.calls" >/dev/null ||
fail "browser-policy group is not created"
grep -F -- '-d -m 0755 -o root -g root /etc/chromium/policies/managed' "$TMPDIR/install.calls" >/dev/null ||
fail "browser-policy directory is created root-owned"
pass "deferred provisioning records groups without calling usermod"
# The docker group is root-equivalent and must never be granted automatically.
@@ -45,17 +70,22 @@ pass "docker group is not recorded at install"
# Missing user (defensive): no usermod either.
OMARCHY_INSTALL_USER=ghost bash -eE "$ROOT/install/hardware/input-group.sh"
OMARCHY_INSTALL_USER=ghost bash -eE "$ROOT/install/config/browser-policy.sh"
[[ ! -f $TMPDIR/usermod.calls ]] || fail "usermod not called for a missing user"
pass "missing install user defers group grants"
# Re-running never duplicates entries.
OMARCHY_INSTALL_USER="" bash -eE "$ROOT/install/hardware/input-group.sh"
[[ $(grep -cxF input "$OMARCHY_PROVISIONING_DIR/groups") == 1 ]] || fail "input group recorded once"
OMARCHY_INSTALL_USER="" bash -eE "$ROOT/install/config/browser-policy.sh"
pass "group recording is idempotent"
# Existing user: usermod applies the recorded groups, and docker is never among them.
OMARCHY_INSTALL_USER=existing bash -eE "$ROOT/install/config/docker.sh"
OMARCHY_INSTALL_USER=existing bash -eE "$ROOT/install/hardware/input-group.sh"
OMARCHY_INSTALL_USER=existing bash -eE "$ROOT/install/config/browser-policy.sh"
grep -qx -- "-aG input existing" "$TMPDIR/usermod.calls" || fail "usermod grants input to the install user"
! grep -q -- "omarchy-browser-policy" "$TMPDIR/usermod.calls" ||
fail "usermod must not grant browser-policy to the install user"
! grep -q -- "docker" "$TMPDIR/usermod.calls" || fail "usermod must not grant docker to the install user"
pass "existing install user gets input but never docker"
pass "existing install user gets input but never docker or browser-policy"
+18
View File
@@ -67,6 +67,24 @@ grep -F 'OMARCHY_INSTALL_USER="$target_user"' "$upgrade_to_quattro" >/dev/null
grep -F '"$apply_lock"' "$upgrade_to_quattro" >/dev/null
pass "Omarchy 4 upgrade configures lock screen authentication for the target user"
grep -F 'install/helpers/browser-policy.sh' "$upgrade_to_quattro" >/dev/null ||
fail "Omarchy 4 upgrade uses the shared browser-policy helper"
grep -F 'as_root test -f "$browser_policy_helper"' "$upgrade_to_quattro" >/dev/null ||
fail "Omarchy 4 upgrade survives a packaged tree without the browser-policy helper"
if grep -F 'browser_policy_setup_group' "$upgrade_to_quattro" >/dev/null; then
fail "Omarchy 4 upgrade does not create a browser-policy group"
fi
grep -F 'browser_policy_setup_dir /etc/chromium/policies/managed' "$upgrade_to_quattro" >/dev/null ||
fail "Omarchy 4 upgrade creates a root-owned Chromium policy directory"
grep -F 'BROWSER_POLICY_MANAGED_DIRS' "$upgrade_to_quattro" >/dev/null ||
fail "Omarchy 4 upgrade hardens every Chromium-family policy directory"
grep -F 'run_as_user_omarchy omarchy-theme-set-browser' "$upgrade_to_quattro" >/dev/null ||
fail "Omarchy 4 upgrade rewrites browser theme colour after a headless theme-set"
if grep -E 'install -d -m 0?[27]?777 /etc/.*/policies|chmod a\+rw|2775' "$upgrade_to_quattro" >/dev/null; then
fail "Omarchy 4 upgrade does not create a world-writable Chromium policy directory"
fi
pass "Omarchy 4 upgrade locks the Chromium policy directory to root"
grep -F 'OMARCHY_UPGRADE_TO_QUATTRO_LIVE=1' "$upgrade_to_quattro" >/dev/null
grep -F 'systemd-networkd.service' "$upgrade_to_quattro" >/dev/null
grep -F 'systemd-networkd.socket' "$upgrade_to_quattro" >/dev/null