feat(deploy): services.bitspire.nfc.enable — declare the reader per machine

pcscd was enabled in hardware/batm3.nix and hardware/upboard.nix, which
cannot express "is a reader fitted": upboard.nix is shared by sintra (HID
Global OMNIKEY 5022) and tejo (nothing fitted), so tejo inherited pcscd it
has no use for, while the douro — with its own hardware file — got none and
wedged on every boot.

Make it a machine capability instead. services.bitspire.nfc.enable owns
pcscd, the two polkit rules and the wedge-recovery unit, and hands the app
a BITSPIRE_NFC_ENABLED flag so it doesn't initialise nfc-pcsc at all on a
machine with no reader. Per-model truth lives in nfcReaderForModel in
flake.nix next to fiatCodeForModel and upgradeWindowForModel, since a
shared hardware file can't answer the question. batm3 and sintra are true;
douro and tejo flip to true when readers are fitted.

The flag goes through the unit's Environment rather than
/var/lib/bitspire/.env, because .env is only written when absent — a
machine provisioned months ago would never pick up a new value.
This commit is contained in:
Padreug 2026-09-29 22:49:59 +02:00
commit bb2ad39628
5 changed files with 137 additions and 95 deletions

View file

@ -91,26 +91,9 @@
cpuFreqGovernor = "performance";
};
# PC/SC daemon for the HID Global OMNIKEY 5022 contactless reader
# (076b:5022, a CCID smart-card reader) used for Bolt Card tap-to-enter
# (ADR-003). pcscd binds the CCID driver; the app talks to pcscd's socket
# (via nfc-pcsc) rather than the USB device directly. Device-agnostic —
# same wiring as batm3's Feitian KP382; harmless if no reader is attached,
# pcscd just idles. Shared by every upboard machine (sintra, tejo).
services.pcscd.enable = true;
# pcscd gates client access via polkit; without a rule the sandboxed
# `bitspire` service user is "Rejected unauthorized PC/SC client". Authorize
# it to talk to the daemon and the card.
security.polkit.extraConfig = ''
polkit.addRule(function(action, subject) {
if ((action.id == "org.debian.pcsc-lite.access_pcsc" ||
action.id == "org.debian.pcsc-lite.access_card") &&
subject.user == "bitspire") {
return polkit.Result.YES;
}
});
'';
# No pcscd here. This file is shared by sintra (HID Global OMNIKEY 5022
# fitted) and tejo (no reader), so the reader is declared per model via
# `nfcReaderForModel` in flake.nix → services.bitspire.nfc.enable.
# Disable suspend/hibernate for kiosk
systemd.targets = {