Own printers, driverless only

The fourth panel this desktop handed to GNOME Settings, and the last one
worth owning.

Driverless only, deliberately. Adding a printer that describes its own
capabilities over IPP is supported; choosing a PPD or fetching a vendor
driver is not, and the page says so rather than pretending. That
restraint is the whole design: a wrong driver produces a printer that
accepts jobs, reports success, and prints nothing, which is the worst
failure this page could ship because it looks like it worked. A printer
old enough to need a PPD stays a job for the system printer tool.

Printers and the queue are separate cards because they answer separate
questions. Which printers exist is one; where a document went is the
other, and it is the one that actually brings someone here -- so the
queue is a single list across every printer.

Device URIs are validated by scheme before reaching CUPS, whose backends
run as root. file: and pipe: do not lead to a printer and are refused
here rather than further down.

This machine has no printer, so the page was built against a temporary
CUPS queue that was created, exercised through the service, and removed;
the service was confirmed to observe the removal rather than merely
perform it. Discovery and the driverless add path are verified by their
refusals rather than against hardware.

Claude-Session: https://claude.ai/code/session_01BRvzt4H8XXLPVH5MyYdk9L
This commit is contained in:
Gabriel Brown
2026-08-19 15:07:17 -04:00
parent 914d58f52b
commit e9d567aa72
11 changed files with 944 additions and 5 deletions
+111
View File
@@ -0,0 +1,111 @@
#!/usr/bin/env bash
# Printing is driverless only, and the page must not be able to become
# otherwise by accident.
#
# The reason is specific. Choosing a PPD or fetching a vendor driver is most of
# what the panel this replaces does, and a wrong choice produces a printer that
# accepts jobs, reports success, and prints nothing -- the worst failure this
# page could ship, because it looks like it worked. So the helper adds printers
# that describe their own capabilities over IPP and has no branch that selects
# anything else.
#
# The second rule is the device URI. It is handed to a CUPS backend that runs as
# root, so it is validated here rather than trusted from a settings page.
#
# Read-only: this reads printer state and exercises refusals. It never adds or
# removes a real printer.
set -uo pipefail
repo_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
helper="$repo_dir/config/dot/quickshell/scripts/panama-printers"
service="$repo_dir/config/dot/quickshell/services/Printers.qml"
page="$repo_dir/config/dot/quickshell/modules/settings/PrintersPage.qml"
fail() {
printf 'printers contract: %s\n' "$1" >&2
exit 1
}
for path in "$helper" "$service" "$page"; do
[[ -r "$path" ]] || fail "missing $path"
done
[[ -x "$helper" ]] || fail 'panama-printers is not executable'
# ── Driverless only ─────────────────────────────────────────────────────────
grep -q 'DRIVERLESS_MODEL = "everywhere"' "$helper" \
|| fail 'the driverless model is not named in one place, so the promise cannot be checked'
# Exactly one place may set a model, and it must be that constant.
model_uses="$(grep -c 'ppdname=' "$helper")"
[[ "$model_uses" == "1" ]] \
|| fail "ppdname is set in $model_uses places; driverless printing must have exactly one"
grep -q 'ppdname=DRIVERLESS_MODEL' "$helper" \
|| fail 'the printer is added with something other than the driverless model'
# No PPD file handling at all.
grep -qE '\.ppd|ppd-name|getPPDs|ppdFile|installDriver|foomatic' "$helper" \
&& fail 'the helper reaches for PPDs or drivers, which this page deliberately does not do'
# And the page must not offer a driver choice. Comments are stripped first:
# the page explains the no-driver policy in prose, and an earlier version of
# this check failed on the explanation rather than on any behaviour.
page_code="$(grep -vE '^\s*//' "$page")"
grep -qiE 'select.*driver|choose.*driver|ppdName|driverList' <<<"$page_code" \
&& fail 'the page offers driver selection'
# It must say so, rather than leaving someone guessing why their printer is absent.
grep -qi 'driverless' "$page" \
|| fail 'the page never explains that only driverless printers are supported'
# ── Device URIs are validated, not trusted ──────────────────────────────────
grep -q 'SAFE_SCHEMES' "$helper" || fail 'device URIs are not restricted by scheme'
for scheme in file pipe; do
grep -qE "\"$scheme\"" <<<"$(sed -n '/^SAFE_SCHEMES/,/)/p' "$helper")" \
&& fail "the $scheme scheme is allowed, and it does not lead to a printer"
done
command -v jq >/dev/null 2>&1 || { printf 'printers contract: SKIP (no jq)\n'; exit 0; }
refusal() { "$helper" "$@" 2>/dev/null | jq -r '.error // ""'; }
# The REASON matters, not merely that something failed. Without validation these
# reach CUPS, which refuses them too -- so a test that only checks for "an error"
# passes with the validation deleted, and proves nothing about this helper.
for bad in "file:///etc/passwd" "pipe:/bin/sh" "ipp://host; rm -rf /" "/etc/passwd" ""; do
answer="$(refusal add "$bad" probe)"
[[ -n "$answer" ]] || fail "the helper accepted \"$bad\" as a printer address"
[[ "$answer" == "That address cannot be used to reach a printer." ]] \
|| fail "\"$bad\" was rejected by the printing service rather than by this helper: $answer"
done
for bad in "../escape" "has space" "a#b" ""; do
[[ -n "$(refusal remove "$bad")" ]] \
|| fail "the helper accepted \"$bad\" as a printer name"
done
[[ -n "$(refusal cancel notanumber)" ]] || fail 'the helper accepted a job id that is not a number'
[[ -n "$(refusal bogus-command)" ]] || fail 'an unknown command was accepted'
# ── The snapshot describes the machine ──────────────────────────────────────
snapshot="$("$helper" snapshot 2>/dev/null)" || fail 'snapshot failed'
jq -e '(.printers | type == "array") and (.jobs | type == "array") and (.service | type == "object")' \
<<<"$snapshot" >/dev/null || fail 'the snapshot is missing printers, jobs, or service state'
jq -e '.service | has("running") and has("startsAtBoot") and has("discoveryAvailable")' \
<<<"$snapshot" >/dev/null || fail 'the service state is incomplete'
jq -e '[.printers[] | has("name") and has("state") and has("isDefault")] | all' \
<<<"$snapshot" >/dev/null || fail 'a printer is missing its name, state, or default flag'
# At most one default, or the page would show two.
[[ "$(jq '[.printers[] | select(.isDefault)] | length' <<<"$snapshot")" -le 1 ]] \
|| fail 'more than one printer is reported as the default'
# ── Removal is confirmed ────────────────────────────────────────────────────
grep -q 'confirmingRemoval' "$page" \
|| fail 'the page removes a printer without a confirmation step'
grep -q 'still queued for it is cancelled' "$page" \
|| fail 'the page does not say that removing a printer cancels its queued jobs'
# ── "On demand" is reported as normal, not as a fault ───────────────────────
# CUPS is socket-activated on this distribution; calling that a problem would
# send people to fix something that is not broken.
grep -q 'This is a normal configuration' "$page" \
|| fail 'a socket-activated printing service is presented as a problem'
printf 'printers contract: PASS (%d printer(s), %d job(s), driverless only)\n' \
"$(jq '.printers | length' <<<"$snapshot")" \
"$(jq '.jobs | length' <<<"$snapshot")"