cat / goq
clone

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

fix(uat): support display-manager-independent autologin (#110)

FelineStateMachine committed c52eb4c
* fix(uat): support generic gaming autologin

* fix(uat): reject ambiguous session properties

Require exactly one nonempty Service, User, Remote, and State property before an autologin session can satisfy cold-boot evidence. Cover conflicting duplicate properties with fail-closed fixtures.
commit
c52eb4c999b1b7fa4dfd039c01cf5186ec3d77c0
parent
f84cb137987ebc38118c882343bece07ebe868ed
author
FelineStateMachine <dami.etoile@gmail.com>
4 files changed, +134 -31
Mdocs/fresh-bazzite-host.md20++++--
Mdocs/public-alpha-uat.md5+
Mscripts/bazzite-inventory.sh31+++++++-
Mscripts/tests/bazzite-inventory-cold-boot.sh109+++++++++++++++++++++++++-----
M docs/fresh-bazzite-host.md +13 -7
@@ -1472,13 +1472,19 @@ set -o pipefail
14721472 14731473 The Gamescope session must predate the first accepted SSH login.14741474 `--cold-boot` is read-only and makes the gate machine-checkable. It exits zero1475-only when no DRM connector is connected, the SDDM Gaming Mode session and1476-required PipeWire nodes are active, the Sigil service is enabled and ready,1477-and Gamescope plus Sigil both predate the first accepted SSH login. Exit status1478-`1` means observed evidence failed a gate. Exit status `3` means the boot1479-journal is unavailable, starts more than five minutes after boot, or otherwise1480-cannot establish the first SSH ordering; do not treat that as a pass. Run it1481-immediately on the first SSH login so journal rotation cannot erase the proof.1475+only when no DRM connector is connected, an active local gaming-user autologin1476+session and the required PipeWire nodes are active, the Sigil service is1477+enabled and ready, and Gamescope plus Sigil both predate the first accepted1478+SSH login. The gaming1479+session check is display-manager-independent: it requires an active, local1480+logind session for the gaming user whose exact PAM service name ends in1481+`-autologin` (for example, `sddm-autologin` or `gdm-autologin`). A manual1482+desktop login, SSH session, or merely started user manager does not satisfy the1483+gate. Exit status `1` means observed evidence failed a gate. Exit status `3`1484+means the boot journal is unavailable, starts more than five minutes after1485+boot, or otherwise cannot establish the first SSH ordering; do not treat that1486+as a pass. Run it immediately on the first SSH login so journal rotation1487+cannot erase the proof.14821488 14831489 If the stock session does not start or does not publish a node without a14841490 physical connector, stop at this gate. This is an expected discovery risk on
M docs/public-alpha-uat.md +5 -0
M scripts/bazzite-inventory.sh +26 -5
@@ -115,6 +115,19 @@ summary_value() {
115115 sed -n "s/^${key}=//p" | head -n 1116116 }117117 118+exact_property_value() {119+ local document="$1"120+ local property="$2"121+ local count122+ local value123+124+ count="$(grep -c "^${property}=" <<<"$document" || true)"125+ [[ "$count" == 1 ]] || return 1126+ value="$(sed -n "s/^${property}=//p" <<<"$document")"127+ [[ -n "$value" ]] || return 1128+ printf '%s\n' "$value"129+}130+118131 monotonic_before() {119132 local earlier="$1"120133 local later="$2"
@@ -195,6 +208,10 @@ cold_boot_session_evidence() {
195208 local session_id196209 local session_details197210 local current_user_id211+ local service212+ local session_user213+ local remote214+ local state198215 local autologin_found=false199216 200217 current_user_id="$(id -u)"
@@ -215,10 +232,14 @@ cold_boot_session_evidence() {
215232 fi216233 printf 'session_begin=%s\n%s\nsession_end=%s\n' \217234 "$session_id" "$session_details" "$session_id"218- if grep -qx 'Service=sddm-autologin' <<<"$session_details" &&219- grep -qx "User=$current_user_id" <<<"$session_details" &&220- grep -qx 'Remote=no' <<<"$session_details" &&221- grep -qx 'State=active' <<<"$session_details"; then235+ service="$(exact_property_value "$session_details" Service)" || continue236+ session_user="$(exact_property_value "$session_details" User)" || continue237+ remote="$(exact_property_value "$session_details" Remote)" || continue238+ state="$(exact_property_value "$session_details" State)" || continue239+ if [[ "$service" =~ ^[[:alnum:]_.@+-]+-autologin$ ]] &&240+ [[ "$session_user" == "$current_user_id" ]] &&241+ [[ "$remote" == no ]] &&242+ [[ "$state" == active ]]; then222243 autologin_found=true223244 fi224245 done <<<"$sessions"
@@ -226,7 +247,7 @@ cold_boot_session_evidence() {
226247 if [[ "$autologin_found" == true ]]; then227248 echo 'gaming_autologin_session=ok'228249 else229- cold_boot_failure no_active_local_sddm_autologin_session250+ cold_boot_failure no_active_local_gaming_autologin_session230251 fi231252 }232253
M scripts/tests/bazzite-inventory-cold-boot.sh +90 -19
@@ -33,41 +33,112 @@ assert_not_contains() {
3333 }3434 3535 session_user_id="$(id -u)"36+session_fixture_user="$session_user_id"37+session_fixture_remote=no38+session_fixture_state=active39+session_fixture_services='Service=sddm-autologin'3640 loginctl() {3741 if [[ "$1" == list-sessions ]]; then3842 printf '2 %s test seat0 tty1\n' "$session_user_id"3943 else4044 printf '%s\n' \4145 'Id=2' \42- "User=$session_user_id" \43- 'Remote=no' \44- 'Service=sddm-autologin' \46+ "User=$session_fixture_user" \47+ "Remote=$session_fixture_remote"48+ [[ -z "$session_fixture_services" ]] || \49+ printf '%s\n' "$session_fixture_services"50+ printf '%s\n' \4551 'Type=wayland' \4652 'Class=user' \47- 'State=active'53+ "State=$session_fixture_state"54+ fi55+}56+57+assert_session_fixture() {58+ local label="$1"59+ local expected="$2"60+ local output61+62+ output="$(cold_boot_session_evidence)"63+ if [[ "$expected" == pass ]]; then64+ assert_contains "$output" 'gaming_autologin_session=ok'65+ assert_not_contains "$output" 'cold_boot_failure='66+ else67+ assert_contains "$output" \68+ 'cold_boot_failure=no_active_local_gaming_autologin_session'69+ assert_not_contains "$output" 'gaming_autologin_session=ok'4870 fi71+ printf 'session_fixture=%s result=%s\n' "$label" "$expected"4972 }50-session_output="$(cold_boot_session_evidence)"51-assert_contains "$session_output" 'gaming_autologin_session=ok'52-assert_not_contains "$session_output" 'cold_boot_failure='73+74+assert_session_fixture sddm pass75+session_fixture_services='Service=gdm-autologin'76+assert_session_fixture gdm pass77+session_fixture_user=6553478+assert_session_fixture wrong-user fail79+session_fixture_user="$session_user_id"80+session_fixture_remote=yes81+assert_session_fixture remote fail82+session_fixture_remote=no83+session_fixture_state=closing84+assert_session_fixture inactive fail85+session_fixture_state=active86+session_fixture_services='Service=gdm-password'87+assert_session_fixture manual-gdm fail88+session_fixture_services=''89+assert_session_fixture missing-service fail90+session_fixture_services='Service='91+assert_session_fixture empty-service fail92+session_fixture_services='Service=sddm-autologin-extra'93+assert_session_fixture near-miss-service fail94+session_fixture_services='Service=-autologin'95+assert_session_fixture empty-service-prefix fail96+session_fixture_services=$'Service=sddm-autologin\nService=gdm-autologin'97+assert_session_fixture duplicate-service fail98+session_fixture_services='Service=sddm-autologin'99+session_fixture_user=$'65534\nUser='"$session_user_id"100+assert_session_fixture duplicate-user fail101+session_fixture_user="$session_user_id"102+session_fixture_remote=$'yes\nRemote=no'103+assert_session_fixture duplicate-remote fail104+session_fixture_remote=no105+session_fixture_state=$'closing\nState=active'106+assert_session_fixture duplicate-state fail107+session_fixture_state=active53108 54109 loginctl() {55110 if [[ "$1" == list-sessions ]]; then56- printf '2 65534 somebody seat0 tty1\n'57- else58111 printf '%s\n' \59- 'Id=2' \60- 'User=65534' \61- 'Remote=no' \62- 'Service=sddm-autologin' \63- 'Type=wayland' \64- 'Class=user' \65- 'State=active'112+ "2 $session_user_id test - pts/0" \113+ "3 $session_user_id test - -" \114+ "4 $session_user_id test seat0 tty1"115+ return66116 fi117+118+ case "$2" in119+ 2)120+ printf '%s\n' \121+ 'Id=2' "User=$session_user_id" 'Remote=yes' 'Service=sshd' \122+ 'Type=tty' 'Class=user' 'State=active'123+ ;;124+ 3)125+ printf '%s\n' \126+ 'Id=3' "User=$session_user_id" 'Remote=no' 'Service=systemd-user' \127+ 'Type=unspecified' 'Class=manager' 'State=active'128+ ;;129+ 4)130+ printf '%s\n' \131+ 'Id=4' "User=$session_user_id" 'Remote=no' 'Service=gdm-autologin' \132+ 'Type=wayland' 'Class=user' 'State=active'133+ ;;134+ *)135+ return 1136+ ;;137+ esac67138 }68-wrong_user_session_output="$(cold_boot_session_evidence)"69-assert_contains "$wrong_user_session_output" \70- 'cold_boot_failure=no_active_local_sddm_autologin_session'139+multiple_session_output="$(cold_boot_session_evidence)"140+assert_contains "$multiple_session_output" 'gaming_autologin_session=ok'141+assert_not_contains "$multiple_session_output" 'cold_boot_failure='71142 72143 pass_journal='[0.500000] host systemd[1]: Reached target Basic System73144 [1.000000] host gamescope-session-plus[100]: starting Gamescope