444 lines
22 KiB
Bash
Executable File
444 lines
22 KiB
Bash
Executable File
#!/bin/sh
|
|
# test-provision-linux.sh — rootless integration test for the Linux
|
|
# kiosk provisioning pipeline (LibreWolf AND Firefox).
|
|
#
|
|
# Runs provision-kiosk.sh and deprovision-kiosk.sh against a sandbox:
|
|
# all privileged destinations (/opt, /etc, /usr/local/bin, systemd) are
|
|
# rewritten to a temp directory, and privileged commands (useradd,
|
|
# systemctl, chown, id) are replaced with shims. No root required, no
|
|
# real system mutation — this is what CI runs on every push.
|
|
#
|
|
# Scenarios:
|
|
# 1. --librewolf native full provision + deprovision cycle
|
|
# 2. --firefox native /etc/firefox/policies path (distro Firefox)
|
|
# 3. --firefox flatpak kiosk-home policy path + sandbox XPI copy
|
|
#
|
|
# What it verifies per scenario:
|
|
# provision: kiosk user creation, /opt staging, XPI build (valid zip
|
|
# with manifest.json), launcher install, kiosk.env browser
|
|
# + flavor, Native Messaging manifests (all five Gecko
|
|
# locations, valid JSON, correct path), policies.json
|
|
# deep-merge (the browser's own keys survive, ours added,
|
|
# extension force-installed with the right install_url),
|
|
# unit generation + enable.
|
|
# deprovision: unit removed, policies.json equal to the pre-provision
|
|
# baseline byte-for-byte, manifests + sandbox XPI copies
|
|
# removed, staged files removed.
|
|
#
|
|
# After the scenarios, the launcher dispatch is exercised directly: all
|
|
# four env permutations (firefox/flatpak, firefox/native,
|
|
# librewolf/flatpak, defaults) run against browser shims and the exec'd
|
|
# command line is asserted.
|
|
#
|
|
# Usage: sh scripts/test-provision-linux.sh (KEEP_SANDBOX=1 to inspect)
|
|
# Exit: 0 pass, 1 fail
|
|
#
|
|
# POSIX sh — no bashisms.
|
|
|
|
set -u
|
|
|
|
REPO_ROOT=$(cd "$(dirname "$0")/.." && pwd)
|
|
SANDBOX=$(mktemp -d)
|
|
PASS=0
|
|
FAIL=0
|
|
KIOSK_USER="vestibule-kiosk"
|
|
|
|
cleanup() {
|
|
if [ "${KEEP_SANDBOX:-0}" = "1" ]; then
|
|
say "sandbox kept at: ${SANDBOX}"
|
|
else
|
|
rm -rf "${SANDBOX}"
|
|
fi
|
|
}
|
|
trap cleanup EXIT INT TERM
|
|
|
|
say() { printf '%s\n' "$1"; }
|
|
pass() { PASS=$((PASS+1)); say " [pass] $1"; }
|
|
fail() { FAIL=$((FAIL+1)); say " [FAIL] $1"; }
|
|
check() { # check <description> <command...>
|
|
desc="$1"; shift
|
|
if "$@" >/dev/null 2>&1; then pass "${desc}"; else fail "${desc}"; fi
|
|
}
|
|
|
|
# ─── Sandbox layout ───────────────────────────────────────────────────
|
|
#
|
|
# repo/ copy of the real repo (scripts/, config/, extension/)
|
|
# root/opt fake /opt/vestibule
|
|
# root/etc fake /etc/vestibule + /etc/systemd/system
|
|
# root/etc/firefox fake /etc/firefox/policies (distro Firefox)
|
|
# root/usrlocal fake /usr/local/bin
|
|
# root/usr/lib/firefox fake distro Firefox install
|
|
# librewolf/ fake native LibreWolf install (wrapper in PATH)
|
|
# home/ fake kiosk user home
|
|
# bin/ PATH shims (privileged + browser + usher)
|
|
|
|
mkdir -p "${SANDBOX}/repo" "${SANDBOX}/root/opt" "${SANDBOX}/root/etc/systemd/system" \
|
|
"${SANDBOX}/root/etc/firefox/policies" "${SANDBOX}/root/usrlocal" \
|
|
"${SANDBOX}/root/usr/lib/firefox" "${SANDBOX}/bin" \
|
|
"${SANDBOX}/librewolf/browser" "${SANDBOX}/librewolf/distribution" \
|
|
"${SANDBOX}/home"
|
|
|
|
cp -r "${REPO_ROOT}/scripts" "${REPO_ROOT}/config" "${REPO_ROOT}/extension" "${SANDBOX}/repo/"
|
|
mkdir -p "${SANDBOX}/repo/helper/target/release"
|
|
printf '#!/bin/sh\nexit 0\n' > "${SANDBOX}/repo/helper/target/release/usher"
|
|
chmod +x "${SANDBOX}/repo/helper/target/release/usher"
|
|
|
|
# Fake native LibreWolf: wrapper in PATH + real install dir with markers.
|
|
printf '#!/bin/sh\nexec "%s/librewolf/librewolf" "$@"\n' "${SANDBOX}" > "${SANDBOX}/bin/librewolf"
|
|
chmod +x "${SANDBOX}/bin/librewolf"
|
|
# Fake LibreWolf binary: logs its argv (launcher dispatch assertions).
|
|
printf '#!/bin/sh\nprintf "%%s\\n" "librewolf $*" >> "%s/browser.log"\n' "${SANDBOX}" \
|
|
> "${SANDBOX}/librewolf/librewolf"
|
|
chmod +x "${SANDBOX}/librewolf/librewolf"
|
|
touch "${SANDBOX}/librewolf/application.ini"
|
|
# Fake Firefox in PATH for the launcher dispatch assertions. Provision
|
|
# detection never consults it: the canonical /usr/lib/firefox path wins.
|
|
printf '#!/bin/sh\nprintf "%%s\\n" "firefox $*" >> "%s/browser.log"\n' "${SANDBOX}" \
|
|
> "${SANDBOX}/bin/firefox"
|
|
chmod +x "${SANDBOX}/bin/firefox"
|
|
# Pre-seed LibreWolf's own shipped policies — the merge must preserve
|
|
# them and the deprovision must return this baseline byte-for-byte.
|
|
cat > "${SANDBOX}/librewolf/distribution/policies.json" <<'EOF'
|
|
{
|
|
"policies": {
|
|
"DisableAppUpdate": true,
|
|
"LibreWolfOwnSetting": "must-survive"
|
|
}
|
|
}
|
|
EOF
|
|
cp "${SANDBOX}/librewolf/distribution/policies.json" "${SANDBOX}/original-lw-policies.json"
|
|
|
|
# Fake distro Firefox at /usr/lib/firefox (canonical Debian/Arch layout;
|
|
# Fedora uses /usr/lib64 — same code path). No PATH wrapper: detection
|
|
# must find it via the canonical path.
|
|
printf '#!/bin/sh\nexit 0\n' > "${SANDBOX}/root/usr/lib/firefox/firefox"
|
|
chmod +x "${SANDBOX}/root/usr/lib/firefox/firefox"
|
|
touch "${SANDBOX}/root/usr/lib/firefox/application.ini"
|
|
# Pre-seed Firefox's own policies in /etc/firefox/policies.
|
|
cat > "${SANDBOX}/root/etc/firefox/policies/policies.json" <<'EOF'
|
|
{
|
|
"policies": {
|
|
"DisableTelemetry": true,
|
|
"FirefoxOwnSetting": "must-survive"
|
|
}
|
|
}
|
|
EOF
|
|
cp "${SANDBOX}/root/etc/firefox/policies/policies.json" "${SANDBOX}/original-ff-policies.json"
|
|
|
|
# ─── PATH shims ───────────────────────────────────────────────────────
|
|
|
|
printf '#!/bin/sh\n# id shim: "id -u" -> 0 (root); "id -u NAME" -> uid or fail if absent\nif [ "$1" = "-u" ] && [ $# -eq 1 ]; then echo 0; exit 0; fi\nname="$2"\nif grep -q "^${name}:" "%s/passwd" 2>/dev/null; then echo 1500; exit 0; fi\nexit 1\n' \
|
|
"${SANDBOX}" > "${SANDBOX}/bin/id"
|
|
printf '#!/bin/sh\necho useradd "$@" >> "%s/priv.log"\nmkdir -p "%s/home/vestibule-kiosk"\nprintf "vestibule-kiosk:x:1500:1500::%s/home/vestibule-kiosk:/bin/sh\\n" >> "%s/passwd"\n' \
|
|
"${SANDBOX}" "${SANDBOX}" "${SANDBOX}" "${SANDBOX}" > "${SANDBOX}/bin/useradd"
|
|
printf '#!/bin/sh\nif [ "$1" = "passwd" ] && [ "$2" = "vestibule-kiosk" ]; then grep "^vestibule-kiosk:" "%s/passwd"; fi\nexit 0\n' \
|
|
"${SANDBOX}" > "${SANDBOX}/bin/getent"
|
|
printf '#!/bin/sh\necho systemctl "$@" >> "%s/priv.log"\nexit 0\n' "${SANDBOX}" > "${SANDBOX}/bin/systemctl"
|
|
printf '#!/bin/sh\nexit 0\n' > "${SANDBOX}/bin/chown"
|
|
printf '#!/bin/sh\necho userdel "$@" >> "%s/priv.log"\ngrep -v "^vestibule-kiosk:" "%s/passwd" > "%s/passwd.tmp" && mv "%s/passwd.tmp" "%s/passwd"\nexit 0\n' \
|
|
"${SANDBOX}" "${SANDBOX}" "${SANDBOX}" "${SANDBOX}" "${SANDBOX}" > "${SANDBOX}/bin/userdel"
|
|
# cage shim: log the invocation, then exec the client after "--". The
|
|
# harness pins VESTIBULE_CAGE_ARGS to a single flag (-d) in every
|
|
# launcher test, so exactly two arguments precede the client.
|
|
printf '#!/bin/sh\nprintf "%%s\\n" "cage $*" >> "%s/browser.log"\nshift 2\nexec "$@"\n' "${SANDBOX}" > "${SANDBOX}/bin/cage"
|
|
# dbus-run-session shim: pass straight through to the compositor.
|
|
printf '#!/bin/sh\nshift\nexec "$@"\n' > "${SANDBOX}/bin/dbus-run-session"
|
|
# flatpak shim: system installs "exist" (info --system succeeds), user
|
|
# installs do not, and "run" is a logged browser launch.
|
|
printf '#!/bin/sh\nif [ "$1" = "info" ]; then [ "$2" = "--system" ] && exit 0; exit 1; fi\nif [ "$1" = "run" ]; then printf "%%s\\n" "flatpak $*" >> "%s/browser.log"; exit 0; fi\nexit 1\n' \
|
|
"${SANDBOX}" > "${SANDBOX}/bin/flatpak"
|
|
for f in "${SANDBOX}/bin/"*; do chmod +x "$f"; done
|
|
|
|
# ─── Rewrite privileged paths in the scripts under test ───────────────
|
|
|
|
rewrite() {
|
|
sed -e "s|/run/systemd/system|${SANDBOX}/run-systemd|g" \
|
|
-e "s|/opt/vestibule|${SANDBOX}/root/opt/vestibule|g" \
|
|
-e "s|/etc/vestibule|${SANDBOX}/root/etc/vestibule|g" \
|
|
-e "s|/etc/systemd/system|${SANDBOX}/root/etc/systemd/system|g" \
|
|
-e "s|/etc/firefox|${SANDBOX}/root/etc/firefox|g" \
|
|
-e "s|/usr/lib/firefox|${SANDBOX}/root/usr/lib/firefox|g" \
|
|
-e "s|/usr/local/bin|${SANDBOX}/root/usrlocal|g" \
|
|
-e "s|/usr/lib/librewolf|${SANDBOX}/librewolf|g" \
|
|
"$1" > "$2"
|
|
}
|
|
mkdir -p "${SANDBOX}/run-systemd"
|
|
rewrite "${REPO_ROOT}/scripts/provision-kiosk.sh" "${SANDBOX}/repo/scripts/provision-kiosk.sh"
|
|
rewrite "${REPO_ROOT}/scripts/deprovision-kiosk.sh" "${SANDBOX}/repo/scripts/deprovision-kiosk.sh"
|
|
rewrite "${REPO_ROOT}/scripts/vestibule-kiosk-launch" "${SANDBOX}/repo/scripts/vestibule-kiosk-launch"
|
|
|
|
export PATH="${SANDBOX}/bin:${PATH}"
|
|
|
|
NM="${SANDBOX}/home/vestibule-kiosk"
|
|
UNIT="${SANDBOX}/root/etc/systemd/system/vestibule-kiosk.service"
|
|
|
|
run_provision() {
|
|
sh "${SANDBOX}/repo/scripts/provision-kiosk.sh" "$@" \
|
|
--kiosk-user "${KIOSK_USER}" --tty 2 --yes \
|
|
> "${SANDBOX}/provision.out" 2>&1
|
|
}
|
|
run_deprovision() {
|
|
sh "${SANDBOX}/repo/scripts/deprovision-kiosk.sh" \
|
|
--kiosk-user "${KIOSK_USER}" \
|
|
--remove-user --remove-opt --remove-usher --yes \
|
|
> "${SANDBOX}/deprovision.out" 2>&1
|
|
}
|
|
report_on_fail() {
|
|
if [ "$1" -ne 0 ]; then
|
|
sed -n '1,60p' "${SANDBOX}/provision.out" 2>/dev/null
|
|
sed -n '1,60p' "${SANDBOX}/deprovision.out" 2>/dev/null
|
|
fi
|
|
}
|
|
|
|
assert_common_provision() {
|
|
# Everything browser-independent: staging, launcher, unit, NM.
|
|
check "usher installed" test -x "${SANDBOX}/root/usrlocal/usher"
|
|
check "usher staged under /opt" test -x "${SANDBOX}/root/opt/vestibule/bin/usher"
|
|
check "launcher installed" test -x "${SANDBOX}/root/usrlocal/vestibule-kiosk-launch"
|
|
check "XPI built" test -f "${SANDBOX}/root/opt/vestibule/extension/vestibule.xpi"
|
|
if python3 -c "
|
|
import zipfile, json
|
|
z = zipfile.ZipFile('${SANDBOX}/root/opt/vestibule/extension/vestibule.xpi')
|
|
m = json.loads(z.read('manifest.json'))
|
|
assert m['version'] == '1.2.2', m['version']
|
|
"; then pass "XPI valid zip with manifest.json v1.2.2"; else fail "XPI valid zip with manifest.json v1.2.2"; fi
|
|
|
|
check "unit generated" test -f "${UNIT}"
|
|
check "unit User substituted" grep -q '^User=vestibule-kiosk$' "${UNIT}"
|
|
check "unit TTYPath substituted" grep -q '^TTYPath=/dev/tty2$' "${UNIT}"
|
|
check "unit conflicts getty" grep -q 'Conflicts=getty@tty2.service' "${UNIT}"
|
|
check "unit execs launcher" grep -q 'ExecStart=/usr/local/bin/vestibule-kiosk-launch' "${UNIT}"
|
|
check "systemctl daemon-reload" grep -q "daemon-reload" "${SANDBOX}/priv.log"
|
|
check "systemctl enable" grep -q "enable vestibule-kiosk.service" "${SANDBOX}/priv.log"
|
|
|
|
# Native Messaging manifests: all five Gecko locations, valid JSON.
|
|
for loc in ".librewolf" ".mozilla" \
|
|
".var/app/io.gitlab.librewolf-community/.librewolf" \
|
|
".var/app/org.mozilla.firefox/.mozilla" \
|
|
"snap/firefox/common/.mozilla"; do
|
|
f="${NM}/${loc}/native-messaging-hosts/com.vestibule.usher.json"
|
|
check "NM manifest ${loc}" test -f "${f}"
|
|
if [ -f "${f}" ] && python3 -c "
|
|
import json
|
|
m = json.load(open('${f}'))
|
|
assert m['path'] == '${SANDBOX}/root/usrlocal/usher', m['path']
|
|
assert m['allowed_extensions'] == ['vestibule@vestibule.kiosk']
|
|
assert m['type'] == 'stdio'
|
|
"; then pass "NM manifest ${loc} valid"; else fail "NM manifest ${loc} valid"; fi
|
|
done
|
|
}
|
|
|
|
assert_common_deprovision() {
|
|
check "unit removed" test ! -f "${UNIT}"
|
|
check "launcher removed" test ! -e "${SANDBOX}/root/usrlocal/vestibule-kiosk-launch"
|
|
check "kiosk.env removed" test ! -e "${SANDBOX}/root/etc/vestibule"
|
|
check "/opt/vestibule removed" test ! -e "${SANDBOX}/root/opt/vestibule"
|
|
check "usher removed" test ! -e "${SANDBOX}/root/usrlocal/usher"
|
|
check "userdel called" grep -q "userdel" "${SANDBOX}/priv.log"
|
|
check "NM manifests removed" test ! -e "${NM}/.librewolf/native-messaging-hosts/com.vestibule.usher.json"
|
|
check "NM manifests removed (firefox flatpak)" test ! -e "${NM}/.var/app/org.mozilla.firefox/.mozilla/native-messaging-hosts/com.vestibule.usher.json"
|
|
check "NM manifests removed (firefox snap)" test ! -e "${NM}/snap/firefox/common/.mozilla/native-messaging-hosts/com.vestibule.usher.json"
|
|
check "sandbox XPI copy removed" test ! -e "${NM}/.var/app/org.mozilla.firefox/vestibule.xpi"
|
|
}
|
|
|
|
# ══════════════════════════════════════════════════════════════════════
|
|
# Scenario 1: LibreWolf, native
|
|
# ══════════════════════════════════════════════════════════════════════
|
|
|
|
say ""
|
|
say "==> scenario 1: provision --librewolf native"
|
|
if run_provision --librewolf native --home-url https://checkin.example.org; then
|
|
pass "provision-kiosk.sh exited 0"
|
|
else
|
|
fail "provision-kiosk.sh exited nonzero"
|
|
report_on_fail 1
|
|
fi
|
|
|
|
assert_common_provision
|
|
|
|
check "kiosk.env written" test -f "${SANDBOX}/root/etc/vestibule/kiosk.env"
|
|
check "kiosk.env home URL" grep -q 'VESTIBULE_HOME_URL="https://checkin.example.org"' "${SANDBOX}/root/etc/vestibule/kiosk.env"
|
|
check "kiosk.env browser librewolf" grep -q 'VESTIBULE_BROWSER="librewolf"' "${SANDBOX}/root/etc/vestibule/kiosk.env"
|
|
check "kiosk.env flavor native" grep -q 'VESTIBULE_BROWSER_FLAVOR="native"' "${SANDBOX}/root/etc/vestibule/kiosk.env"
|
|
|
|
POL="${SANDBOX}/librewolf/distribution/policies.json"
|
|
if python3 -c "
|
|
import json
|
|
p = json.load(open('${POL}'))['policies']
|
|
assert p['LibreWolfOwnSetting'] == 'must-survive', 'pre-existing key lost'
|
|
assert p['DisablePrivateBrowsing'] is True, 'canonical key missing'
|
|
assert p['SanitizeOnShutdown']['Cookies'] is True, 'nested key missing'
|
|
es = p['ExtensionSettings']
|
|
assert es['*']['installation_mode'] == 'blocked'
|
|
assert es['vestibule@vestibule.kiosk']['installation_mode'] == 'force_installed'
|
|
assert es['vestibule@vestibule.kiosk']['install_url'] == 'file://${SANDBOX}/root/opt/vestibule/extension/vestibule.xpi', es['vestibule@vestibule.kiosk']['install_url']
|
|
"; then pass "policies.json deep-merge correct (librewolf)"; else fail "policies.json deep-merge correct (librewolf)"; fi
|
|
check "policies backup created" test -f "${POL}.vestibule-bak"
|
|
|
|
say ""
|
|
say "==> scenario 1: deprovision"
|
|
if run_deprovision; then
|
|
pass "deprovision-kiosk.sh exited 0"
|
|
else
|
|
fail "deprovision-kiosk.sh exited nonzero"
|
|
report_on_fail 1
|
|
fi
|
|
assert_common_deprovision
|
|
if cmp -s "${POL}" "${SANDBOX}/original-lw-policies.json"; then
|
|
pass "librewolf policies.json equals the pre-provision baseline (byte-for-byte)"
|
|
else
|
|
fail "librewolf policies.json equals the pre-provision baseline (byte-for-byte)"
|
|
fi
|
|
|
|
# ══════════════════════════════════════════════════════════════════════
|
|
# Scenario 2: Firefox, native (distro package -> /etc/firefox/policies)
|
|
# ══════════════════════════════════════════════════════════════════════
|
|
|
|
say ""
|
|
say "==> scenario 2: provision --firefox native"
|
|
if run_provision --firefox native --home-url https://portal.example.org; then
|
|
pass "provision-kiosk.sh exited 0"
|
|
else
|
|
fail "provision-kiosk.sh exited nonzero"
|
|
report_on_fail 1
|
|
fi
|
|
|
|
assert_common_provision
|
|
|
|
FFPOL="${SANDBOX}/root/etc/firefox/policies/policies.json"
|
|
check "kiosk.env browser firefox" grep -q 'VESTIBULE_BROWSER="firefox"' "${SANDBOX}/root/etc/vestibule/kiosk.env"
|
|
check "kiosk.env flavor native (ff)" grep -q 'VESTIBULE_BROWSER_FLAVOR="native"' "${SANDBOX}/root/etc/vestibule/kiosk.env"
|
|
check "firefox policies file deployed" test -f "${FFPOL}"
|
|
if python3 -c "
|
|
import json
|
|
p = json.load(open('${FFPOL}'))['policies']
|
|
assert p['FirefoxOwnSetting'] == 'must-survive', 'pre-existing Firefox key lost'
|
|
assert p['DisablePrivateBrowsing'] is True, 'canonical key missing'
|
|
assert p['SanitizeOnShutdown']['Cookies'] is True, 'nested key missing'
|
|
es = p['ExtensionSettings']
|
|
assert es['vestibule@vestibule.kiosk']['installation_mode'] == 'force_installed'
|
|
assert es['vestibule@vestibule.kiosk']['install_url'] == 'file://${SANDBOX}/root/opt/vestibule/extension/vestibule.xpi', es['vestibule@vestibule.kiosk']['install_url']
|
|
"; then pass "firefox /etc/firefox policies deep-merge correct"; else fail "firefox /etc/firefox policies deep-merge correct"; fi
|
|
check "firefox policies backup created" test -f "${FFPOL}.vestibule-bak"
|
|
# Firefox provisioning must not touch the LibreWolf install.
|
|
if cmp -s "${POL}" "${SANDBOX}/original-lw-policies.json"; then
|
|
pass "librewolf policies untouched by firefox provision"
|
|
else
|
|
fail "librewolf policies untouched by firefox provision"
|
|
fi
|
|
|
|
say ""
|
|
say "==> scenario 2: deprovision"
|
|
if run_deprovision; then
|
|
pass "deprovision-kiosk.sh exited 0"
|
|
else
|
|
fail "deprovision-kiosk.sh exited nonzero"
|
|
report_on_fail 1
|
|
fi
|
|
assert_common_deprovision
|
|
if cmp -s "${FFPOL}" "${SANDBOX}/original-ff-policies.json"; then
|
|
pass "firefox /etc/firefox policies.json equals the pre-provision baseline (byte-for-byte)"
|
|
else
|
|
fail "firefox /etc/firefox policies.json equals the pre-provision baseline (byte-for-byte)"
|
|
fi
|
|
|
|
# ══════════════════════════════════════════════════════════════════════
|
|
# Scenario 3: Firefox, Flatpak (kiosk-home policy path + XPI copy)
|
|
# ══════════════════════════════════════════════════════════════════════
|
|
|
|
say ""
|
|
say "==> scenario 3: provision --firefox flatpak"
|
|
if run_provision --firefox flatpak --home-url https://lobby.example.org; then
|
|
pass "provision-kiosk.sh exited 0"
|
|
else
|
|
fail "provision-kiosk.sh exited nonzero"
|
|
report_on_fail 1
|
|
fi
|
|
|
|
assert_common_provision
|
|
|
|
FFHOME_POL="${NM}/.var/app/org.mozilla.firefox/.mozilla/policies/policies.json"
|
|
check "kiosk.env browser firefox (fp)" grep -q 'VESTIBULE_BROWSER="firefox"' "${SANDBOX}/root/etc/vestibule/kiosk.env"
|
|
check "kiosk.env flavor flatpak (fp)" grep -q 'VESTIBULE_BROWSER_FLAVOR="flatpak"' "${SANDBOX}/root/etc/vestibule/kiosk.env"
|
|
check "XPI copied to flatpak home" test -f "${NM}/.var/app/org.mozilla.firefox/vestibule.xpi"
|
|
check "flatpak policies file deployed" test -f "${FFHOME_POL}"
|
|
if python3 -c "
|
|
import json
|
|
p = json.load(open('${FFHOME_POL}'))['policies']
|
|
es = p['ExtensionSettings']
|
|
assert es['vestibule@vestibule.kiosk']['installation_mode'] == 'force_installed'
|
|
# install_url must point INSIDE the sandbox-visible home, not /opt.
|
|
assert es['vestibule@vestibule.kiosk']['install_url'] == 'file://${NM}/vestibule.xpi', es['vestibule@vestibule.kiosk']['install_url']
|
|
"; then pass "flatpak install_url points at sandbox-visible XPI"; else fail "flatpak install_url points at sandbox-visible XPI"; fi
|
|
|
|
say ""
|
|
say "==> scenario 3: deprovision"
|
|
if run_deprovision; then
|
|
pass "deprovision-kiosk.sh exited 0"
|
|
else
|
|
fail "deprovision-kiosk.sh exited nonzero"
|
|
report_on_fail 1
|
|
fi
|
|
assert_common_deprovision
|
|
check "flatpak-home policies removed" test ! -e "${FFHOME_POL}"
|
|
|
|
# ════════════════════════════════════════════════════════════════════
|
|
# Launcher dispatch: all four env permutations run against browser
|
|
# shims; the exec'd command line is asserted, not just parsed.
|
|
# ════════════════════════════════════════════════════════════════════
|
|
|
|
say ""
|
|
say "==> launcher dispatch"
|
|
LAUNCHER="${SANDBOX}/repo/scripts/vestibule-kiosk-launch"
|
|
KIOSK_ENV="${SANDBOX}/root/etc/vestibule/kiosk.env"
|
|
URL="https://launch.example.org"
|
|
|
|
write_kiosk_env() {
|
|
mkdir -p "${SANDBOX}/root/etc/vestibule"
|
|
{
|
|
printf 'VESTIBULE_HOME_URL="%s"\n' "${URL}"
|
|
printf 'VESTIBULE_CAGE_ARGS="-d"\n'
|
|
[ -n "${1:-}" ] && printf 'VESTIBULE_BROWSER="%s"\n' "$1"
|
|
[ -n "${2:-}" ] && printf 'VESTIBULE_BROWSER_FLAVOR="%s"\n' "$2"
|
|
} > "${KIOSK_ENV}"
|
|
}
|
|
|
|
launcher_check() {
|
|
# $1 = description, $2 = expected command line (fixed string)
|
|
desc="$1"; expect="$2"
|
|
rm -f "${SANDBOX}/browser.log"
|
|
sh "${LAUNCHER}" > "${SANDBOX}/launcher.out" 2>&1
|
|
if grep -qF "${expect}" "${SANDBOX}/browser.log" 2>/dev/null; then
|
|
pass "launcher dispatches ${desc}"
|
|
else
|
|
fail "launcher dispatches ${desc} (log: $(cat "${SANDBOX}/browser.log" 2>/dev/null || echo empty))"
|
|
fi
|
|
}
|
|
|
|
write_kiosk_env firefox flatpak
|
|
launcher_check "firefox/flatpak -> flatpak run" \
|
|
"flatpak run org.mozilla.firefox --kiosk -P vestibule-profile -no-remote ${URL}"
|
|
|
|
write_kiosk_env firefox native
|
|
launcher_check "firefox/native -> firefox" \
|
|
"firefox --kiosk -P vestibule-profile -no-remote ${URL}"
|
|
|
|
write_kiosk_env librewolf flatpak
|
|
launcher_check "librewolf/flatpak -> flatpak run" \
|
|
"flatpak run io.gitlab.librewolf-community --kiosk -P vestibule-profile -no-remote ${URL}"
|
|
|
|
write_kiosk_env "" ""
|
|
launcher_check "defaults -> librewolf native" \
|
|
"librewolf --kiosk -P vestibule-profile -no-remote ${URL}"
|
|
|
|
# ─── Summary ──────────────────────────────────────────────────────────
|
|
|
|
say ""
|
|
if [ "${FAIL}" -eq 0 ]; then
|
|
say "OK — ${PASS} assertions passed: kiosk provision/deprovision works for LibreWolf native, Firefox native, and Firefox Flatpak."
|
|
exit 0
|
|
else
|
|
say "FAIL: ${FAIL} failed of $((PASS+FAIL))"
|
|
exit 1
|
|
fi
|