Skip to main content

max / alloy

Read polkit's defaults off the machine, rather than off fw13 once in July The privilege ladder is built on a table of implicit defaults in wiki alloy-privilege, every value of which was read on Pop!_OS. Tier 1 grants five actions because their default is auth_admin_keep; a default that became yes would make the rules file a security artifact shipped for nothing, and one that became auth_admin would take away the burst caching the settings tab counts on. Nothing checked. check-installed.sh --policy is that re-read, one command, no root. Measured on fw13: every NetworkManager, timedate1, hostname1, locale1 and systemd1 row still reads as recorded. The four rpm-ostree rows report ABSENT there because fw13 has no rpm-ostree, which is the half only a booted Alloy image can answer.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-08-16 00:18 UTC
Signed with PGP, not checked
Commit: f357bf5fbac53b9983bcc726edda6d20eb756b0f
Parent: c407be9
2 files changed, +116 insertions, -7 deletions
@@ -32,8 +32,24 @@
32 32 # property anyone cares about and no amount of label-reading proves
33 33 # it as directly as running one.
34 34 #
35 + # A third check answers a different standing question, and is separate because
36 + # it needs no root and reports rather than passes or fails:
37 + #
38 + # policy what polkit's *implicit* defaults actually are on this machine,
39 + # for every action the console depends on.
40 + #
41 + # Wiki `alloy-privilege` records that table, and every reading in it was taken
42 + # on fw13, which is Pop!_OS. The note says so and asks for it to be re-read on
43 + # a booted Alloy image, because the whole privilege ladder is built on those
44 + # values: tier 1 grants five actions precisely because their upstream default
45 + # is `auth_admin_keep`, and a Fedora override or an upstream change would make
46 + # a shipped rules file either redundant or, worse, the only thing standing
47 + # between a user and a prompt nobody can explain. `--policy` is that re-read,
48 + # reduced to one command someone can run on fw12 and paste back.
49 + #
35 50 # Usage:
36 51 # sudo build/check-installed.sh # check this machine
52 + # build/check-installed.sh --policy # read the polkit defaults back
37 53 # build/check-installed.sh --self-test # check the filter; touches nothing
38 54 #
39 55 # Or against a VM from the harness in build/vmtest:
@@ -45,8 +61,10 @@
45 61 #
46 62 # Exit codes follow check-rust-stage.sh:
47 63 #
48 - # 0 the machine is labelled correctly and DynamicUser works.
49 - # 1 it is not. Every offending line is printed, with the repair.
64 + # 0 the machine is labelled correctly and DynamicUser works. Under
65 + # `--policy`, every action reads the way wiki `alloy-privilege` says.
66 + # 1 it is not. Every offending line is printed, with the repair. Under
67 + # `--policy`, at least one action has drifted or is not defined here.
50 68 # 3 something about the run, not about the machine: not root, no
51 69 # restorecon, or SELinux is not enforcing here. Prints `error:`.
52 70 #
@@ -127,11 +145,97 @@
127 145 printf 'self-test: the filter is right about all three shapes\n'
128 146 }
129 147
130 - if [ "${1:-}" = "--self-test" ]; then
131 - self_test
132 - exit 0
133 - fi
134 - [ $# -eq 0 ] || die "unknown argument: $1"
148 + # The policy table from wiki `alloy-privilege`, as `<action> <implicit active>`.
149 + #
150 + # Only the implicit defaults are read, not the effective answer. The effective
151 + # answer on an Alloy machine includes
152 + # `usr/share/polkit-1/rules.d/50-alloy-settings.rules`, which is asserted
153 + # separately by `crates/alloy/tests/polkit_rules.rs` and by a Containerfile
154 + # block. What is unasserted anywhere, and what this reads, is the vendor
155 + # default underneath: the five granted actions are granted *because* their
156 + # default is `auth_admin_keep`, and a default that quietly became `yes` would
157 + # make the rules file a security artifact shipped for no reason, while one that
158 + # became `auth_admin` would mean the burst-caching the settings tab counts on
159 + # is gone.
160 + #
161 + # rpm-ostree and systemd1.manage-units are in the list without being granted
162 + # anything: the first is what `alloy update` and `alloy pkg` go through and the
163 + # prompt there is deliberate, and the second is what `run0` asks for, which is
164 + # the command Alloy teaches instead of sudo.
165 + POLICY_TABLE='
166 + org.freedesktop.NetworkManager.network-control yes
167 + org.freedesktop.NetworkManager.enable-disable-wifi yes
168 + org.freedesktop.NetworkManager.enable-disable-network yes
169 + org.freedesktop.NetworkManager.settings.modify.system auth_admin_keep
170 + org.freedesktop.timedate1.set-timezone auth_admin_keep
171 + org.freedesktop.timedate1.set-ntp auth_admin_keep
172 + org.freedesktop.timedate1.set-time auth_admin_keep
173 + org.freedesktop.hostname1.set-static-hostname auth_admin_keep
174 + org.freedesktop.hostname1.set-machine-info auth_admin_keep
175 + org.freedesktop.locale1.set-locale auth_admin_keep
176 + org.freedesktop.locale1.set-keyboard auth_admin_keep
177 + org.projectatomic.rpmostree1.upgrade auth_admin_keep
178 + org.projectatomic.rpmostree1.rollback auth_admin_keep
179 + org.projectatomic.rpmostree1.install-uninstall-packages auth_admin_keep
180 + org.projectatomic.rpmostree1.client-management yes
181 + org.freedesktop.systemd1.manage-units auth_admin_keep
182 + '
183 +
184 + # What polkit says the default is for one action, or `undefined` when this
185 + # machine does not define it at all.
186 + #
187 + # An action nobody defines is the quiet failure worth catching: a grant naming
188 + # a renamed action is inert and says nothing, and the symptom is a password
189 + # prompt on a machine that was supposed to have none.
190 + implicit_active() {
191 + local out
192 + out="$(pkaction --action-id "$1" --verbose 2>/dev/null)" || true
193 + [ -n "$out" ] || { printf 'undefined\n'; return; }
194 + printf '%s\n' "$out" | awk -F': *' '/implicit active:/ { print $2; found = 1 }
195 + END { if (!found) print "unreadable" }'
196 + }
197 +
198 + read_policy() {
199 + command -v pkaction >/dev/null 2>&1 || die "no pkaction: install polkit"
200 +
201 + local drift=0 absent=0 action expected actual mark
202 + while read -r action expected; do
203 + [ -n "$action" ] || continue
204 + actual="$(implicit_active "$action")"
205 + if [ "$actual" = "$expected" ]; then
206 + mark='ok '
207 + elif [ "$actual" = undefined ]; then
208 + mark='ABSENT '
209 + absent=$((absent + 1))
210 + else
211 + mark='DRIFT '
212 + drift=$((drift + 1))
213 + fi
214 + printf '%s %-56s %s\n' "$mark" "$action" "$actual"
215 + done <<< "$POLICY_TABLE"
216 +
217 + # Reported apart because they mean different things. DRIFT is the reading
218 + # this exists to catch: the default moved and the ladder is built on the old
219 + # one. ABSENT is usually the host, not the policy — run this on a machine
220 + # without rpm-ostree, as fw13 is, and the four rpm-ostree rows cannot be
221 + # answered by anything. On a booted Alloy image both are findings.
222 + if [ "$((drift + absent))" -ne 0 ]; then
223 + [ "$drift" -eq 0 ] || printf '\n%s action(s) read differently than wiki `alloy-privilege` records.\n' "$drift"
224 + [ "$absent" -eq 0 ] || printf '\n%s action(s) are not defined on this machine.\n' "$absent"
225 + printf 'That table decides which actions tier 1 grants, so correct the note before the rules file.\n'
226 + return 1
227 + fi
228 + printf '\nEvery action reads the way wiki `alloy-privilege` records it.\n'
229 + }
230 +
231 + case "${1:-}" in
232 + --self-test) self_test; exit 0 ;;
233 + # Spelled as a conditional rather than `read_policy; exit $?`, so a drift
234 + # verdict returns through the `if` instead of tripping the ERR trap.
235 + --policy) if read_policy; then exit 0; else exit 1; fi ;;
236 + '') ;;
237 + *) die "unknown argument: $1" ;;
238 + esac
135 239
136 240 [ "$(id -u)" -eq 0 ] || die "run as root: restorecon cannot stat everything under /etc otherwise, and a partial read would pass"
137 241 command -v restorecon >/dev/null 2>&1 || die "no restorecon: install policycoreutils"
@@ -80,6 +80,11 @@
80 80 `restorecon`, or an install from the `selinux=0` GRUB entry, which deliberately
81 81 produces an unlabelled machine.
82 82
83 + `--policy` is the other question a booted machine can answer and the build host
84 + cannot: what polkit's implicit defaults actually are for every action the
85 + console goes through. It needs no root, and wiki `alloy-privilege` is the table
86 + it checks against.
87 +
83 88 ## What it caught
84 89
85 90 The two defects fixed in `crates/alloy/src/install.rs` on 2026-08-09: the