Commit Graph

1181 Commits (b3b46a125bec55ce9e702e508a43aae035b14182)

Author SHA1 Message Date
Amir Alexander Abdelbaki b3b46a125b build(hyprlua): package astal-menu's new deps; Super+D opens from top
- Installer: add python-pillow (map tile stitching) and networkmanager (the Network
  quad's nmcli backend) so a fresh install has a working map and network panel.
- Super+D binds explicitly to `menu-toggle.sh toggle top` so it pops in from the top.

The astal-menu config (incl. new backend/nm.py, ui/statsbar.py, etc.) already ships
via the config-updater CONFIGS list and is re-synced by sysupdate.sh; settings live
in XDG_STATE_HOME so updates don't wipe them.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XUWCXM4KhjRkwheaA3X7bP
2026-07-06 09:29:58 +02:00
Amir Alexander Abdelbaki 57dede403e feat(astal-menu): stats line, side-slide flag, drawer pop, tighter buttons
- Add a minimalist system-stats line at the top of the panel: CPU / MEM / GPU / disk
  utilisation + network down/up rate, read straight from /proc and /sys on a 2s timer
  (no subprocess). ui/statsbar.py.
- Opening side is selectable: `main.py --side top|bottom|left|right` (also via
  `menu-toggle.sh <verb> <side>` or just `menu-toggle.sh <side>`). The panel anchors
  flush to that edge, and the compositor's layer slide brings it in from there.
  Unified all layer anchoring into MenuWindow._apply_anchor.
- App drawer now does a bouncy pop-expand (CSS scale, play-once guard like the quads).
- Tighten the action-pill buttons vertically (padding 6->1px, min-height 32->22) so
  they stop wasting vertical space.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XUWCXM4KhjRkwheaA3X7bP
2026-07-06 09:26:37 +02:00
Amir Alexander Abdelbaki e63c99f299 feat(astal-menu): pannable map with night/satellite tiles
The Location map was a fixed static image with no way to move the viewport, on the
light OSM tiles. Now:
- Drag to pan (re-renders at the new centre; the pin stays anchored to the real
  location and clamps to the edge when panned away), scroll to zoom, double-click to
  recentre. Panning/zooming coalesce into ~11 renders/sec.
- Tiles default to the dark CartoDB "night" map (fits the theme); a new "Satellite
  view" feature toggle switches to Esri World Imagery. staticmap.py gained a style
  arg + a separate marker coordinate, and caches tiles per style.

Verified: dark + satellite render, drag re-centres the view (pin goes off-centre),
and the coordinate round-trip is exact.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XUWCXM4KhjRkwheaA3X7bP
2026-07-06 08:59:05 +02:00
Amir Alexander Abdelbaki abea1bec43 feat(astal-menu): Bluetooth connect status + Forget button
- Connect flow now shows real status: a spinner + Cancel while connecting, and a red
  "failed" tag + Retry if the attempt stops without linking (via notify::connecting
  going false) or a 25s timeout backstop fires. Previously Connect gave no feedback
  and could look stuck forever.
- Add a Forget button on paired devices (adapter.remove_device) to unpair them.
- Track per-device pending/failed state so the row reflects connecting/failed/
  connected/paired accurately.

Verified the paired row renders Forget + Connect and the connected row renders
Forget + Disconnect.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XUWCXM4KhjRkwheaA3X7bP
2026-07-06 08:43:13 +02:00
Amir Alexander Abdelbaki e79d427c2a fix(astal-menu): refresh Bluetooth list on device connection changes
The device rows already render a "Disconnect" button when a device is connected,
but the list only rebuilt on adapter-level notify::devices / notify::is-powered —
not on per-device state changes. So a device connected (via the menu or elsewhere)
while the menu was open kept its "Connect" button and offered no way to disconnect.
Hook each device's notify::connected/connecting/paired (once each) to refresh the
list, so a connected device flips to "Disconnect".

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XUWCXM4KhjRkwheaA3X7bP
2026-07-06 00:17:35 +02:00
Amir Alexander Abdelbaki 5cd880c388 screw the presence detect 2026-07-06 00:16:06 +02:00
Amir Alexander Abdelbaki 221d0dde55 fix(astal-menu): keep toggle switches pill-shaped (valign center)
Switches sat with the default FILL vertical alignment, so in taller rows (e.g. the
Bluetooth Power switch in the expanded card's header) they stretched to the row
height and rendered as a squared/vertical blob. Give every Gtk.Switch
valign=CENTER so it keeps its fixed pill height regardless of the row.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XUWCXM4KhjRkwheaA3X7bP
2026-07-06 00:12:16 +02:00
Amir Alexander Abdelbaki 0e8cdd5335 fix(astal-menu): play the quad-expand pop once, not on a loop
The .quad-pop CSS animation stayed applied for the whole time a quad was expanded,
so every re-layout of the expanded card (module content streaming in, the compact
grid updating beneath the overlay) restarted the transform animation — making the
pop repeat continuously. Remove the class ~340ms after expanding (just past the
300ms animation) so it plays exactly once and no later re-layout can retrigger it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XUWCXM4KhjRkwheaA3X7bP
2026-07-06 00:06:18 +02:00
Amir Alexander Abdelbaki 6a5a5bce97 feat(astal-menu): bouncy slide-in on open, springy pop on quad expand
- Main open: enable Hyprland's `layers` animation with the bouncy myBezier curve and
  a slide style, so the layer-shell control centre slides in from the top edge with a
  little overshoot instead of just appearing. (Also gives notifications/bar the same
  springy slide, which suits the DE.) A per-namespace layerrule was tried first but
  this hyprlua build doesn't honour its animation timing.
- Quad expand: a CSS @keyframes scale-bounce (scale 0.82 -> 1.05 -> 1.0) added to the
  expanded card on expand and cleared on collapse so it replays every time. Verified
  GTK4 CSS transforms/keyframes render on this build, and that the card scales during
  the animation.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XUWCXM4KhjRkwheaA3X7bP
2026-07-06 00:00:14 +02:00
Amir Alexander Abdelbaki 3aafd2cc17 fix(astal-menu): working favourites, 3-day weather, deploy-safe settings
Favourites:
- Pin/unpin from the drawer never worked: the right-click / long-press gestures
  were added to a Gtk.Button in the default (bubble) phase, where the button's own
  primary-click gesture swallowed them. Move them to the CAPTURE phase and claim the
  sequence (shared add_pin_gestures helper) so they fire reliably and don't also
  launch the app.
- Show a ★ on pinned tiles and re-render tiles when favourites change, so the state
  is visible and updates live.
- Verified end-to-end (right-click pins, right-click again unpins).

Weather: the expanded quad showed current conditions only. weather.sh used
`${2:-0}`, which rewrote the expanded view's intentionally-empty opts to "0"
(current only); use `${2-0}` so the empty value reaches wttr.in as its default
3-day forecast. Verified the expanded view now renders all three days.

Settings: move settings.json from CONFIG_DIR to XDG_STATE_HOME. The config-updater
`rm -rf`s ~/.config/astal-menu on every deploy, which was wiping pinned favourites
and quad toggles; the state dir is untouched by config sync. Migrates the old file.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XUWCXM4KhjRkwheaA3X7bP
2026-07-05 23:35:23 +02:00
Amir Alexander Abdelbaki 16f75edb13 style(astal-menu): fixed-shape switches, inset close button, shorter panel, uniform expand icons
- Switches: give them a fixed pill with a bordered round knob (the reset theme
  left them shapeless).
- Close (x) button: inset with a margin so it no longer overlaps the drawn border.
- Height: the panel overflowed the monitor. Trim the map compact height, quad
  min-height, card padding, grid/panel spacing, top margin, and drawer strip so it
  fits (≈1600 -> ≈1310 logical on a 1440 display).
- App drawer expand button: use the same nf-fa-expand/compress glyphs as the module
  expand buttons instead of chevrons, so all expand controls look uniform.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XUWCXM4KhjRkwheaA3X7bP
2026-07-05 20:48:52 +02:00
Amir Alexander Abdelbaki d468d66e5f feat(astal-menu): NetworkManager control panel; single-ring settings/close buttons
Network expanded view is rewritten into four tabs over a new nmcli backend
(backend/nm.py, JSON in/out):
- Adapters: each device foldout with editable IPv4 and IPv6 — Automatic/DHCP
  toggle, address, a linked subnet-mask <-> CIDR pair (edit either, the other
  follows), gateway; applied via `nmcli connection modify/up`. Manual fields dim
  when DHCP is on.
- Routes: the kernel routing table (read-only; editing kernel routes needs root).
- VLAN: pick a parent device + ID to create/bring up a VLAN, list + activate/delete.
- DNS: effective servers per device + a per-connection override (servers +
  ignore-automatic).
Verified reads and the write path end-to-end (VLAN add/delete via nmcli; each tab
rendered in a harness).

Also: flatten the settings-cog MenuButton's inner `button` node so it shows one
ring instead of two, and drop the border on the close (x) button.

Weather keeps its wttr.in 3-day forecast (unchanged, per request).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XUWCXM4KhjRkwheaA3X7bP
2026-07-05 20:32:39 +02:00
Amir Alexander Abdelbaki 4e5ee4f9ba fix(astal-menu): single module border; unblock rfkill so Bluetooth powers on
- Borders: with the app stylesheet now above the theme, the CSS `.quad-card`
  border rendered a second ring concentric with the Cairo bordered() ring. Drop the
  CSS border/background/radius from the card boxes so only the Cairo card shows.
- Bluetooth: the power/scan/connect controls were correctly wired to AstalBluetooth,
  but the adapter was rfkill soft-blocked, making set_powered a silent no-op. The
  power toggle now runs `rfkill unblock bluetooth` before powering on.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XUWCXM4KhjRkwheaA3X7bP
2026-07-05 20:11:36 +02:00
Amir Alexander Abdelbaki 503b7f3336 fix(astal-menu): float modules on transparent gaps (beat theme's global bg)
The panel showed a solid #1a1a1a slab between modules. Root cause: the CyberQueer
GTK theme is installed as ~/.config/gtk-4.0/gtk.css (a symlink), which GTK4 loads
at PRIORITY_USER (800) — above our PRIORITY_APPLICATION (600) — and its reset rule
`* { background-color: #1a1a1a }` painted every node, including the structural
containers between modules. Our transparency overrides silently lost the cascade.

Fixes:
- theme.py: load the app stylesheets at USER+1 so they sit just above the
  user-level theme symlink and actually win.
- style.css: blank the structural container nodes (window/.panel/overlay/revealer/
  grid/scrolledwindow/viewport/drawingarea) so the desktop shows between modules.
- window.py/quadgrid.py: draw each module's card background with the Cairo
  bordered(fill_bg=True) so cards stay opaque (incl. rounded corners) while the
  gaps go transparent — this GTK build doesn't paint CSS backgrounds on containers,
  hence the Cairo fill.

Popovers/buttons keep their backgrounds (the theme's rule still covers those nodes;
only structural containers are overridden). Verified visually end-to-end.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XUWCXM4KhjRkwheaA3X7bP
2026-07-05 19:51:54 +02:00
Amir Alexander Abdelbaki 76194980cb fix(astal-menu): focus windows via hyprlua dispatcher, not native focuswindow
The Open-windows taskbar dispatched `hyprctl dispatch focuswindow address:…`,
but this is a hyprlua setup where `hyprctl dispatch` evaluates its argument as
Lua — so the native dispatcher syntax raised a Lua parse error and nothing
happened. Switch to `hl.dsp.focus({ window = "address:…" })`, the hyprlua focus
dispatcher, which focuses the window and switches to its workspace. Verified it
moves across workspaces end-to-end.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XUWCXM4KhjRkwheaA3X7bP
2026-07-05 19:22:37 +02:00
Amir Alexander Abdelbaki b9e80fbfbe fix(astal-menu): stop LD_PRELOAD leaking into launched apps (Firefox crash)
astal-menu-start.sh LD_PRELOADs libgtk4-layer-shell so it loads before
libwayland-client. That preload is only needed at the daemon's own exec — the
library is resident afterwards and the variable is never re-read — but every app
started via AstalApps.launch() inherited it, and Firefox aborts at startup with
libgtk4-layer-shell preloaded (gdk_display_manager_get() before gtk_init()).

main.py now drops LD_PRELOAD from its environment right after startup, so
launched GUI apps (and backend subprocesses) run with a clean env. Verified the
layer-shell library stays mapped and the menu surface still maps afterwards.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XUWCXM4KhjRkwheaA3X7bP
2026-07-05 19:14:16 +02:00
Amir Alexander Abdelbaki 277f04c65d fix(astal-menu): live-apply widget settings, float modules, IP-locate via traceroute
Widget settings popover toggles now take effect immediately. QuadCard only
rebuilt a card when its Enabled state flipped, so per-module feature toggles
(Wi-Fi, discovery, routes, CLI art, …) were persisted but never applied. The
card now rebuilds whenever any of its own feature values change, and the
incomplete partial per-module refresh callbacks (which also leaked a dead
subscription per rebuild) are dropped in favour of that single path.

Make the backmost surface transparent so each module floats on its own drawn
border/background: force `window`/`.background`/`.panel` transparent, since a
plain `.menu-window` rule did not override the GTK theme's solid window node.

Locate via IP now works and uses traceroute: geolocate.py traceroutes to
1.1.1.1, takes the first globally-routable hop (the ISP egress) and resolves it
through a public geolocation API, falling back to self-IP when traceroute is
missing or finds no public hop. The ip_locate toggle gates the lookup entirely
(placeholder when off). Adds `traceroute` to the hyprlua package list.

Autostart: `sleep 1 && hyprctl reload` after all spawns so layer-shell clients
settle on the final config.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XUWCXM4KhjRkwheaA3X7bP
2026-07-05 17:02:40 +02:00
Amir Alexander Abdelbaki 3d75182b54 feat(hyprlua): add astal-menu popup, replacing nwg-dock + nwg-drawer
A touch-friendly GTK4 popup control centre (Python + PyGObject, wlr-layer-shell)
launched from the EWW bar or Super+D. Replaces nwg-dock and nwg-drawer.

Layout: a floating, drawn-bordered panel (anchored top-centre so it never blocks
the rest of the screen) with a 2x2 quad grid over a full-width app drawer, plus a
top taskbar. Any quad expands over the others; the drawer expands to the bottom.

Modules:
- Location  — static OSM map (backend/staticmap.py) on IP geolocation
              (libshumate won't paint tiles in this env; shumate-demo is blank too)
- Weather   — wttr.in ANSI art rendered via an SGR parser into a TextView
- Bluetooth — AstalBluetooth: discovery/connect/disconnect + local history
- Network   — AstalNetwork wifi + nmcli/ip/ss for IP, DHCP/manual, routes, ports,
              public IP; per-feature toggles
- Taskbar   — open windows from hyprctl, grouped by app with pop-out per instance
- Favorites — pinned apps (right-click/long-press to pin) atop the app drawer

Notes:
- Frontend is Python/GTK4, not Lua: lgi/Astal-Lua are GTK3-only.
- Module borders are drawn with a Cairo overlay (lib/border.py); this GTK build's
  renderer skips CSS border/background on plain container widgets.
- Consumes Astal GObject libs (io/apps/network/bluetooth) via introspection.

Wiring: autostart + Super+D/Super+Shift+A binds, EWW launcher button in all three
bar variants, apply-theme.sh (_colors.css), installer packages, config-updater.
drawer.sh moved to scripts/deprecated/.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 00:11:39 +02:00
Amir Alexander Abdelbaki 654606df86 fix(hyprlua): spawn filepicker floating, compact, centred on the cursor
The dialog was landing off-cursor and at ~half-screen. Two Hyprland
gotchas were fighting each other: `move` is evaluated against the
window's natural size and `size` is applied afterwards from the top-left,
so a cursor_x-(window_w/2) move centred the pre-shrink window. zenity's
file chooser also ignores --width/--height and has a ~738x363 GTK
minimum.

Fix the size at 760x460 and hard-code the move offsets to half that
(380x230) so the shrunk window lands exactly on the pointer. Drop the
dead zenity --width/--height sizing from the script.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 15:06:37 +02:00
Amir Alexander Abdelbaki 54338f3602 feat(hyprlua): size filepicker dialog to 5% of the display
Add a size rule alongside the move so the zenity dialog no longer opens
at its default ~50% size. zenity clamps to its GTK minimum (~738x363),
which is well under half the screen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 14:58:06 +02:00
Amir Alexander Abdelbaki d9e6ee0f10 feat(hyprlua): move filepicker dialog to 5% of the display
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 14:52:52 +02:00
Amir Alexander Abdelbaki 8900fe0004 feat(hyprlua): spawn filepicker dialog at 10% of the display
Rename the at-cursor rule to filepicker and move the dialog to a fixed
position 10% into the display (from the top-left) instead of following
the cursor.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 14:51:55 +02:00
Amir Alexander Abdelbaki 3324e669bb feat(hyprlua): spawn filepicker dialog at cursor via +at-cursor tag
Add a dedicated at-cursor window rule (float + move to cursor) and point
the Super+F / Super+Shift+F filepicker binds at it, so the zenity dialog
opens centered on the mouse instead of mid-screen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 14:50:10 +02:00
Amir Alexander Abdelbaki 403023c096 feat(hyprlua): float filepicker-to-clipboard dialog via +centered tag
Prefix the Super+F / Super+Shift+F filepicker binds with [tag +centered]
so the zenity dialog spawns as a centered floating window (60% x 60%),
matching the centered rule in windowrules.lua. Same tagged-spawn
mechanism as Super+U.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 14:48:49 +02:00
Amir Alexander Abdelbaki 8ca1026552 feat(hyprlua): file-picker-to-clipboard binds on Super+F / Super+Shift+F
Add filepicker-clipboard.sh: a zenity file dialog that copies the
selected file's path (Super+F) or contents (Super+Shift+F) to the
clipboard via wl-copy. Path mode collapses $HOME to ~.

Repoints Super+F / Super+Shift+F from wofi-file-search/foldersearch
(kept as comments) in usr/binds.lua.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 14:43:00 +02:00
Amir Alexander Abdelbaki b879b1ae89 feat(greeter): cyberqueer ReGreet theme + wire greetd into installers
Add a self-contained CyberQueer login skin for the greetd/ReGreet greeter and
make it a first-class, selectable module.

Theme:
- New etc-greetd/regreet.css: login-specific stylesheet (glowing pink clock +
  card, violet-bordered combos, hot-pink Login, quiet red-outline power
  buttons). Loaded by ReGreet at APPLICATION priority over an Adwaita-dark base;
  regreet.toml theme_name switched cyberqueer->Adwaita to avoid the desktop
  theme's `* { all: unset }`. Redefines Adwaita's accent/destructive named
  colours so the semantic buttons recolour. Verified via headless demo render.
- Register regreet.css in apply-theme.sh SYS_FILES so palette edits propagate.

Installers:
- modules.conf: add greetd-regreet (three-way mutually exclusive with lightdm+ly).
- Regenerate tui-install.sh, generate-answerfile.sh, docs/md/modules.md via
  generate-modules.sh.
- install-modules.sh (hand-maintained): add greetd-regreet to counter/menu/
  summary/dispatch.

Migration:
- New migrate-to-greetd.sh: migrate to Plymouth + greetd/ReGreet (greetd is the
  target, so it's not in the disable list). migrate-to-lightdm.sh relabelled the
  Xorg alternative.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P1ApxGuM3N3nSiAJonSjMQ
2026-07-04 13:37:30 +02:00
Amir Alexander Abdelbaki 48c756d3e2 feat(plymouth): centred skull logo + boot-log tail, drop spinner
Rework the M-Archy splash: scale the skull to ~42% of screen height and
centre it instead of filling the screen, then draw the latest 3 boot-log
lines beneath it (fed by both the status and display-message callbacks).
Drops the imagemagick-generated dot.png throbber and its refresh loop.

Render the logo at 600px (down from 1920px) since it is no longer
full-screen, and only pull in imagemagick for the transparent-placeholder
fallback. migrate-to-lightdm purges the stale dot.png before re-running the
module so upgraded installs end up byte-clean. Update docs and module
labels ("skull logo + boot-log tail"), and simplify bg-skull.svg.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 03:18:44 +02:00
Amir Alexander Abdelbaki 29f6c62008 feat(greeter): switch to greetd+ReGreet (Wayland), fix FIDO/scaling/wallpaper
Replace the Xorg lightdm-gtk-greeter with a wlroots-native greetd + ReGreet
greeter (inside a cage kiosk), fixing three issues rooted in running an X
greeter on a multi-monitor / HiDPI / Wayland box: a blank output, tiny
scaling, and the Xorg->Wayland VT/seat handover race that left the Hyprland
session with dead keyboard/mouse.

- etc-greetd/: greetd config, ReGreet config (cyberqueer GTK4 theme, larger
  font, wallpaper background), cage session launcher, and a password + FIDO
  PAM stack (no securetty/OATH, which a graphical greeter cannot drive).
- greetd-regreet.sh: install/enable module, mutually exclusive with the
  lightdm and ly greeter modules.
- Greeter background tracks the desktop wallpaper: a root systemd .path unit
  mirrors the picker's choice to a greeter-readable path (the user's home is
  0700, so the unprivileged greeter cannot read it directly).

The LightDM path is kept as a dormant alternative and hardened en route:
pam_u2f (FIDO) added to its PAM stack, a HiDPI + multi-monitor
display-setup.sh, a larger greeter font, and the same wallpaper-sync units.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 03:16:12 +02:00
Amir Alexander Abdelbaki d1e5f765aa feat(greeter): switch HyprLua to LightDM, fix Plymouth splash, extract ly module
Plymouth: bg-skull.svg is a 1920x1080 transparent composition but was rendered
at 300px and treated as a small centred logo, so the skull all but vanished and
the spinner (positioned off the logo height) landed on the monitor artwork. Now
render at native 1920px, scale to fill the screen, and pin the spinner at a
fixed 0.93 of screen height. Also fix DOTFILES_DIR (was off by one level, so the
bundled SVG never resolved and it fell back to a transparent placeholder) and
the dead ../plymouth.sh paths in plymouth-custom.sh and install-modules.sh.

Greeter: HyprLua now uses LightDM + lightdm-gtk-greeter, themed with the
existing cyberqueer GTK theme and a rendered skull background, via a new
self-contained lightdm module. ly is extracted from the DE scripts into its own
module so it stays installable; niri and legacy hyprland keep their inline ly.
Both greeters are registered in modules.conf as mutually exclusive, and the
generated installer/answerfile/docs regions were rebuilt from it. install-modules.sh
guards the 'ly' token with a padded match so it can't substring-hit 'p(ly)mouth'.

Add setup/tools/migrate-to-lightdm.sh to move an existing install (ly / greetd /
GDM / SDDM / LXDM) onto the Plymouth + LightDM setup: it disables the old DM for
the next boot only (never stops the running session) and delegates install +
theming to the module scripts. Supports --dry-run / --no-plymouth / --yes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 01:53:37 +02:00
Amir Alexander Abdelbaki 2ffedd076e fix(installer): flush stray tty input, split shell rc's from shell setup
The first checklist (Select Components) could silently auto-confirm its
defaults, swallowing the user's toggle: tui-install.sh runs right after the
long, mostly-unattended base install, and keystrokes buffered during that
wait were consumed by the script's very first read. Drain the tty before the
first prompt.

Also split the "shell" component into "shell" (tools/plugins/programs) and
a new "shellrc" (personal .bashrc/.zshrc/.vimrc), so the shell environment
can be installed without overwriting the user's rc files. shell-setup.sh
reads MARCHY_DEPLOY_SHELL_RC to gate the rc symlinks and now also deploys
.vimrc, which /etc/skel sync already expected but nothing ever created.
Removes the separate, easily-desynced "Shell Config for New Users" prompt
in favor of deriving /etc/skel behavior from the same shellrc choice, and
mirrors the removal in generate-answerfile.sh.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-03 14:22:03 +02:00
Amir Alexander Abdelbaki 01c58905b2 docs(ansipa): add administration guide (full policy catalogue + recipes)
New docs/md/ansipa-administration.md — an operations-focused guide, separate
from the architecture doc (freeipa-ansible.md) and the deployment guide
(ansipa-setup.md). Covers:

- How administration works: group-driven, the policy enforcer vs the software
  installer timers, host- vs user-group scope, immediate-apply commands, and
  the everyday ipa hostgroup/group commands.
- The full policy catalogue with per-policy apply/revert behaviour, targeting
  (name suffix vs group description), and prerequisites:
  device (dev_daemon-*, dev_timeshift-backup, dev_no-local-users,
  dev_local-sudo-*, dev_ssh_*), monitoring (dev_mon_base/clamscan/timeshift/
  power, usr_mon_logins), software installers (dev_pkg_*, dev_mod_*, dev_fp_*),
  user (usr_admin, usr_block-binary-*, usr_prt_*, usr_smb_*), and BaseUser sync.
- Common recipes (onboard a workstation, grant/block, live policy editing) and
  a troubleshooting table.

Linked from the docs index.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUhrcFU8J1Hnf7vNqNxZNi
2026-07-02 15:42:43 +02:00
Amir Alexander Abdelbaki 4f22a3b03f refactor(ansipa): dev_security-scan → dev_mon_clamscan, report to CheckMK; drop SMB scan pipeline
Rename the security-scan policy to dev_mon_clamscan (fits the XXX_mon_* naming
for monitoring groups) and make it hand results to CheckMK natively instead of
uploading logs to an SMB share.

- dev_mon_clamscan.sh: runs the daily ClamAV/rkhunter/chkrootkit scan and writes
  its own CheckMK local check (ansipa_clamscan → service "Ansipa_ClamScan"); the
  agent from dev_mon_base collects it. Removes the SMB upload entirely. Discovery
  matches dev_mon_clamscan BEFORE the generic dev_mon_* catch-all so it sets
  WANT_CLAMSCAN rather than being treated as a dev_mon.sh check. mkdir -p the
  cron dir (minimal hosts lack /etc/cron.d until cron is installed).
- Remove the now-redundant dev_mon_malware check from dev_mon.sh (subsumed).
- Remove usr_scan-notify and the whole SMB scan-alert pipeline it fed:
  ansipa-fetch-alerts.sh, ansipa-scan-notify.sh, server ansipa-check-scans.sh,
  the ansipa-scans Samba share + scanupload account, /etc/ansipa-smb.creds, and
  the SMB_SCAN_PASSWORD/smb_scan_password variables (playbook, compose, run.sh,
  .env, Dockerfile). The ansipa-luks-keys and ansipa-policystore shares stay.

Verified live on the Arch client: enrolling in dev_mon_clamscan writes the scan
script, cron, and local check (which reports "Ansipa_ClamScan"); leaving the
group removes all three. Docs updated (policy tables, architecture, SMB shares,
scan-flow → CheckMK).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUhrcFU8J1Hnf7vNqNxZNi
2026-07-02 13:49:18 +02:00
Amir Alexander Abdelbaki adea0f457d fix(ansipa): reliable nginx + keycloak healthchecks
Both containers were reporting "unhealthy" while serving fine — the
healthchecks I added probed the wrong address/endpoint:

- nginx: `wget localhost` resolves to IPv6 ::1 inside the container, but nginx
  listens on IPv4 0.0.0.0:80 only, so the probe was refused. Use 127.0.0.1.
- keycloak: with KC_HTTP_RELATIVE_PATH=/auth, /health/ready on the 9000
  management port returns 404. Probe /auth/realms/master on the serving port
  8080 instead (bash /dev/tcp — the image has no curl/wget).

Verified all five containers report healthy and the gateway serves /, /ipa/ui/,
/cmk/ and /auth/ correctly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUhrcFU8J1Hnf7vNqNxZNi
2026-07-02 13:22:24 +02:00
Amir Alexander Abdelbaki 435547822c docs(ansipa): firewall ports, multi-distro enrollment, final consistency pass
- ansipa Setup Guide: add a Firewall section — which inbound ports to open on
  the server (minimum LDAP/Kerberos/HTTPS + per-feature SMB/CheckMK/Keycloak/
  gateway), that clients need nothing inbound for policy enforcement or CheckMK
  push mode, and copy-paste firewalld / ufw / nftables rule examples.
- freeipa-ansible.md: reflect the now-supported mixed fleet (Arch, Fedora,
  RHEL/Rocky/Alma, Debian/Ubuntu) instead of "Arch-only", note the Arch
  autofs/AUR enrollment caveat, and cross-link the setup guide.

Nothing about the deployment is left to guesswork: architecture, every port,
firewall rules, the nginx portal + reverse-proxy snippets, NAT/push-mode, the
Proxmox LXC generator, and the tools reorg paths are all documented.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUhrcFU8J1Hnf7vNqNxZNi
2026-07-02 13:17:33 +02:00
Amir Alexander Abdelbaki dac9060516 fix(de): niri — disable greetd so ly is the sole greeter
niri contradictorily enabled BOTH ly@tty1 and greetd.service (it deployed a
greetd-tuigreet config and enabled greetd late in the script) while also
configuring and enabling ly — so two display managers raced for tty1 and the
stale greetd/tuigreet greeter could win. niri's intent is ly (it disables
getty@tty1, deploys ly config, enables ly@tty1).

Add disable_service greetd.service next to the ly enable and remove the
greetd-config-deploy-and-enable block, matching the hyprlua/hyprland fix. ly
lists the niri Wayland session from /usr/share/wayland-sessions, so no greetd
path is needed. Verified the same fix live on a hyprlua install (greetd
disabled, ly@tty1 enabled).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUhrcFU8J1Hnf7vNqNxZNi
2026-07-02 13:15:12 +02:00
Amir Alexander Abdelbaki baf5e73cc1 feat(tools): ansipa-proxmox-lxc.sh — pre-configured full-stack ansipa Proxmox LXC
Generate everything needed to run the complete ansipa stack (FreeIPA + CheckMK
+ Keycloak + PostgreSQL + nginx gateway) inside a single Proxmox LXC container.
Unlike freeipa-image.sh's proxmox-lxc target (which exports a FreeIPA-only CT
rootfs), this runs the tested docker-compose stack inside a privileged,
nesting-enabled CT ("Docker-in-LXC"), so it is the whole management plane in
one container.

Prompts for domain/realm/VMID/resources, generates all service secrets, and
emits: pct-create-<vmid>.sh, ansipa-<vmid>.conf (nesting=1,keyctl=1,fuse=1 +
the cgroup/apparmor allowances FreeIPA's systemd and Docker overlay2 need), a
first-boot provisioner that installs Docker and brings the stack up via run.sh,
a filled-in .env (mode 600), and a DEPLOY guide. Verified the generator emits
correct, syntactically-valid artifacts. Documented in the ansipa Setup Guide.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUhrcFU8J1Hnf7vNqNxZNi
2026-07-02 13:13:02 +02:00
Amir Alexander Abdelbaki a73bc7cb93 refactor(setup): consolidate build/deploy tooling under setup/tools; docs
Move the build and deployment scripts into setup/tools alongside the existing
generators (proxmox-lxc-gen.sh, freeipa-image.sh, generate-modules.sh):
  - setup/generate-answerfile.sh   -> setup/tools/generate-answerfile.sh
  - setup/archiso/build.sh         -> setup/tools/build.sh
  - setup/archiso/wds-deploy.sh    -> setup/tools/wds-deploy.sh
  - setup/archiso/write-usb.sh     -> setup/tools/write-usb.sh

The archiso overlay/ (profile data: airootfs, profiledef.sh, packages.extra)
stays in setup/archiso/; build.sh now resolves it via an OVERLAY_DIR anchored
at the repo root, and DOTFILES_DIR is corrected for the new two-levels-deep
location. Updated every reference (generate-modules.sh, readme.md,
docs/md/{archiso,installation,index}.md).

generate-answerfile.sh: add linux-hardened to the kernel menu; verified its
emitted answerfile schema still matches every field the installers consume
(drive/kernel/keymap/hostname/username/password/luks_password/encrypt/
fido2_*/run_tui/components/desktop_environment/apps/shell_rc/colors).

Docs: add a dedicated ansipa Setup Guide (docs/md/ansipa-setup.md) covering
architecture, the full port list, the nginx portal + reverse-proxy paths, the
exact upstream reverse-proxy snippets (nginx/Caddy), NAT/push-mode behaviour,
and the Arch autofs/AUR caveat; link it from the index and cross-reference the
CheckMK/nginx ports from freeipa-ansible.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUhrcFU8J1Hnf7vNqNxZNi
2026-07-02 13:09:18 +02:00
Amir Alexander Abdelbaki d63e0e554c chmods 2026-07-02 12:58:45 +02:00
Amir Alexander Abdelbaki 5543194bec fix(modules): correct wrong package names/sources found by static audit
Statically audited every optional-module and DE script's package tokens
against the official repos, the AUR, and Flathub. Ten modules named a package
that does not exist at the source they used, so each would abort with "target
not found" (pacman), an AUR miss, or a Flathub 404:

Installed via pacman but AUR-only (switched to the yay AUR helper):
  - tetris:   bastet
  - doom:     chocolate-doom, freedoom
  - openarena:openarena
  - openshot: openshot
  - freeipa-client (module): oddjob — now optional via yay with a
    pam_mkhomedir fallback (matches freeipa-enroll.sh)

Wrong AUR/repo package names:
  - cecilia:      cecilia -> cecilia-git
  - productivity: python-jrnl -> jrnl (in the official repos)
  - localtunnel:  AUR fallback localtunnel -> nodejs-localtunnel

Wrong/absent Flatpak IDs:
  - zen-browser: io.github.zen_browser.zen -> app.zen_browser.zen
  - stuntrally:  io.github.stuntrally.StuntRally3 is not on Flathub at all;
    switch to the AUR stuntrally-bin (the actual Stunt Rally 3)

Verified all corrected names resolve (repo / AUR RPC / Flathub API). Modules
whose tokens are in the official repos and merely installed via yay (nyxt,
toot, llama-cpp — yay handles both sources) were left as-is.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUhrcFU8J1Hnf7vNqNxZNi
2026-07-02 12:55:59 +02:00
Amir Alexander Abdelbaki be757fda5a feat(ansipa): nginx gateway — reverse proxy + portal start-page
Add an nginx service that fronts all three web UIs on a single hostname/port
and serves a portal landing page, designed to sit behind the operator's own
TLS-terminating reverse proxy.

- Each backend is proxied at the path it already serves natively — FreeIPA
  /ipa, CheckMK /cmk, Keycloak under a configured /auth relative path — so no
  fragile path rewriting is needed and one upstream proxy line exposes
  everything. FreeIPA's strict Host/Referer anti-CSRF checks are satisfied by
  pinning Host to the IPA hostname and rewriting Referer.
- Honors incoming X-Forwarded-Proto/For so it works behind a second reverse
  proxy (double-proxy verified: portal, FreeIPA, CheckMK and Keycloak all
  reachable through two layers, and a CheckMK login POST completes to an
  authenticated session through the gateway).
- Keycloak: KC_HTTP_RELATIVE_PATH=/auth + KC_PROXY_HEADERS=xforwarded so it
  builds correct URLs behind the gateway; deliberately not forwarding
  X-Forwarded-Port (this gateway is :80 internally; the public port is the
  upstream proxy's) to avoid https://host:80 redirects.
- .env.example documents ANSIPA_HTTP_PORT and gives the exact upstream
  reverse-proxy snippet (nginx location block + Caddy one-liner).

Portal is a static cyberqueer-themed page linking to /ipa/ui/, /cmk/, /auth/.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUhrcFU8J1Hnf7vNqNxZNi
2026-07-02 12:36:28 +02:00
Amir Alexander Abdelbaki b21f415cde fix(ansipa): hostname-binary-free FQDN + push-mode orchestration (NAT path)
Found while running the policy matrix and NAT/WAN scenario in VMs:

- ansipa-enforce-policies.sh and the dev_security-scan generated script called
  `hostname -f`, but the hostname binary (inetutils) is not installed on a
  minimal Arch system, so the enforcer aborted with "hostname: command not
  found" on every run. Add an ansipa_fqdn() helper (hostnamectl / getent /
  /etc/hostname / kernel-hostname fallback chain) and use it; inline the same
  fallback in the standalone scan script.

- Fix two stacked bugs that meant CheckMK push mode — the only monitoring
  transport that works when a client is behind NAT — never functioned:
  * ansipa-checkmk-setup.sh referenced IPA_ADMIN_PASS in the DONE_FLAG
    early-exit path, but that variable was assigned only afterwards, so every
    rerun kinit'd with an empty password, failed silently, and skipped the
    push-mode request writer. Resolve config before the early exit.
  * _write_push_requests parsed `ipa hostgroup-show dev_mon_base` members with
    awk that did `next` on the "Member hosts:" line — but ipa prints members on
    that same line, so the only line with hostnames was discarded and no push
    request was ever written. Rewrite the awk to capture the label line's value
    plus wrapped continuation lines. Verified end-to-end: requests are written
    and CheckMK flips the host to cmk_agent_connection=push-agent.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUhrcFU8J1Hnf7vNqNxZNi
2026-07-02 12:25:03 +02:00
Amir Alexander Abdelbaki 0cd352da00 fix(de): disable greetd so ly is the sole greeter on hyprlua/hyprland
core.sh enables greetd (tuigreet) on every install, but the ly-based Hyprland
DEs only disabled getty@tty1 and enabled ly@tty1 — leaving both display
managers enabled and racing for tty1, so the stale greetd/tuigreet greeter
could win and show the old text login instead of ly.

Add a disable_service helper (mirrors enable_service; best-effort, non-fatal)
and call disable_service greetd.service in hyprlua.sh and hyprland.sh right
before enabling ly@tty1, so ly owns the login screen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUhrcFU8J1Hnf7vNqNxZNi
2026-07-02 11:28:15 +02:00
Amir Alexander Abdelbaki 0f767fb051 fix(ansipa): docker stack volume/network naming, healthchecks, client-routable CMK URL
Found while bringing up the FreeIPA+CheckMK+Keycloak stack in a VM:

- Pin volume and network names (name:) so compose and the cgroup-v2 run.sh
  wrapper share the same objects. Compose otherwise prefixes the project name
  (image_cmk-creds, image_ipa-net), so the run.sh-started freeipa container
  mounted a different cmk-creds volume than the compose-started checkmk wrote
  to — the automation secret never reached IPA and the dev_mon_* integration
  retried forever. run.sh also now labels the network it creates so compose
  adopts it instead of erroring "exists but not created by compose".
- run.sh: mount cmk-creds into freeipa and include checkmk in the "all" target;
  both were missing, so the CheckMK path was never wired up via run.sh.
- Fix both healthchecks: Keycloak has no curl/wget and serves /health on the
  management port 9000 only when KC_HEALTH_ENABLED=true, so the old curl probe
  left it permanently unhealthy — use a bash /dev/tcp probe against 9000.
  CheckMK's /api/1.0/version needs auth (401), so probe the login page instead.
- Advertise a client-routable CheckMK URL (CMK_ADVERTISED_URL) in the
  dev_mon_base description instead of the container-internal 172.30.0.12, which
  enrolled clients cannot reach; falls back to the internal URL when unset.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUhrcFU8J1Hnf7vNqNxZNi
2026-07-02 11:28:00 +02:00
Amir Alexander Abdelbaki 3ee375b1c1 fix(ansipa): FreeIPA enrollment for Arch/Fedora/RHEL + autofs AUR workaround
Found while testing client enrollment across distros in VMs:

- Restore the executable bit on freeipa-enroll.sh (lost on a prior edit), which
  made freeipa-client.sh fail with a misleading "not found" for every path.
- Arch: freeipa-client is AUR-only, not the repo package "freeipa" — pacman -S
  freeipa died with "target not found". Install sssd/krb5 from repos and
  freeipa-client via an aur_install helper that drops to the sudo user.
- Bundle autofs-pkgbuild/: freeipa-client (AUR) hard-depends on autofs (AUR),
  whose PKGBUILD pins autofs-5.1.9.tar.xz — pruned from kernel.org at the 5.2.0
  release, so it 404s and blocks all Arch enrollment. Build autofs ourselves
  from upstream git pinned to a 5.1.9-series commit that already carries the
  cyrus-sasl function-pointer fix GCC 14+ needs, and install it before the
  freeipa-client AUR build so the broken AUR autofs is never touched. Verified
  the bundled PKGBUILD builds and installs cleanly on Arch.
- Fedora vs RHEL/Rocky/Alma use different client package names: keep
  freeipa-client on Fedora, use ipa-client on the RHEL family (freeipa-client
  does not exist there). Split the case arms accordingly.
- Guard both freeipa-client.sh entry points against unattended/no-TTY runs: the
  module TUI would hang on a dialog menu, and the wrapper would block on an
  interactive password read when the shipped answerfile has a blank password.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUhrcFU8J1Hnf7vNqNxZNi
2026-07-02 11:27:46 +02:00
Amir Alexander Abdelbaki 405e37d243 fix(installer): keyring race, unattended password, EFI fallback, rebuild cleanup
Found while testing both installers end-to-end in VMs:

- Wait for archiso's pacman-init.service instead of racing it. The installer
  autostarts at login while the live keyring is still being populated
  asynchronously, so every package failed with "signature is unknown trust" /
  "invalid or corrupted package (PGP signature)". Do not run pacman-key --init
  ourselves (corrupts the half-built keyring); wait, then refresh
  archlinux-keyring so an ISO built weeks ago still trusts current keys.
- archbaseos-guided-install.sh: honor the answerfile's password/luks_password
  fields; previously it always prompted interactively, so a documented
  "zero-interaction" netboot/WDS install hung forever with no console.
- Install GRUB to the UEFI removable-media fallback (/EFI/BOOT/BOOTX64.EFI) in
  addition to the NVRAM entry. Without it, an installed disk with empty/cleared
  NVRAM (fresh board, CMOS reset, or a cloned/redeployed image — the whole point
  of this installer) shows "No bootable device". Verified: the disk now boots to
  the login manager with fresh NVRAM.
- build.sh: sudo rm -rf the work dir. mkarchiso runs as root and leaves
  root-owned files if interrupted, so the next plain rm -rf aborted the script
  under set -e before mkarchiso could run.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUhrcFU8J1Hnf7vNqNxZNi
2026-07-02 11:27:27 +02:00
Amir Alexander Abdelbaki d0bf9b2f12 chore(gitignore): ignore inventory-test to avoid committing test credentials
FreeipaAnsible test inventory contains a plaintext ansible_ssh_pass.
2026-07-02 07:03:12 +02:00
Amir Alexander Abdelbaki 03db4f00a7 fix(ansipa): Arch package/hostname fixes, safer seed_policystore delegation
- Use samba/openssh package names on Arch instead of Debian-style samba-client/openssh-server
- Skip AUR-only freeipa install when ipa-client-install already present; skip oddjob if not in official repos
- Guard seed_policystore delegate_to when ipa_server_host is undefined
- Make hostname detection and OS version parsing more robust
- Fix inverted DNS_UPDATE/CONFIGURE_SUDO enrollment flags
2026-07-02 07:01:46 +02:00
Amir Alexander Abdelbaki 815c0e57a8 refactor(ansipa): split enforce-policies monolith into modular policies.d/ system
The 1550-line ansipa-enforce-policies.sh is replaced by a slim orchestrator
that sources policy files from policies.d/ — one file per policy type — via
a shared lib/ansipa-policy.sh that consolidates all IPA group discovery into
two queries (one host-show, one group-find) instead of five or more.

New files:
- ansible/lib/ansipa-policy.sh          shared constants, log/warn, _ansipa_discover(),
                                         _smb_parse_cred(), _ansipa_sync_policystore()
- ansible/policies.d/dev_daemon.sh
- ansible/policies.d/dev_timeshift-backup.sh
- ansible/policies.d/dev_security-scan.sh
- ansible/policies.d/dev_no-local-users.sh
- ansible/policies.d/dev_local-sudo.sh
- ansible/policies.d/dev_ssh.sh
- ansible/policies.d/dev_mon.sh         includes usr_mon_logins (same CMK dep)
- ansible/policies.d/usr_admin.sh
- ansible/policies.d/usr_block-binary.sh
- ansible/policies.d/usr_prt.sh
- ansible/policies.d/usr_scan-notify.sh
- ansible/policies.d/usr_smb.sh
- ansible/policies.d/usr_policystore.sh NEW: auto-mount ~/policystore for
                                         usr_smb_adm_policystore members

The policies.d/ folder on the FreeIPA container is exposed as an SMB share
(ansipa-policystore) so admins can live-edit policy files without Ansible.
The enforcer syncs from the share before each run; cached local files are
used as fallback when SMB is unreachable.

- ansipa-smb-setup.sh: adds ansipa-policystore share + smb-policystore system
  user + usr_smb_adm_policystore IPA group with auto-generated credential
- deploy-ansipa-policies.yml: deploys lib/ and policies.d/ to enrolled clients;
  adds optional seed_policystore task for bootstrap

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-01 19:27:35 +02:00
Amir Alexander Abdelbaki b4ae7ae4ce feat(tools): add proxmox-lxc-gen.sh — TUI wizard for LXC containers
Interactive dialog-based wizard that walks through every relevant
Proxmox LXC parameter and emits three files:

  pct-create-<vmid>.sh    — runnable pct create command
  lxc-<vmid>.conf         — drop-in /etc/pve/lxc/ config
  deploy-guide-<vmid>.txt — step-by-step deployment notes

TUI screens (dialog, cyan theme):
  1. Identity      — VMID, hostname, description, tags
  2. OS/template   — distro menu (debian/ubuntu/alpine/arch/fedora/
                     rocky/centos/void/custom); pveam pattern resolved
                     at deploy time so the latest version is always used
  3. Resources     — memory, swap, cores, disk size, rootfs storage pool
  4. Network       — DHCP or static (IP/CIDR + gateway + DNS + search
                     domain); bridge, VLAN tag, firewall flag
  5. Security      — unprivileged/privileged; feature checklist
                     (nesting, fuse, keyctl, mounts, apparmor unconfined,
                     cgroup:rw, seccomp disable)
  6. Options       — root password (passwordbox, hidden); SSH pubkey
                     file; start-on-boot; auto-start; TTY count
  7. Proxmox host  — optional SSH target for direct provisioning;
                     template storage; output directory; node name
  8. Summary       — scrollable review before generating

If a Proxmox host is provided, the script SCPs the create script and
runs it over SSH. Matches DIALOGRC theme style of freeipa-image.sh
(cyan accent instead of magenta to visually distinguish).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-01 18:55:59 +02:00
Amir Alexander Abdelbaki 0dd7ce3b51 docs(ansipa): document all policies; fix package check for pacman/dpkg
- ansipa-enforce-policies.sh header: add missing dev_ssh_*, usr_smb_r_*,
  usr_smb_rw_*, dev_mon_* (base/malware/timeshift/power), usr_mon_logins
  with concise descriptions matching actual behaviour.  Notes section
  updated with CheckMK setup prerequisite.
- ansipa_packages local check: replace broken rpm||dpkg fallback (wc -l
  always exits 0 so dpkg/pacman branches were never reached) with an
  if/elif/elif that probes for rpm, dpkg, or pacman in order.  Includes
  pacman.log-based recent-packages list for Arch hosts.
- deploy-ansipa-policies.yml prerequisites: add CheckMK and SMB mount notes.
- .env.example: add CheckMK section (CMK_ADMIN_PASSWORD, CMK_SITE_ID).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-01 18:46:27 +02:00