A user on SteamOS asked whether the manual commands in the 0.25.0 release notes are their job or the update script's. Answering it turned up a real bug behind the question.
The bug
scripts/60-punktfunk.ruleschgrps the usbip vhci attach/detach nodes to a dedicated punktfunk group — deliberately not input, because writing attach hands the kernel a caller-supplied socket fd and materialises an arbitrary emulated USB device (security-review 2026-08-05 M-4).
Four of the six host install paths shipped that rule in 0.25.0 without ever creating the group. The chgrp then fails, the nodes stay root:root 0644, and the virtual Steam Deck pad silently never attaches — it degrades to a generic Xbox 360 controller with nothing in any log the user would look at. The remedy the release notes print fails too, with usermod: group 'punktfunk' does not exist.
Path
Was
Now
Arch / CachyOS, upgraded
post_upgrade() called only _ensure_update_group — post_install was correct, so only boxes that reached 0.25.0 via pacman -Syu are affected
also calls _ensure_punktfunk_group
NixOS
no users.groups.punktfunk at all, although host.users' own option description already promised the usbip/vhci pad
declares the group; host.users joins both
Bazzite sysext
a group is host state (/etc/group) and cannot ride an image, and the deb/rpm scriptlets that would create it never run there
groupadd in post_merge
Steam Deck source install
install.sh / update.sh handled input only
create the group and join it
deb and rpm were correct throughout — they run one postinst / %post on install and upgrade alike.
Why the Deck scripts join the group rather than print the command
The distro packages print it because they cannot know whether the operator wants that pad. Running scripts/steamdeck/install.shis the statement "make my Deck a host with native pad passthrough", and the script already auto-joins input (systemwide input injection). The alternative is exactly the silent failure being fixed. It warns loudly and documents gpasswd -d "$USER" punktfunk. The per-distro guides keep it opt-in. Flagging this one explicitly in case you'd rather it only printed the command.
Also: web.env secret hygiene on the Deck
install.sh's chmod 600 sat inside the create-only branch, despite a comment describing it as "the idempotent belt for a pre-existing file" — so it only ever ran on files just written 0600 anyway. update.sh never touched the config dir at all. A Deck set up once and only ever updated since therefore kept web.env at the ambient umask (0644), with the console login password and session secret readable by every local account.
Both scripts now harden ~/.config/punktfunk to 0700 and web.env to 0600 on every run, and say so loudly — a chmod does not un-leak an already-readable secret, so the password still needs rotating. The 0.25.0 notes' "consider rotating your console password" is upgraded to an actual instruction with the commands.
A set -e trap in the fix itself
Both group blocks are if ensure_group ...; then rather than ensure_group || true. A failed groupadd must not fall through to a usermod against a nonexistent group: under set -e that aborted install.shafter the long build and before the services were installed, and update.sh before its service restart — leaving the host down. Measured in a container: old shape exits 6 and never reaches the restart, new shape warns and continues.
Docs
The group was documented nowhere on the docs site — only in the release notes and CHANGELOG. Now covered in arch.md, fedora.md, ubuntu.md, bazzite.md, install.md, steamos-host.md, all five uninstall paths, and a new troubleshooting entry for the actual symptom ("the pad arrives as an Xbox 360 controller instead of a Steam Deck") with the four checks that isolate it.
docs/releases/v0.25.0.md gains the group 'punktfunk' does not exist caveat and scopes the bullet to hosts (a machine you only stream from needs nothing). CHANGELOG.md records the known issue against the breaking change that introduced it.
⚠ The live Gitea release body still carries the old 0.25.0 text.docs/releases/README.md sanctions editing the file after the tag, but syncing it needs a re-announce or an API PATCH — left alone here since that is outward-facing.
Answering the original question
On a Deck, once this lands, the user runs nothing by hand: update.sh creates and joins the group and fixes the file modes. Stock SteamOS runs no firewall, so the 47993 bullet does not apply there either. Rotating the console password after a pre-0.25.0 install is the one item still on them.
Verification
bash -n on all four edited scripts.
Arch post_upgrade() sourced and driven in a container: creates the group, idempotent on a second run, no regression on punktfunk-update.
ensure_group and both membership branches exercised in a container, including a control that reproduces the original bug — chgrp to a missing group fails and leaves the node root:root 0644.
The find -perm /0077 probe across 0644 / 0640 / 0604 / 0600 / 0400 on GNU findutils (correctly flags the first three), plus the missing-file case not aborting under set -e.
nix flake check --no-build — the exact gate in nix.yml, which packaging/nix/** triggers — passes, including checking NixOS module 'nixosModules.default'. A full NixOS eval returns aliceExtraGroups: ["input","punktfunk"] with both groups declared.
docs-sitebun run build + bun run lint (tsc --noEmit) clean.
Not verified on glass: no Deck, Arch, Bazzite or NixOS box was touched. The container tests cover the group and permission logic, not a real vhci attach.
A user on SteamOS asked whether the manual commands in the 0.25.0 release notes are their job or the update script's. Answering it turned up a real bug behind the question.
## The bug
`scripts/60-punktfunk.rules` `chgrp`s the usbip vhci `attach`/`detach` nodes to a dedicated `punktfunk` group — deliberately not `input`, because writing `attach` hands the kernel a caller-supplied socket fd and materialises an arbitrary emulated USB device (security-review 2026-08-05 M-4).
**Four of the six host install paths shipped that rule in 0.25.0 without ever creating the group.** The `chgrp` then fails, the nodes stay `root:root 0644`, and the virtual Steam Deck pad silently never attaches — it degrades to a generic Xbox 360 controller with nothing in any log the user would look at. The remedy the release notes print fails too, with `usermod: group 'punktfunk' does not exist`.
| Path | Was | Now |
|---|---|---|
| **Arch / CachyOS, upgraded** | `post_upgrade()` called only `_ensure_update_group` — `post_install` was correct, so only boxes that reached 0.25.0 via `pacman -Syu` are affected | also calls `_ensure_punktfunk_group` |
| **NixOS** | no `users.groups.punktfunk` at all, although `host.users`' own option description already promised the usbip/vhci pad | declares the group; `host.users` joins both |
| **Bazzite sysext** | a group is host state (`/etc/group`) and cannot ride an image, and the deb/rpm scriptlets that would create it never run there | `groupadd` in `post_merge` |
| **Steam Deck source install** | `install.sh` / `update.sh` handled `input` only | create the group **and** join it |
deb and rpm were correct throughout — they run one `postinst` / `%post` on install and upgrade alike.
### Why the Deck scripts join the group rather than print the command
The distro packages print it because they cannot know whether the operator wants that pad. Running `scripts/steamdeck/install.sh` *is* the statement "make my Deck a host with native pad passthrough", and the script already auto-joins `input` (systemwide input injection). The alternative is exactly the silent failure being fixed. It warns loudly and documents `gpasswd -d "$USER" punktfunk`. The per-distro guides keep it opt-in. **Flagging this one explicitly in case you'd rather it only printed the command.**
## Also: `web.env` secret hygiene on the Deck
`install.sh`'s `chmod 600` sat *inside* the create-only branch, despite a comment describing it as "the idempotent belt for a pre-existing file" — so it only ever ran on files just written `0600` anyway. `update.sh` never touched the config dir at all. A Deck set up once and only ever updated since therefore kept `web.env` at the ambient umask (`0644`), with the console login password and session secret readable by every local account.
Both scripts now harden `~/.config/punktfunk` to `0700` and `web.env` to `0600` on every run, and say so loudly — a chmod does not un-leak an already-readable secret, so the password still needs rotating. The 0.25.0 notes' "consider rotating your console password" is upgraded to an actual instruction with the commands.
## A `set -e` trap in the fix itself
Both group blocks are `if ensure_group ...; then` rather than `ensure_group || true`. A failed `groupadd` must not fall through to a `usermod` against a nonexistent group: under `set -e` that aborted `install.sh` *after* the long build and before the services were installed, and `update.sh` before its service restart — leaving the host down. Measured in a container: old shape exits 6 and never reaches the restart, new shape warns and continues.
## Docs
The group was documented **nowhere** on the docs site — only in the release notes and CHANGELOG. Now covered in `arch.md`, `fedora.md`, `ubuntu.md`, `bazzite.md`, `install.md`, `steamos-host.md`, all five uninstall paths, and a new troubleshooting entry for the actual symptom ("the pad arrives as an Xbox 360 controller instead of a Steam Deck") with the four checks that isolate it.
`docs/releases/v0.25.0.md` gains the `group 'punktfunk' does not exist` caveat and scopes the bullet to hosts (a machine you only stream *from* needs nothing). `CHANGELOG.md` records the known issue against the breaking change that introduced it.
⚠ **The live Gitea release body still carries the old 0.25.0 text.** `docs/releases/README.md` sanctions editing the file after the tag, but syncing it needs a re-announce or an API PATCH — left alone here since that is outward-facing.
## Answering the original question
On a Deck, once this lands, the user runs nothing by hand: `update.sh` creates and joins the group and fixes the file modes. Stock SteamOS runs no firewall, so the 47993 bullet does not apply there either. Rotating the console password after a pre-0.25.0 install is the one item still on them.
## Verification
- `bash -n` on all four edited scripts.
- Arch `post_upgrade()` sourced and driven in a container: creates the group, idempotent on a second run, no regression on `punktfunk-update`.
- `ensure_group` and both membership branches exercised in a container, **including a control that reproduces the original bug** — `chgrp` to a missing group fails and leaves the node `root:root 0644`.
- The `find -perm /0077` probe across `0644 / 0640 / 0604 / 0600 / 0400` on GNU findutils (correctly flags the first three), plus the missing-file case not aborting under `set -e`.
- `nix flake check --no-build` — the exact gate in `nix.yml`, which `packaging/nix/**` triggers — passes, including `checking NixOS module 'nixosModules.default'`. A full NixOS eval returns `aliceExtraGroups: ["input","punktfunk"]` with both groups declared.
- `docs-site` `bun run build` + `bun run lint` (`tsc --noEmit`) clean.
Not verified on glass: no Deck, Arch, Bazzite or NixOS box was touched. The container tests cover the group and permission logic, not a real vhci attach.
60-punktfunk.rules chgrp's the usbip vhci attach/detach nodes to a dedicated
`punktfunk` group (security-review 2026-08-05 M-4: writing `attach` materialises
an arbitrary emulated USB device, so it must not ride on `input`). Four of the
six install paths shipped that rule in 0.25.0 without ever creating the group.
chgrp then failed, the nodes stayed root:root 0644, and the virtual Steam Deck
pad silently never attached — while `usermod -aG punktfunk` failed outright with
"group 'punktfunk' does not exist".
Affected and fixed:
* arch — post_upgrade() called only _ensure_update_group, so every box that
reached 0.25.0 by `pacman -Syu` missed it; post_install was correct.
* nix — no users.groups.punktfunk at all, though host.users' own description
already promised the usbip/vhci pad. Declares it now and adds
host.users to both groups.
* bazzite sysext — a group is host state and cannot ride an image, and the
deb/rpm scriptlets that would create it never run there.
* steamdeck install.sh/update.sh — handled `input` only. Both now create the
group and join it: running that script IS the statement "make my
Deck a host with native pad passthrough".
deb and rpm were correct throughout (one postinst/%post for install + upgrade).
Also on the Deck path: web.env secret hygiene. install.sh's `chmod 600` sat
inside the create-only branch despite a comment calling it "the idempotent belt
for a pre-existing file", and update.sh never touched the config dir at all — so
an install set up once and only updated since kept web.env world-readable
(0644) with the console password and session secret in it. Both scripts now
harden ~/.config/punktfunk to 0700 and web.env to 0600 on every run, and say so
loudly, because a chmod does not un-leak an already-readable secret: the
password still needs rotating.
Both group blocks are `if ensure_group ...` rather than `ensure_group || true`:
a failed groupadd must not fall through to a usermod against a nonexistent
group, which under `set -e` aborted install.sh after the long build and
update.sh before the service restart (verified: exit 6, no restart).
Docs: the group is now documented where people actually look — the per-distro
guides, install.md, steamos-host.md, a new troubleshooting entry for "pad
arrives as an Xbox 360 controller", and the uninstall pages. The 0.25.0 notes
gain the "group does not exist" caveat and turn the password bullet from
"consider rotating" into a real instruction, and CHANGELOG records the known
issue against the breaking change that introduced it.
Verified: bash -n on all four scripts; the arch scriptlet's post_upgrade driven
in a container (creates the group, idempotent on re-run); the ensure_group
helper and both membership branches, including a control that reproduces the
original bug (chgrp to a missing group leaves the node root:root 0644); the
find -perm /0077 probe across 0644/0640/0604/0600/0400 on GNU findutils;
`nix flake check --no-build` (the exact CI gate) and a NixOS eval showing
alice.extraGroups == ["input","punktfunk"]; docs-site build + typecheck.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
A user on SteamOS asked whether the manual commands in the 0.25.0 release notes are their job or the update script's. Answering it turned up a real bug behind the question.
The bug
scripts/60-punktfunk.ruleschgrps the usbip vhciattach/detachnodes to a dedicatedpunktfunkgroup — deliberately notinput, because writingattachhands the kernel a caller-supplied socket fd and materialises an arbitrary emulated USB device (security-review 2026-08-05 M-4).Four of the six host install paths shipped that rule in 0.25.0 without ever creating the group. The
chgrpthen fails, the nodes stayroot:root 0644, and the virtual Steam Deck pad silently never attaches — it degrades to a generic Xbox 360 controller with nothing in any log the user would look at. The remedy the release notes print fails too, withusermod: group 'punktfunk' does not exist.post_upgrade()called only_ensure_update_group—post_installwas correct, so only boxes that reached 0.25.0 viapacman -Syuare affected_ensure_punktfunk_groupusers.groups.punktfunkat all, althoughhost.users' own option description already promised the usbip/vhci padhost.usersjoins both/etc/group) and cannot ride an image, and the deb/rpm scriptlets that would create it never run theregroupaddinpost_mergeinstall.sh/update.shhandledinputonlydeb and rpm were correct throughout — they run one
postinst/%poston install and upgrade alike.Why the Deck scripts join the group rather than print the command
The distro packages print it because they cannot know whether the operator wants that pad. Running
scripts/steamdeck/install.shis the statement "make my Deck a host with native pad passthrough", and the script already auto-joinsinput(systemwide input injection). The alternative is exactly the silent failure being fixed. It warns loudly and documentsgpasswd -d "$USER" punktfunk. The per-distro guides keep it opt-in. Flagging this one explicitly in case you'd rather it only printed the command.Also:
web.envsecret hygiene on the Deckinstall.sh'schmod 600sat inside the create-only branch, despite a comment describing it as "the idempotent belt for a pre-existing file" — so it only ever ran on files just written0600anyway.update.shnever touched the config dir at all. A Deck set up once and only ever updated since therefore keptweb.envat the ambient umask (0644), with the console login password and session secret readable by every local account.Both scripts now harden
~/.config/punktfunkto0700andweb.envto0600on every run, and say so loudly — a chmod does not un-leak an already-readable secret, so the password still needs rotating. The 0.25.0 notes' "consider rotating your console password" is upgraded to an actual instruction with the commands.A
set -etrap in the fix itselfBoth group blocks are
if ensure_group ...; thenrather thanensure_group || true. A failedgroupaddmust not fall through to ausermodagainst a nonexistent group: underset -ethat abortedinstall.shafter the long build and before the services were installed, andupdate.shbefore its service restart — leaving the host down. Measured in a container: old shape exits 6 and never reaches the restart, new shape warns and continues.Docs
The group was documented nowhere on the docs site — only in the release notes and CHANGELOG. Now covered in
arch.md,fedora.md,ubuntu.md,bazzite.md,install.md,steamos-host.md, all five uninstall paths, and a new troubleshooting entry for the actual symptom ("the pad arrives as an Xbox 360 controller instead of a Steam Deck") with the four checks that isolate it.docs/releases/v0.25.0.mdgains thegroup 'punktfunk' does not existcaveat and scopes the bullet to hosts (a machine you only stream from needs nothing).CHANGELOG.mdrecords the known issue against the breaking change that introduced it.⚠ The live Gitea release body still carries the old 0.25.0 text.
docs/releases/README.mdsanctions editing the file after the tag, but syncing it needs a re-announce or an API PATCH — left alone here since that is outward-facing.Answering the original question
On a Deck, once this lands, the user runs nothing by hand:
update.shcreates and joins the group and fixes the file modes. Stock SteamOS runs no firewall, so the 47993 bullet does not apply there either. Rotating the console password after a pre-0.25.0 install is the one item still on them.Verification
bash -non all four edited scripts.post_upgrade()sourced and driven in a container: creates the group, idempotent on a second run, no regression onpunktfunk-update.ensure_groupand both membership branches exercised in a container, including a control that reproduces the original bug —chgrpto a missing group fails and leaves the noderoot:root 0644.find -perm /0077probe across0644 / 0640 / 0604 / 0600 / 0400on GNU findutils (correctly flags the first three), plus the missing-file case not aborting underset -e.nix flake check --no-build— the exact gate innix.yml, whichpackaging/nix/**triggers — passes, includingchecking NixOS module 'nixosModules.default'. A full NixOS eval returnsaliceExtraGroups: ["input","punktfunk"]with both groups declared.docs-sitebun run build+bun run lint(tsc --noEmit) clean.Not verified on glass: no Deck, Arch, Bazzite or NixOS box was touched. The container tests cover the group and permission logic, not a real vhci attach.
60-punktfunk.rules chgrp's the usbip vhci attach/detach nodes to a dedicated `punktfunk` group (security-review 2026-08-05 M-4: writing `attach` materialises an arbitrary emulated USB device, so it must not ride on `input`). Four of the six install paths shipped that rule in 0.25.0 without ever creating the group. chgrp then failed, the nodes stayed root:root 0644, and the virtual Steam Deck pad silently never attached — while `usermod -aG punktfunk` failed outright with "group 'punktfunk' does not exist". Affected and fixed: * arch — post_upgrade() called only _ensure_update_group, so every box that reached 0.25.0 by `pacman -Syu` missed it; post_install was correct. * nix — no users.groups.punktfunk at all, though host.users' own description already promised the usbip/vhci pad. Declares it now and adds host.users to both groups. * bazzite sysext — a group is host state and cannot ride an image, and the deb/rpm scriptlets that would create it never run there. * steamdeck install.sh/update.sh — handled `input` only. Both now create the group and join it: running that script IS the statement "make my Deck a host with native pad passthrough". deb and rpm were correct throughout (one postinst/%post for install + upgrade). Also on the Deck path: web.env secret hygiene. install.sh's `chmod 600` sat inside the create-only branch despite a comment calling it "the idempotent belt for a pre-existing file", and update.sh never touched the config dir at all — so an install set up once and only updated since kept web.env world-readable (0644) with the console password and session secret in it. Both scripts now harden ~/.config/punktfunk to 0700 and web.env to 0600 on every run, and say so loudly, because a chmod does not un-leak an already-readable secret: the password still needs rotating. Both group blocks are `if ensure_group ...` rather than `ensure_group || true`: a failed groupadd must not fall through to a usermod against a nonexistent group, which under `set -e` aborted install.sh after the long build and update.sh before the service restart (verified: exit 6, no restart). Docs: the group is now documented where people actually look — the per-distro guides, install.md, steamos-host.md, a new troubleshooting entry for "pad arrives as an Xbox 360 controller", and the uninstall pages. The 0.25.0 notes gain the "group does not exist" caveat and turn the password bullet from "consider rotating" into a real instruction, and CHANGELOG records the known issue against the breaking change that introduced it. Verified: bash -n on all four scripts; the arch scriptlet's post_upgrade driven in a container (creates the group, idempotent on re-run); the ensure_group helper and both membership branches, including a control that reproduces the original bug (chgrp to a missing group leaves the node root:root 0644); the find -perm /0077 probe across 0644/0640/0604/0600/0400 on GNU findutils; `nix flake check --no-build` (the exact CI gate) and a NixOS eval showing alice.extraGroups == ["input","punktfunk"]; docs-site build + typecheck.