Reverts incorrect touch_long_press_time option (not a real Hyprland setting).
Adds evdev-right-click-emulation install + systemd enable to the tablet (T)
eww bar selection in the hyprlua installer.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds w3m to the install list and appends the text/html mailcap entry
so alot renders HTML emails as plain text via w3m -dump.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The glob path = .../calendars/* was not expanded by khal, so no events
were visible. Now caldav-sync.sh and ics-to-calendarim both generate
explicit [[name]]/path entries per calendar and regenerate the config
on every sync so newly discovered calendars are picked up automatically.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Installs vdirsyncer + khal, writes vdirsyncer/khal configs, creates
ics-to-calendarim converter to populate calendar.vim local JSON cache,
and sets up a systemd user timer for 15-minute periodic sync.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- x now opens a full-screen overlay: alot left (55%), abook top-right,
calendar bottom-right
- Add esc = exit bindings to alot config for search/thread/taglist/
bufferlist modes, applied to live ~/.config/alot/config and to the
mail-notmuch.sh setup script
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace tab/vsplit PIM approach with nvim_open_win floating windows:
r opens a tiled full-screen overlay (alot top, calendar+abook bottom)
n/g/f open individual centered floats with rounded border
- Add setup/modules/optional-Modules/apps/mail-notmuch.sh:
configures mbsync, msmtp, notmuch, alot from interactive prompts
installs a systemd user timer for 5-min periodic mail sync
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Pin pamu2fcfg enrollment to the target hostname (-o/-i pam://$HOSTNAME)
so the credential origin matches pam_u2f.so at runtime; enrolling outside
the chroot previously used the live ISO hostname, causing auth to fail
- Add `cue` to the pam_u2f.so PAM line so ly prompts the user to touch
the key after password entry
- Add --needed to hyprlua AUR yay call to survive re-runs
- Degrade gracefully in lamco-rdp-server when no user D-Bus session is
active (systemctl --user enable would abort the module under set -e)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add modules/lib/logging.sh with log(), skip(), warn(), err() helpers.
Source it in all 84 scripts (core, DEs, optional apps) and replace bare
echo calls with structured log messages. Add log file capture to install.sh.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
sauerbraten: open-source Cube 2 FPS (pacman)
stuntrally: rally racing game via Flatpak (io.github.stuntrally.StuntRally3)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
openarena: open-source Quake III Arena (pacman)
tetris: bastet + vitetris (pacman + AUR)
doom: Chocolate Doom + Freedoom game data (pacman)
Wired up in simple-install.sh, tui-install.sh, and install-modules.sh.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
policy-scan-notify is now a FreeIPA *user* group instead of a host group,
so alert notifications follow the user to every enrolled machine. The
fetch-alerts timer is installed fleet-wide on any host where the group exists;
the profile.d snippet gates notification daemon start on runtime group
membership (id(1) / SSSD) so non-members log in unaffected.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
policy-block-binary-<name> is now a FreeIPA *user* group instead of a host group,
so restrictions follow the user to every enrolled machine. The PATH wrapper is
installed on all hosts and checks group membership at runtime via id(1)/SSSD,
passing non-members through transparently. __ in the group name decodes to .
so Flatpak app IDs are supported (flatpak run fallback included). AppArmor layer
removed since per-user confinement requires a different approach and the wrapper
alone is sufficient. Adds local_sudo_<username> host group policy which writes
a sudoers drop-in granting that user full sudo on the specific device, reverted
on group leave.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a new host group policy `no_local_users` that locks the passwords of root
and all local users (UID >= 1000) via `passwd -l`, ensuring only FreeIPA domain
accounts with centrally-managed sudo rules can authenticate and gain elevated
privileges. Leaving the group reverts by unlocking every account tracked in the
state file. Updates docs with group reference entry and Local User Lockdown section.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ansipa-smb-setup.sh:
- Adds KeyAdmin Linux group and luks-upload service account (member of
KeyAdmin) on the IPA container, both persisted across restarts.
- LUKS base dir /data/luks-keys owned root:KeyAdmin, mode 2750 (setgid
so new files inherit the group).
- New [ansipa-luks-keys] SMB share: valid users = @KeyAdmin, read only,
write list = luks-upload. Human admins gain read access by being added
to KeyAdmin: useradd -r -G KeyAdmin <user> && smbpasswd -a <user>.
- LUKS_KEY_UPLOAD_PASSWORD sourced from env / /data/samba/ansipa-smb.env
alongside the existing SMB_SCAN_PASSWORD.
collect-luks-keys.yml:
- After fetching /_LUKS_BACKUP_KEY from each client, uploads it to the
ansipa-luks-keys share via smbclient using a temp credentials file
(no_log, deleted in post_tasks).
- Local staging copy is removed after a successful upload.
- SMB credentials file uses an epoch-stamped path to avoid collisions.
.env.example: documents LUKS_KEY_UPLOAD_PASSWORD.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Host groups named policy-daemon-enable-<unit> and
policy-daemon-disable-<unit> are now matched by a wildcard case arm in
the group parser — no per-service configuration required.
Enforcement (every 30 min via existing timer):
enable: systemctl enable --now <unit>; state written to
/var/lib/ansipa-policies/daemon-enabled
disable: systemctl disable --now <unit>; state written to
/var/lib/ansipa-policies/daemon-disabled
revert: when a host leaves a group the opposite action is applied
on the next run (enable→disable, disable→enable)
conflict: unit in both lists is skipped with a warning
The .service suffix is optional — _svc_unit() appends it when the name
contains no dot, so all systemd unit types work as-is.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Installs lamco-rdp-server from AUR (native Wayland RDP server, Rust,
H.264/VA-API). Enables lamco-rdp-server.service as a systemd user
service. Wired into tui-install.sh alongside the existing rdp-client
and qemu entries.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
rdp-client.sh: installs Remmina with the FreeRDP and libvncserver plugins
for RDP and VNC sessions.
qemu.sh: installs the full QEMU/KVM stack (qemu-full, libvirt, virt-manager,
virt-viewer, dnsmasq, bridge-utils, edk2-ovmf, swtpm, vde2), enables and
starts libvirtd, auto-starts the default NAT network, and adds the user to
the libvirt and kvm groups.
Both modules are wired into tui-install.sh: count_steps, checklist,
confirmation summary, and run_module dispatch.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ansipa-smb.service: WantedBy=multi-user.target (was smb.service) so the
setup service always runs at boot, not only when smb.service pulls it in
docker-compose.yml: add NetBIOS UDP ports 137/138 to match Dockerfile EXPOSE
and nmb.service being enabled
ansipa-smb-setup.sh:
- use printf '%q' when writing SMB_SCAN_PASSWORD to ansipa-smb.env so
passwords with spaces or shell-special chars are correctly quoted
- always write /etc/cron.d/ansipa-check-scans (remove the [[ ! -f ]] guard)
since /etc/cron.d is on the ephemeral container layer and is lost on
container recreation; the service runs on every start anyway
Dockerfile: add -e SMB_SCAN_PASSWORD and -p 445:445 to the quick-test comment
ansipa-fetch-alerts.sh: replace $NEW && log with [[ "$NEW" == true ]] && log
to avoid set -e ambiguity with the 'false' builtin
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Container (ansipa image):
- Add samba + cronie to Dockerfile; expose ports 445/139
- ansipa-smb-setup.sh: idempotent setup of smbd + scanupload user +
/data/scan-results/{archive,alerts}/ on every container start
- ansipa-smb.service: runs setup before smb.service on each boot
- ansipa-check-scans.sh: hourly cron on server; analyses archive logs for
ClamAV/rkhunter/chkrootkit findings and writes <host>/<date>.alert files
- docker-compose.yml: add SMB_SCAN_PASSWORD env var + port mappings
- .env.example: document SMB_SCAN_PASSWORD
Client (policy-security-scan):
- Scan script now uploads log to //ipa-server/ansipa-scans/archive/<host>/
via smbclient after each run
Client (policy-scan-notify — new policy group):
- ansipa-fetch-alerts.sh: root timer (10 min) downloads alerts from SMB into
~/administration/<hostname>/ for each active login session; deletes server
alert when user removes local file (acknowledgment)
- ansipa-scan-notify.sh: user daemon started via /etc/profile.d/ansipa-notify.sh;
sends notify-send every 10 min while *.alert files remain in ~/administration/
- deploy-ansipa-policies.yml: installs samba-client, deploys SMB creds file
(/etc/ansipa-smb.creds, 0600), and deploys both notification scripts
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Binary blocking now applies two layers:
1. PATH-priority wrapper in /usr/local/bin/ (existing)
2. Empty AppArmor profile in /etc/apparmor.d/ loaded in enforce mode
An empty AppArmor profile denies all access — the blocked binary cannot
load shared libraries and exits immediately with a permission error,
covering callers that use absolute paths and bypassed the wrapper.
AppArmor layer is skipped silently when apparmor_parser is not present,
and deferred with a warning if the real binary is not yet installed.
Profiles are unloaded and deleted when the host leaves the policy group.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Qt: replace QT_STYLE_OVERRIDE/QT_STYLE_SHEET env vars with QT_QPA_PLATFORMTHEME=qt6ct +
QT_QUICK_CONTROLS_STYLE=Fusion; add cyberqueer Qt6 style plugin (QProxyStyle wrapping
Fusion with hardcoded dark palette); enable custom_palette in qt6ct.conf so qt6ct applies
the dark QPalette directly for both Qt Widgets and Qt Quick apps.
GTK: fix dark mode not applying — set gtk-application-prefer-dark-theme=1 in GTK3
settings.ini; add gsettings color-scheme=prefer-dark to install script (required by
libadwaita apps which ignore gtk-theme-name); add index.theme so the theme is recognized
by GTK theme discovery.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
airline#themes#cyberqueer#palette was undefined because the theme file was
being copied under the wrong name (cyberqueer-airline.vim instead of
cyberqueer.vim). Fixed by adding the file at the proper rtp-relative path
nvim/autoload/airline/themes/cyberqueer.vim — picked up automatically via
the ~/.config/nvim symlink, no extra copy step needed. Removed the now-
redundant manual cp from shell-setup.sh.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Renames nvim/ → nvim.old/ (preserving init.vim + incomplete prior attempts)
and creates a fresh nvim/ with init.lua. All settings, keymaps, and plugin
declarations are converted from VimScript to Lua idioms. Plugin manager
migrated from vim-plug to lazy.nvim, which self-bootstraps on first launch.
shell-setup.sh updated to drop the vim-plug curl install; the symlink and
airline theme copy are retained (path updated for lazy's data directory).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Duplicates desktopenvs/hyprland/ as desktopenvs/hyprlua/ and converts all
Hyprland-specific configs (.conf) to Lua (.lua) using the 0.55+ hl.* API:
hyprland.lua, envvars.lua, monitors.lua, input.lua, autostart.lua,
windowrules.lua, binds.lua. Non-Hyprland tool configs (hyprpaper, hyprlock,
hypridle, hyprtoolkit) remain as .conf. Adds hyprlua.sh installer (user-side
.lua files install to ~/.config/hypr/ for require() resolution) and registers
HyprLua as the recommended DE option in tui-install.sh, marking the old
hyprlang-based Hyprland install as legacy.
Also consolidates hyprland (legacy) env vars into hypr-usr/envvars.conf,
removing duplicates from hyprland.conf and monitors.conf.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
New playbook collect-luks-keys.yml connects to all enrolled FreeIPA
clients, checks for /_LUKS_BACKUP_KEY (placed there by the installer
when encryption is enabled), and fetches each key to the Ansible
controller as luks-keys/<HOSTNAME>_LUKS_BACKUP_KEY (mode 0400).
Hosts without the file are reported but not treated as errors.
The luks-keys/ store directory is created with mode 0700.
Usage:
ansible-playbook -i inventory collect-luks-keys.yml
Can be scheduled via cron on the controller for automatic collection.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
New optional modules (browsers): chromium, firefox, zen-browser,
nyxt, librewolf, min-browser.
New optional modules (editors/IDEs): vscodium, zed, geany,
codeblocks, kate.
Add lynx to default core packages.
All 11 modules wired into both install-modules.sh and tui-install.sh
(the archiso-embedded installer) with consistent count_steps,
checklist, summary, and dispatch entries. Every module path verified
to exist; all scripts pass bash -n syntax check.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add bc, dmidecode, dosfstools, e2fsprogs, fzf, git, hdparm, lshw, lsof,
openbsd-netcat, parted, ripgrep, rsync, strace, sysstat, tmux, and whois —
utilities that ship by default on most distros or are now effectively standard.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Each script installs the DE meta-package, an appropriate display manager,
PipeWire audio, NetworkManager, Bluetooth, and Flatpak, then enables the
relevant services (sddm/gdm/lightdm/cosmic-greeter).
COSMIC falls back to sddm if cosmic-greeter is not installed.
tui-install.sh: DE menu expanded from 3 to 8 entries (height 20×70).
install-modules.sh: DEs added to checklist, summary, and dispatch so
they can be installed standalone on an existing system.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
IPA group naming: fp_install_org__mozilla__firefox (dots encoded as __)
Decoding: sed strips prefix, then s/__/./g restores the Flatpak app ID.
Single underscores in app IDs are preserved unambiguously.
ansipa-install-flatpaks.sh:
- kinit with host keytab, queries ipa group-find --pkey-only with awk $NF
- Validates decoded ID against reverse-domain regex before installing
- Ensures flathub system remote exists
- System-scope install (flatpak install --system) since service runs as root
- Timer offset to 4 min (after packages at 2 min) to avoid contention
deploy-ansipa-install.yml updated to deploy the Flatpak script, service,
and timer alongside the existing package installer.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Presents a Cyberqueer-themed menu after package install:
- Answerfile: prompts for path (defaults to FreeipaAnsible/freeipa-client-answerfile.json),
offers to create one with defaults if it doesn't exist
- Manual: dialog inputboxes for domain, realm, server, hostname, principal,
passwordbox for the admin password, yes/no for mkhomedir/sudo/dns/fido2
- Skip: prints post-install hints
Falls back to ipa-client-install directly if freeipa-client.sh is not
available (standalone install outside the dotfiles repo).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add freeipa-client module (sssd, cyrus-sasl-gssapi, freeipa-client AUR)
with post-install enrollment hints; wired into tui-install.sh and
install-modules.sh
- Add ansipa-install-modules.sh: reads IPA host groups named
ansipa-module-<name>, applies matching module scripts via a yay wrapper
that drops to ANSIPA_USER so AUR builds work from the root service
- Add ansipa-install-modules.service + .timer (boot + 30 min)
- Add deploy-ansipa-modules.yml Ansible playbook that deploys scripts,
writes /etc/ansipa-modules.conf, and enables the timer
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The previous proxmox-vm target (virt-customize + QCOW2) is replaced with
a proper Proxmox LXC CT template builder:
- Exports container rootfs as .tar.zst (same mechanism as the lxc target)
- Asks for CT ID, storage, bridge, memory, cores, disk size
- Generates pve-ct-<VMID>.conf with the required FreeIPA LXC options:
unprivileged: 0
lxc.apparmor.profile: unconfined
lxc.cap.drop:
lxc.mount.auto: proc:rw sys:rw cgroup:rw
lxc.cgroup2.devices.allow: a
- Generates proxmox-lxc-setup.txt with the full 6-step setup guide
(upload, pct create, apply LXC opts, set env vars, start, Keycloak)
- Optionally uploads template + conf to Proxmox host via SCP if a
host is provided
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
freeipa-image-builder.sh: TUI chooser that builds a FreeIPA server image
and exports it to four target formats:
docker — builds via podman/docker, optional registry push
lxc — exports container rootfs as .tar.zst Proxmox CT template,
generates pct import instructions
proxmox-vm — downloads Rocky/Fedora cloud image, customizes with
virt-customize, outputs QCOW2 + cloud-init user-data.yml
oci-archive — skopeo OCI tarball for air-gapped import
Keycloak TUI option generates the full constellation:
docker-compose.yml FreeIPA + Keycloak + PostgreSQL stack
.env pre-filled env template (passwords placeholder)
keycloak-configure.sh post-start Keycloak REST API config script
image/Dockerfile: Fedora 41 + freeipa-server-dns + ansible-core,
systemd-enabled container (CMD /sbin/init).
image/ipa-first-boot.{sh,service}: systemd oneshot that runs
ipa-server-install on first container/VM boot from env vars
(IPA_DOMAIN, IPA_ADMIN_PASSWORD, IPA_DM_PASSWORD, and optionals).
ConditionPathExists=!/etc/ipa/default.conf makes it idempotent.
image/keycloak-configure.sh: Keycloak REST API automation that:
- waits for Keycloak readiness
- creates a realm
- wires FreeIPA LDAP user federation (READ_ONLY, vendor=rhds)
- adds attribute mappers: email, firstName, lastName, uidNumber
- adds group mapper (IPA groups → Keycloak groups, cn=groups,cn=accounts)
- triggers an initial full user sync
image/docker-compose.yml: freeipa + postgres + keycloak services on
a private 172.30.0.0/24 bridge; FreeIPA has a fixed IP so Keycloak
can resolve it via extra_hosts.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Installs open-webui from AUR and enables open-webui.service.
Serves the browser UI at http://localhost:8080; Ollama module
should be installed first for full LLM backend functionality.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
podman, podman-compose, cockpit, cockpit-files, cockpit-podman all have
dedicated optional modules — no reason to install them on every system.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ollama.sh: installs from official repos, enables ollama.service, notes
GPU sharing caveat with llama.cpp. For NVIDIA/AMD GPU variants use
ollama-cuda or ollama-rocm from AUR instead.
llama-cpp.sh: standalone inference CLI and server via yay (covers both
official repos and AUR). Both modules coexist at the package level;
docker/podman/cockpit modules confirmed conflict-free (all use --needed,
podman+cockpit base packages already in core-packages.sh).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Installs @anthropic-ai/claude-code via npm, sourcing nvm if npm is not
already in PATH. Wired into tui-install.sh and install-modules.sh.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>