cat / goq
clone

turns a linux box into a private steam streaming appliance: plug in, tap your key, play from another computer

fix: adopt identical legacy package assets

Dami committed 4c8b625
Preflight every managed user target before mutation, atomically replace only owner-matched byte-identical regular files, and fail closed on customized or unsafe paths.
commit
4c8b625e1b3499bb176c00488fb14e7ba5b60d87
parent
635bb9474e46219ad0d4c40ca18b7f8990b85dd4
author
Dami <dami.etoile@gmail.com>
3 files changed, +205 -11
Mdocs/fresh-bazzite-host.md4+
Mscripts/install-bazzite-package.sh91++++++++++++++++++++---
Ascripts/tests/bazzite-package-assets.sh121++++++++++++++++++++++++++++++
M docs/fresh-bazzite-host.md +4 -0
M scripts/install-bazzite-package.sh +80 -11
@@ -43,7 +43,7 @@ done
4343 [[ "$(uname -s)" == Linux ]] || die "this package must be installed on Linux"4444 [[ "$(uname -m)" == x86_64 ]] || die "expected x86_64, got $(uname -m)"4545 [[ "$(id -u)" -ne 0 ]] || die "run as the dedicated gaming user, not root"46-for command in diff flock ldd sha256sum systemctl systemd-analyze timeout; do46+for command in cmp diff flock ldd sha256sum systemctl systemd-analyze timeout; do4747 command -v "$command" >/dev/null 2>&1 || die "$command is required"4848 done4949
@@ -111,6 +111,7 @@ next_current="$install_root/.current-package-$release_id-$$"
111111 next_previous="$install_root/.previous-package-$release_id-$$"112112 lock_path="$install_root/.install.lock"113113 verify_unit="$install_root/.verify-package-$release_id-$$.service"114+next_managed_links=()114115 115116 install -d -m 0755 "$HOME/.local" "$HOME/.local/libexec" "$install_root" "$releases_root"116117 exec 9>"$lock_path"
@@ -125,6 +126,9 @@ cleanup() {
125126 fi126127 [[ ! -L "$next_current" ]] || rm -f -- "$next_current"127128 [[ ! -L "$next_previous" ]] || rm -f -- "$next_previous"129+ for next_managed_link in "${next_managed_links[@]}"; do130+ [[ ! -L "$next_managed_link" ]] || rm -f -- "$next_managed_link"131+ done128132 [[ ! -f "$verify_unit" ]] || rm -f -- "$verify_unit"129133 exit "$status"130134 }
@@ -204,25 +208,90 @@ local_bin="$HOME/.local/bin"
204208 asset_dir="$HOME/.local/share/sigil-spark/package-assets"205209 install -d -m 0700 "$config_root" "$pipewire_dir" "$systemd_dir" "$local_bin" "$asset_dir"206210 207-ensure_managed_link() {211+# BEGIN managed asset helpers (exercised directly by bazzite-package-assets.sh)212+preflight_managed_link() {208213 local link="$1"209214 local target="$2"210- if [[ -e "$link" || -L "$link" ]]; then211- [[ -L "$link" && "$(readlink -- "$link")" == "$target" ]] \212- || die "refusing to replace unmanaged path: $link"213- return215+ local release_asset="$3"216+217+ if [[ -L "$link" ]]; then218+ [[ "$(readlink "$link")" == "$target" ]] \219+ || die "refusing to replace unmanaged symlink: $link"220+ managed_link_action=keep221+ elif [[ -e "$link" ]]; then222+ [[ -f "$link" && -O "$link" ]] \223+ || die "refusing to replace unsafe or unowned path: $link"224+ cmp -s "$link" "$release_asset" \225+ || die "refusing to replace modified path: $link"226+ managed_link_action=replace227+ else228+ managed_link_action=create214229 fi215- ln -s "$target" "$link"216230 }217231 218-ensure_managed_link "$pipewire_dir/50-sigil-spark-audio.conf" \232+install_managed_links() {233+ local -a actions=()234+ local -a prepared_links=()235+ local index link next_link236+237+ [[ "${#managed_links[@]}" -eq 4 \238+ && "${#managed_links[@]}" -eq "${#managed_targets[@]}" \239+ && "${#managed_links[@]}" -eq "${#managed_release_assets[@]}" ]] \240+ || die "internal managed asset list mismatch"241+242+ # Classify every destination before changing any of them. This prevents a243+ # late unmanaged path from leaving an earlier package asset half-migrated.244+ for index in "${!managed_links[@]}"; do245+ preflight_managed_link \246+ "${managed_links[$index]}" \247+ "${managed_targets[$index]}" \248+ "${managed_release_assets[$index]}"249+ actions+=("$managed_link_action")250+ done251+252+ next_managed_links=()253+ for index in "${!managed_links[@]}"; do254+ [[ "${actions[$index]}" == keep ]] && continue255+ link="${managed_links[$index]}"256+ next_link="${link}.sigil-package-$release_id-$$-$index"257+ [[ ! -e "$next_link" && ! -L "$next_link" ]] \258+ || die "temporary managed link path already exists: $next_link"259+ prepared_links[index]="$next_link"260+ next_managed_links+=("$next_link")261+ done262+263+ for index in "${!managed_links[@]}"; do264+ [[ "${actions[$index]}" == keep ]] && continue265+ next_link="${prepared_links[$index]}"266+ ln -s "${managed_targets[$index]}" "$next_link"267+ if mv --help 2>&1 | grep -q -- '--no-target-directory'; then268+ mv -Tf -- "$next_link" "${managed_links[$index]}"269+ else270+ mv -f "$next_link" "${managed_links[$index]}"271+ fi272+ done273+}274+# END managed asset helpers275+276+managed_links=(277+ "$pipewire_dir/50-sigil-spark-audio.conf"278+ "$systemd_dir/sigil-host.service"279+ "$local_bin/sigil-spark-host-rollback"280+ "$asset_dir/70-sigil-remote-input.rules"281+)282+managed_targets=(219283 "$install_root/current/assets/50-sigil-spark-audio.conf"220-ensure_managed_link "$systemd_dir/sigil-host.service" \221284 "$install_root/current/assets/sigil-host.service"222-ensure_managed_link "$local_bin/sigil-spark-host-rollback" \223285 "$install_root/current/tools/rollback-bazzite-release.sh"224-ensure_managed_link "$asset_dir/70-sigil-remote-input.rules" \225286 "$install_root/current/assets/70-sigil-remote-input.rules"287+)288+managed_release_assets=(289+ "$release_path/assets/50-sigil-spark-audio.conf"290+ "$release_path/assets/sigil-host.service"291+ "$release_path/tools/rollback-bazzite-release.sh"292+ "$release_path/assets/70-sigil-remote-input.rules"293+)294+install_managed_links226295 227296 ln -s "releases/$release_id" "$next_current"228297 if [[ -n "$current_release_id" && "$current_release_id" != "$release_id" ]]; then
A scripts/tests/bazzite-package-assets.sh +121 -0
@@ -0,0 +1,121 @@
1+#!/usr/bin/env bash2+3+set -euo pipefail4+5+script_dir="$(CDPATH='' cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"6+repo_dir="$(CDPATH='' cd -- "$script_dir/../.." && pwd -P)"7+installer="$repo_dir/scripts/install-bazzite-package.sh"8+temp_parent="${TMPDIR:-/tmp}"9+temp_parent="${temp_parent%/}"10+temp_root="$(mktemp -d "$temp_parent/sigil-package-assets.XXXXXX")"11+helper_script="$temp_root/managed-assets.sh"12+13+cleanup() {14+ local status=$?15+ trap - EXIT INT TERM HUP16+ case "$temp_root" in17+ "$temp_parent"/sigil-package-assets.??????) rm -rf -- "$temp_root" ;;18+ esac19+ exit "$status"20+}21+trap cleanup EXIT INT TERM HUP22+23+sed -n \24+ '/^# BEGIN managed asset helpers /,/^# END managed asset helpers$/p' \25+ "$installer" | sed '1d;$d' >"$helper_script"26+grep -Fq 'install_managed_links()' "$helper_script"27+28+# shellcheck source=/dev/null29+source "$helper_script"30+31+die() {32+ printf 'test installer rejected: %s\n' "$*" >&233+ exit 134+}35+36+# Referenced by the sourced production helper block.37+# shellcheck disable=SC203438+release_id=0123456789abcdef39+# shellcheck disable=SC203440+next_managed_links=()41+42+make_assets() {43+ local root="$1"44+ local index45+ install -d -m 0700 "$root/assets" "$root/links"46+ for index in 0 1 2 3; do47+ printf 'release asset %s\n' "$index" >"$root/assets/$index"48+ done49+}50+51+set_managed_arrays() {52+ local root="$1"53+ managed_links=(54+ "$root/links/0"55+ "$root/links/1"56+ "$root/links/2"57+ "$root/links/3"58+ )59+ managed_targets=(60+ "$root/future/0"61+ "$root/future/1"62+ "$root/future/2"63+ "$root/future/3"64+ )65+ managed_release_assets=(66+ "$root/assets/0"67+ "$root/assets/1"68+ "$root/assets/2"69+ "$root/assets/3"70+ )71+}72+73+success_root="$temp_root/success"74+make_assets "$success_root"75+set_managed_arrays "$success_root"76+ln -s "${managed_targets[0]}" "${managed_links[0]}"77+cp "${managed_release_assets[2]}" "${managed_links[2]}"78+cp "${managed_release_assets[3]}" "${managed_links[3]}"79+install_managed_links80+for index in 0 1 2 3; do81+ [[ -L "${managed_links[$index]}" ]]82+ [[ "$(readlink "${managed_links[$index]}")" == "${managed_targets[$index]}" ]]83+done84+85+mismatch_root="$temp_root/mismatch"86+make_assets "$mismatch_root"87+set_managed_arrays "$mismatch_root"88+cp "${managed_release_assets[1]}" "${managed_links[1]}"89+ln -s "${managed_targets[2]}" "${managed_links[2]}"90+printf 'locally modified\n' >"${managed_links[3]}"91+if ( install_managed_links ); then92+ printf 'FAIL: mismatched regular asset unexpectedly succeeded\n' >&293+ exit 194+fi95+[[ ! -e "${managed_links[0]}" && ! -L "${managed_links[0]}" ]]96+[[ -f "${managed_links[1]}" && ! -L "${managed_links[1]}" ]]97+cmp -s "${managed_release_assets[1]}" "${managed_links[1]}"98+[[ -L "${managed_links[2]}" ]]99+[[ "$(readlink "${managed_links[2]}")" == "${managed_targets[2]}" ]]100+[[ -f "${managed_links[3]}" && ! -L "${managed_links[3]}" ]]101+grep -Fq 'locally modified' "${managed_links[3]}"102+103+unsafe_root="$temp_root/unsafe"104+make_assets "$unsafe_root"105+set_managed_arrays "$unsafe_root"106+cp "${managed_release_assets[1]}" "${managed_links[1]}"107+ln -s "${managed_targets[2]}" "${managed_links[2]}"108+mkfifo "${managed_links[3]}"109+if ( install_managed_links ); then110+ printf 'FAIL: unsafe managed asset type unexpectedly succeeded\n' >&2111+ exit 1112+fi113+[[ ! -e "${managed_links[0]}" && ! -L "${managed_links[0]}" ]]114+[[ -f "${managed_links[1]}" && ! -L "${managed_links[1]}" ]]115+[[ -L "${managed_links[2]}" ]]116+[[ -p "${managed_links[3]}" ]]117+118+# Intentional literal verifies the ownership gate in the extracted production helper.119+# shellcheck disable=SC2016120+grep -Fq '[[ -f "$link" && -O "$link" ]]' "$helper_script"121+printf 'bazzite_package_asset_tests=ok\n'