| 235 |
235 |
|
https://pkgs.tailscale.com/stable/fedora/tailscale.repo
|
| 236 |
236 |
|
|
| 237 |
237 |
|
# Terra — Fedora repo for parts of the Wayland ecosystem (swww,
|
| 238 |
|
- |
# starship, and some others). Does not carry Rust binaries like
|
|
238 |
+ |
# starship, satty, and some others). Does not carry Rust binaries like
|
| 239 |
239 |
|
# nushell or yazi; COPRs below handle those.
|
| 240 |
240 |
|
# https://terra.fyralabs.com/
|
| 241 |
241 |
|
RUN dnf install -y --nogpgcheck \
|
| 266 |
266 |
|
# yazi binary
|
| 267 |
267 |
|
RUN dnf copr enable -y varlad/yazi
|
| 268 |
268 |
|
|
| 269 |
|
- |
# satty (screenshot annotator) is expected in ublue-os/staging;
|
| 270 |
|
- |
# if it turns out to need its own COPR, add here.
|
|
269 |
+ |
# satty (screenshot annotator) needs no COPR. It resolves from Terra, at
|
|
270 |
+ |
# 0.21.1-1.fc43 — checked 2026-07-30 by repoquery against the full repo
|
|
271 |
+ |
# set this file configures, which is the only way to answer it, since the
|
|
272 |
+ |
# question is which of four enabled repos wins.
|
|
273 |
+ |
#
|
|
274 |
+ |
# This block used to say satty "is expected in ublue-os/staging", and it
|
|
275 |
+ |
# was not there: repoquery with terra absent returns nothing for satty at
|
|
276 |
+ |
# all. The install line worked the whole time because Terra was answering
|
|
277 |
+ |
# a question nobody had asked it. Recording the wrong repo costs nothing
|
|
278 |
+ |
# until someone drops the one that was actually carrying the package.
|
| 271 |
279 |
|
|
| 272 |
280 |
|
# =====================================================================
|
| 273 |
281 |
|
# Fonts pulled from upstream releases (not cleanly packaged in Fedora):
|
| 487 |
495 |
|
# and is also the install path for ungoogled-chromium.
|
| 488 |
496 |
|
podman \
|
| 489 |
497 |
|
flatpak \
|
|
498 |
+ |
# Secrets (docs/STACK.md#secrets). Two different jobs, and only the
|
|
499 |
+ |
# first of them is about Max's own logins.
|
|
500 |
+ |
#
|
|
501 |
+ |
# gnome-keyring is the Secret Service provider, and it is here
|
|
502 |
+ |
# because its absence broke Make Creative's own software on Make
|
|
503 |
+ |
# Creative's own distro. Nothing in the image registered
|
|
504 |
+ |
# org.freedesktop.secrets, and the Rust `keyring` crate and Tauri's
|
|
505 |
+ |
# credential plumbing both resolve to it on Linux, so GoingsOn and
|
|
506 |
+ |
# Balanced Breakfast had nowhere to put a credential and
|
|
507 |
+ |
# synckit-client had nowhere to persist its E2EE key. That surfaces
|
|
508 |
+ |
# as a confusing runtime error inside an app, four layers from the
|
|
509 |
+ |
# cause.
|
|
510 |
+ |
#
|
|
511 |
+ |
# gnome-keyring-pam is a SEPARATE package and not a weak dependency
|
|
512 |
+ |
# of the one above, which matters more than it looks. Fedora's
|
|
513 |
+ |
# /etc/pam.d/greetd already carries the two stanzas that unlock the
|
|
514 |
+ |
# keyring with the login password, and both are `-` prefixed:
|
|
515 |
+ |
#
|
|
516 |
+ |
# -auth optional pam_gnome_keyring.so
|
|
517 |
+ |
# -session optional pam_gnome_keyring.so auto_start
|
|
518 |
+ |
#
|
|
519 |
+ |
# A leading `-` tells PAM to skip a module it cannot load, without a
|
|
520 |
+ |
# word in any log. So the provider alone gets you a Secret Service
|
|
521 |
+ |
# that works and a keyring locked behind a second password prompt
|
|
522 |
+ |
# nobody chose, and the config that was supposed to prevent that is
|
|
523 |
+ |
# sitting right there looking correct. Same defect class as the
|
|
524 |
+ |
# emoji alias and the swayosd unit path: configuration that is
|
|
525 |
+ |
# correct about something absent. Both packages or neither.
|
|
526 |
+ |
#
|
|
527 |
+ |
# Nothing here ships a /etc/pam.d file. greetd owns that one and the
|
|
528 |
+ |
# stanzas are already in it, so the fix is a package rather than a
|
|
529 |
+ |
# config edit; the assertion further down is what keeps that true.
|
|
530 |
+ |
#
|
|
531 |
+ |
# KeePassXC also provides the interface and was rejected for
|
|
532 |
+ |
# dragging Qt into a ratatui/egui design language, not on
|
|
533 |
+ |
# capability. systemd-creds is unrelated and stays: service
|
|
534 |
+ |
# credentials for daemons, no interactive component.
|
|
535 |
+ |
gnome-keyring \
|
|
536 |
+ |
gnome-keyring-pam \
|
|
537 |
+ |
# gopass is the password manager, on its age backend, synced by git
|
|
538 |
+ |
# (decided 2026-07-30). Fedora main carries it at 1.16.1; no COPR.
|
|
539 |
+ |
# It needs no gpg on the age backend, and the git half is the `git`
|
|
540 |
+ |
# already named below.
|
|
541 |
+ |
gopass \
|
| 490 |
542 |
|
# -----------------------------------------------------------------
|
| 491 |
543 |
|
# Session prerequisites — not curated picks. See the header above.
|
| 492 |
544 |
|
# fedora-bootc is a server base; everything in this group is
|
| 778 |
830 |
|
RUN grep -q -- '--cmd alloy-session' /etc/greetd/config.toml \
|
| 779 |
831 |
|
|| { echo "greetd does not launch the session wrapper; the skeleton would never be applied" >&2; exit 1; }
|
| 780 |
832 |
|
|
|
833 |
+ |
# =====================================================================
|
|
834 |
+ |
# The Secret Service — assert the provider is reachable and its unlock
|
|
835 |
+ |
# is not inert.
|
|
836 |
+ |
#
|
|
837 |
+ |
# Three things have to hold together for an app to store a credential
|
|
838 |
+ |
# without prompting, and every one of them fails quietly on its own.
|
|
839 |
+ |
#
|
|
840 |
+ |
# 1. Something has to claim org.freedesktop.secrets. That is a D-Bus
|
|
841 |
+ |
# activation file, not a running daemon: the bus starts
|
|
842 |
+ |
# gnome-keyring-daemon on the first call. Absent, the `keyring`
|
|
843 |
+ |
# crate returns an error from inside the app, which is where this
|
|
844 |
+ |
# whole task started.
|
|
845 |
+ |
# 2. pam_gnome_keyring.so has to be loadable, or the `-` prefixed
|
|
846 |
+ |
# stanzas in greetd's PAM stack are skipped in silence and the
|
|
847 |
+ |
# keyring stays locked behind a second prompt. The module is in
|
|
848 |
+ |
# gnome-keyring-pam, a separate package; see the install group.
|
|
849 |
+ |
# 3. greetd's PAM stack has to still carry those stanzas. They are
|
|
850 |
+ |
# Fedora's, not Alloy's, so nothing in this repo would notice them
|
|
851 |
+ |
# leaving. Alloy ships no /etc/pam.d file, which is deliberate —
|
|
852 |
+ |
# copying greetd's stack in to add two lines it already has means
|
|
853 |
+ |
# owning a file that upstream keeps changing — and the cost of not
|
|
854 |
+ |
# owning it is exactly this check.
|
|
855 |
+ |
#
|
|
856 |
+ |
# The `auto_start` on the session line is named rather than matched
|
|
857 |
+ |
# loosely: without it the module authenticates against the keyring and
|
|
858 |
+ |
# never starts the daemon, which reads as the unlock working right up
|
|
859 |
+ |
# until an app asks for a secret.
|
|
860 |
+ |
# =====================================================================
|
|
861 |
+ |
RUN set -eux; \
|
|
862 |
+ |
service=/usr/share/dbus-1/services/org.freedesktop.secrets.service; \
|
|
863 |
+ |
[ -f "$service" ] \
|
|
864 |
+ |
|| { echo "nothing claims org.freedesktop.secrets; every app using the keyring crate fails at runtime" >&2; exit 1; }; \
|
|
865 |
+ |
grep -q '^Name=org.freedesktop.secrets$' "$service" \
|
|
866 |
+ |
|| { echo "$service no longer claims the org.freedesktop.secrets name" >&2; exit 1; }; \
|
|
867 |
+ |
module=$(find /usr/lib64/security /usr/lib/security -name pam_gnome_keyring.so 2>/dev/null | head -n 1); \
|
|
868 |
+ |
[ -n "$module" ] \
|
|
869 |
+ |
|| { echo "pam_gnome_keyring.so is absent; greetd's '-' prefixed stanzas would be skipped silently and the keyring would prompt separately" >&2; exit 1; }; \
|
|
870 |
+ |
grep -q '^-*auth .*pam_gnome_keyring\.so' /etc/pam.d/greetd \
|
|
871 |
+ |
|| { echo "greetd's PAM stack no longer unlocks the keyring on auth; Alloy would have to ship its own /etc/pam.d/greetd" >&2; exit 1; }; \
|
|
872 |
+ |
grep -q '^-*session .*pam_gnome_keyring\.so.*auto_start' /etc/pam.d/greetd \
|
|
873 |
+ |
|| { echo "greetd's PAM stack no longer starts the keyring daemon at session open; secrets would fail after a login that looked fine" >&2; exit 1; }; \
|
|
874 |
+ |
echo "secret service: provider present, $module loadable, greetd unlocks it"
|
|
875 |
+ |
|
|
876 |
+ |
# gopass, and the one thing about it that can be wrong without saying so.
|
|
877 |
+ |
#
|
|
878 |
+ |
# The store is age-backed rather than GPG-backed (docs/STACK.md#secrets),
|
|
879 |
+ |
# and age support is compiled into gopass rather than shipped as a plugin,
|
|
880 |
+ |
# so a Fedora build with the feature dropped would still install, still
|
|
881 |
+ |
# run, and only fail when a store is initialized. `gopass age --help` is
|
|
882 |
+ |
# the cheapest question that distinguishes the two.
|
|
883 |
+ |
#
|
|
884 |
+ |
# HOME is redirected at a temporary directory and the directory removed,
|
|
885 |
+ |
# which is not tidiness. gopass writes a config file on any invocation,
|
|
886 |
+ |
# including one that only asks for help, so the plain form of this check
|
|
887 |
+ |
# bakes /root/.config/gopass/config into the shipped image: a config for
|
|
888 |
+ |
# an account with no store, authored by a build step, sitting where the
|
|
889 |
+ |
# real one would go the first time anyone runs gopass as root. A guard
|
|
890 |
+ |
# that leaves state behind is a guard that changes what it was checking.
|
|
891 |
+ |
RUN command -v gopass >/dev/null \
|
|
892 |
+ |
|| { echo "gopass is missing; docs/STACK.md names it as the password manager" >&2; exit 1; }
|
|
893 |
+ |
RUN set -eux; \
|
|
894 |
+ |
probe=$(mktemp -d); \
|
|
895 |
+ |
HOME="$probe" gopass age --help >/dev/null 2>&1 \
|
|
896 |
+ |
|| { rm -rf "$probe"; echo "this gopass build has no age backend; the whole reason it was picked over pass is gone" >&2; exit 1; }; \
|
|
897 |
+ |
rm -rf "$probe"; \
|
|
898 |
+ |
[ ! -e /root/.config/gopass ] \
|
|
899 |
+ |
|| { echo "the gopass probe wrote into /root anyway; it would ship in the image" >&2; exit 1; }
|
|
900 |
+ |
|
| 781 |
901 |
|
# =====================================================================
|
| 782 |
902 |
|
# The screenshot helper — assert the binds reach it.
|
| 783 |
903 |
|
#
|