Author SHA1 Message Date
alvinlollo 00c89f23f0 feat(installer): Skip login manager when unl0kr handles the passphrase
Tests / tests (push) Successful in 2m56s
unl0kr already prompts for the LUKS passphrase on screen, so a login
manager on top of it would be a second prompt. The login screen now only
collects a fallback (none/greetd/sddm/gdm) when unl0kr is selected;
resolve_login_manager applies it only when install_unl0kr falls back to
the systemd initramfs, and the summary shows both states.

Also ships /etc/unl0kr.conf (breezy-dark) plus the empty
/usr/share/unl0kr/unl0kr.conf the package omits so unl0kr stops warning
about an unparseable config, and pins Hyprland in the user's
AccountsService record so gdm autologin does not fall back to
gnome.desktop.
2026-10-13 19:33:57 +11:00
alvinlollo 3b1e7d1982 chore: Add pre-commit hook running shellcheck on every commit
Tests / tests (push) Successful in 3m11s
2026-10-13 18:07:05 +11:00
alvinlollo 6a708c0303 feat(installer): Add warn-only post-install update step 2026-10-13 17:49:05 +11:00
alvinlollo 0cdaa6f82d fix(iso): Put [cachyos] ahead of [core] in live pacman.conf 2026-10-13 17:48:59 +11:00
alvinlollo 5735859179 chore(installer): Reformat alvin-install (shfmt, 2-space indent) 2026-10-13 17:48:42 +11:00
5 changed files with 2015 additions and 1756 deletions
+13 -2
View File
@@ -53,7 +53,7 @@ install them into the target without the network.
| `pacman.conf` | Repos: cachyos → core → extra → multilib → chaotic-aur → local-aur |
| `bootstrap_packages` | Minimal build-time packages (`base`, `arch-install-scripts`) |
| `airootfs/root/customize_airootfs.sh` | Runs inside chroot during build: keyrings, skel dotfiles (incl. end4-pC), qsConfig patch, end-4 `install-deps`, package harvest, uv/font pre-warm |
| `airootfs/root/.live-pacman.conf` | `/etc/pacman.conf` of the built image (adds `[local-aur]` = `file:///opt/localrepo`) |
| `airootfs/root/.live-pacman.conf` | `/etc/pacman.conf` of the built image (adds `[local-aur]` = `file:///opt/localrepo`); also what pacstrap resolves the target from, so `[cachyos]` must stay ahead of `[core]` like in `pacman.conf` |
| `airootfs/usr/local/bin/alvin-install` | Installer: partitions, pacstrap, LUKS (systemd initramfs **or** experimental unl0kr + optional TPM2 unlock), user (fish shell), git identity + GitHub SSH keys, login manager (none/greetd/sddm/gdm) + autologin, optional sshd (default on), end-4 dotfiles (`--skip-alldeps`), boot |
| `localrepo/build-end4-deps.sh` | Non-interactive AUR builds for end-4 dependencies |
| `localrepo/update.sh` | Regenerates localrepo DB, syncs names to packages.x86_64, syncs `airootfs/opt/localrepo/` |
@@ -74,7 +74,7 @@ The airootfs overlay ships it as `/usr/local/bin/alvin-install` (mode `0755` for
locale, login manager, sshd, summary) then a fixed order of `install_*` steps
(partition → LUKS → format/mount → pacstrap → fstab → repos → timezone → locale →
hostname → network → sshd → user → git/SSH → end-4 dots → mkinitcpio → bootloader →
TPM/unl0kr → login manager → autologin → cleanup). Screens and install steps are
TPM/unl0kr → login manager (none if unl0kr succeeded; with unl0kr selected the login screen only asks for a fallback) → autologin → update (reflector + keyrings + `pacman -Syu`, warn-only) → cleanup). Screens and install steps are
independent — edit one without
touching the other. An `EXIT` trap unmounts `$TARGET` and closes `cryptroot` on any exit.
- **Package list**: `install_pacstrap` builds the *installed* system's list from the medium's
@@ -97,6 +97,16 @@ yamllint -d "{extends: relaxed, rules: {document-start: disable, line-length: di
`packages.x86_64` syntax: one package per line, `[a-zA-Z0-9._@+\-]+` only, no trailing
whitespace.
A **pre-commit hook** (`githooks/pre-commit`) runs the same ShellCheck pass on every
commit, so CI failures surface before you push. Enable it once per clone:
```bash
git config core.hooksPath githooks
```
It skips linting (with a warning) when `shellcheck` is missing rather than blocking the
commit; CI remains the enforcer. Bypass it with `git commit --no-verify`.
## Gotchas
- The profile root is the **repo root** (not a `releng/` subdirectory). CI builds with `mkarchiso -v -w "$PWD/work" -o "$PWD/out" -- "$PWD"` (`.gitea/workflows/build-iso.yaml`), and the local build command above does the same — never pass a `releng` path.
@@ -113,6 +123,7 @@ whitespace.
- **MicroTeX flags**: the image's `makepkg.conf` is CachyOS's (`-march=native -O3`, LTO). GCC 16.2 hit an internal compiler error (segfault) on MicroTeX's `gtkmm_main.cpp` with it (failed CI run 155; not reproducible locally), so `customize_airootfs.sh` patches end-4's `illogical-impulse-microtex-git` PKGBUILD to `options=(!lto)` + `-O2` (our `localrepo/end4-pkgbuilds/microtex-git` carries the same).
- **CAP_SETFCAP on the runner**: without it pacstrap drops `security.capability` xattrs (newuidmap/newgidmap, snap-confine, dumpcap, kwin_wayland, ...) from the live ISO with only a warning. `build-iso.yaml` fails the job early if the runner lacks it — fix the runner, don't remove the check.
- **yay SIGSEGV on exit**: yay 13 (libalpm via purego/`dyalpm`) can segfault in `alpm_release()` *after* a finished transaction (failed CI run at end-4's `illogical-impulse-kde` step), which aborted `install-deps`. `customize_airootfs.sh` puts a temporary `yay` shim first on the builder's `PATH`: a failed plain `yay -S <pkgs>` counts as success only if `pacman -T` confirms every target is installed (it logs `[yay-shim]`). Every other failure keeps yay's exit code.
- **gvfs / dead `~/.gvfs`**: `install_end4_dots` replays end-4's gsettings writes via `dbus-run-session` as the target user. A session bus D-Bus-activates gvfsd → gvfsd-fuse mounts `~/.gvfs` and dies with the bus, leaving a dead FUSE mount that root can't stat, so the home's catch-all `chown -R` failed (`cannot access '/mnt/home/<user>/.gvfs': Permission denied`) and aborted the install before the bootloader. The replay therefore runs with `GIO_USE_VFS=local GVFS_DISABLE_FUSE=1`, and the function unmounts anything mounted under the home before that chown — keep both.
- mono's `cert-sync` runs before `ca-certificates.crt` exists during pacstrap, so `customize_airootfs.sh` (live) and `install_pacstrap` (target) re-run it.
- `/etc/skel/.zshrc` is owned by `grml-zsh-config`, so ours is staged as `airootfs/root/.zshrc-skel` and installed by `customize_airootfs.sh` after pacstrap — never add files under `airootfs/` at paths a package owns, or pacstrap aborts with "exists in filesystem".
- `packages.x86_64` is sorted alphabetically. Keep it sorted when adding/removing entries.
+15 -1
View File
@@ -384,11 +384,25 @@ sudo mkarchiso -v -w work -o out/ .
### CI Checks (must pass before merge)
- **ShellCheck**: all `.sh` files checked with `shellcheck -x -s bash`
- **ShellCheck**: all `.sh` files, plus extensionless bash scripts in `airootfs/usr/local/bin/`, checked with `shellcheck -x -s bash`
- **yamllint**: all `.yml`/`.yaml` files (relaxed config)
- **packages.x86_64 syntax**: one package per line, no trailing whitespace, `[a-zA-Z0-9._@+\-]+` only
- **Package repo check**: every package in `packages.x86_64` must be resolvable via `pacman -Si` in allowed repos (`cachyos`, `extra`, `multilib`, `chaotic-aur`), OR have a pre-built `.pkg.tar.zst` in `localrepo/`, OR appear in `localrepo/build-end4-deps.sh`
### Git Hooks
A pre-commit hook (`githooks/pre-commit`) runs the ShellCheck pass on every commit, so lint failures surface before you push instead of in CI.
```bash
# Enable once per clone
git config core.hooksPath githooks
# Bypass the hook for a single commit
git commit --no-verify
```
If `shellcheck` is not installed the hook warns and skips rather than blocking the commit; CI remains the enforcer.
### Recommended VirtualBox Settings (for testing)
- RAM: 4GB minimum, 8GB recommended
+8 -4
View File
@@ -33,6 +33,14 @@ LocalFileSigLevel = Optional
# - URLs will have $arch replaced by the name of the architecture
#
# [cachyos] first, same as the build's pacman.conf: pacstrap installs the
# target from this file, so with [core] ahead the target got Arch builds of
# everything cachyos also ships (pacman -2 vs the live -4 -> libalpm
# "unknown key '%INSTALLED_DB%'" warnings) and flipped them on the first -Syu.
[cachyos]
SigLevel = Required DatabaseOptional
Include = /etc/pacman.d/cachyos-mirrorlist
[core]
Include = /etc/pacman.d/mirrorlist
@@ -42,10 +50,6 @@ Include = /etc/pacman.d/mirrorlist
[multilib]
Include = /etc/pacman.d/mirrorlist
[cachyos]
SigLevel = Required DatabaseOptional
Include = /etc/pacman.d/cachyos-mirrorlist
[chaotic-aur]
SigLevel = Required DatabaseOptional
Include = /etc/pacman.d/chaotic-mirrorlist
File diff suppressed because it is too large Load Diff
+51
View File
@@ -0,0 +1,51 @@
#!/usr/bin/env bash
# pre-commit hook: run ShellCheck on every shell script in the repo.
#
# This mirrors the CI check in .gitea/workflows/tests.yaml so the local
# lint and the CI lint cannot drift apart. Enable it in a clone with:
#
# git config core.hooksPath githooks
set -u
if ! command -v shellcheck >/dev/null 2>&1; then
echo "pre-commit: shellcheck not found on PATH, skipping lint." >&2
echo "pre-commit: install it with 'pacman -S shellcheck'; CI still enforces it." >&2
exit 0
fi
# Same file set as CI: *.sh plus the extensionless bash scripts in
# airootfs/usr/local/bin picked up by their shebang.
# find's stderr is dropped because localrepo/end4-pkgbuilds/*/pkg is left
# at mode d--x--x--x by makepkg and prints "Permission denied" locally.
sh_files=$(
{
find . -name '*.sh' -not -path './.git/*' 2>/dev/null
find airootfs/usr/local/bin -type f ! -name '*.sh' \
-exec grep -lE '^#!(/usr/bin/env bash|/bin/bash)' {} + 2>/dev/null
} | sed '/^$/d' | sort -u
)
if [ -z "$sh_files" ]; then
echo "pre-commit: no shell scripts found."
exit 0
fi
failed=0
while IFS= read -r f; do
if shellcheck -x -s bash "$f"; then
echo " ok $f"
else
echo " FAIL $f" >&2
failed=1
fi
done <<< "$sh_files"
if [ "$failed" -ne 0 ]; then
echo "" >&2
echo "pre-commit: ShellCheck failed. Fix the issues above, or bypass with:" >&2
echo " git commit --no-verify" >&2
exit 1
fi
exit 0