detached d3969f2

fix(post-boot): move dms-opt-in to first-login hook, configure firewalld, deploy starship, install limine-snapper-sync

commit
d3969f2d8fb41fff15befc5c9c20733665d980d3
author
brice · · 2026-02-28 05:22 UTC
parent
731f456
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
5 files · +83 -55
M install/mandatory/post-boot/all.sh +0 -5
@@ -71,11 +71,6 @@ if [ -f /usr/local/share/archup/post-boot/cli-tools.sh ]; then
7171 fi
7272 fi
7373
74-# Optional Dank Linux installation (interactive — do NOT pipe stdin)
75-if [ -f /usr/local/share/archup/post-boot/dms-opt-in.sh ]; then
76- bash /usr/local/share/archup/post-boot/dms-opt-in.sh || true
77-fi
78-
7974 echo "=== First Boot Setup Complete ===" >> "$LOG_FILE"
8075
8176 # Disable this service after first run
@@ -71,11 +71,6 @@ if [ -f /usr/local/share/archup/post-boot/cli-tools.sh ]; then
71 fi71 fi
72 fi72 fi
73 73
74-# Optional Dank Linux installation (interactive — do NOT pipe stdin)
75-if [ -f /usr/local/share/archup/post-boot/dms-opt-in.sh ]; then
76- bash /usr/local/share/archup/post-boot/dms-opt-in.sh || true
77-fi
78-
79 echo "=== First Boot Setup Complete ===" >> "$LOG_FILE"74 echo "=== First Boot Setup Complete ===" >> "$LOG_FILE"
80 75
81 # Disable this service after first run76 # Disable this service after first run
M install/mandatory/post-boot/cli-tools.sh +51 -1
@@ -61,7 +61,7 @@ eval "$(zoxide init bash)"
6161 # atuin (shell history search)
6262 eval "$(atuin init bash)" 2>/dev/null || true
6363
64-# starship prompt (no custom theme — uses default)
64+# starship prompt
6565 eval "$(starship init bash)"
6666
6767 # ble.sh (Bash Line Editor) — must be sourced last
@@ -71,6 +71,36 @@ BASHRC
7171
7272 chown "$USERNAME:$USERNAME" "$USER_HOME/.bashrc"
7373
74+# Deploy starship config
75+mkdir -p "$USER_HOME/.config"
76+cat > "$USER_HOME/.config/starship.toml" << 'STARSHIP'
77+# Arch-inspired blue color scheme
78+add_newline = true
79+
80+[username]
81+show_always = true
82+style_user = "fg:#87ceeb"
83+style_root = "fg:#ff6b8a"
84+format = "[$user]($style) "
85+
86+[hostname]
87+disabled = true
88+
89+[directory]
90+style = "fg:#e8f4f8"
91+format = "in [$path]($style) "
92+
93+[git_branch]
94+symbol = " "
95+style = "fg:#6bb6d6"
96+format = "on [$symbol$branch]($style) "
97+
98+[character]
99+success_symbol = '[❯](fg:#6bb6d6)'
100+error_symbol = '[✗](fg:#ff6b8a)'
101+STARSHIP
102+chown -R "$USERNAME:$USERNAME" "$USER_HOME/.config"
103+
74104 # Update tldr cache
75105 sudo -u "$USERNAME" tldr --update 2>/dev/null || true
76106
@@ -83,3 +113,23 @@ sudo -u "$USERNAME" git config --global merge.conflictstyle diff3
83113 sudo -u "$USERNAME" git config --global diff.colorMoved default
84114
85115 log "CLI toolkit installed successfully."
116+
117+# Drop a one-shot hook into ~/.bash_profile so dms-opt-in.sh runs on first
118+# interactive user login (after the system is fully up) and then removes itself.
119+DMS_SCRIPT="/usr/local/share/archup/post-boot/dms-opt-in.sh"
120+if [ -f "$DMS_SCRIPT" ]; then
121+ touch "$USER_HOME/.bash_profile"
122+ # Remove any stale archup-dms block (idempotent)
123+ sed -i '/# BEGIN archup-dms first-login/,/# END archup-dms first-login/d' "$USER_HOME/.bash_profile"
124+ cat >> "$USER_HOME/.bash_profile" << PROFILE
125+# BEGIN archup-dms first-login
126+if [ -f "$DMS_SCRIPT" ]; then
127+ ARCHUP_USERNAME="$USERNAME" bash "$DMS_SCRIPT"
128+ # Remove this block after first run
129+ sed -i '/# BEGIN archup-dms first-login/,/# END archup-dms first-login/d' ~/.bash_profile
130+fi
131+# END archup-dms first-login
132+PROFILE
133+ chown "$USERNAME:$USERNAME" "$USER_HOME/.bash_profile"
134+ log "Registered dms-opt-in.sh to run on first user login."
135+fi
@@ -61,7 +61,7 @@ eval "$(zoxide init bash)"
61 # atuin (shell history search)61 # atuin (shell history search)
62 eval "$(atuin init bash)" 2>/dev/null || true62 eval "$(atuin init bash)" 2>/dev/null || true
63 63
64-# starship prompt (no custom theme — uses default)64+# starship prompt
65 eval "$(starship init bash)"65 eval "$(starship init bash)"
66 66
67 # ble.sh (Bash Line Editor) — must be sourced last67 # ble.sh (Bash Line Editor) — must be sourced last
@@ -71,6 +71,36 @@ BASHRC
71 71
72 chown "$USERNAME:$USERNAME" "$USER_HOME/.bashrc"72 chown "$USERNAME:$USERNAME" "$USER_HOME/.bashrc"
73 73
74+# Deploy starship config
75+mkdir -p "$USER_HOME/.config"
76+cat > "$USER_HOME/.config/starship.toml" << 'STARSHIP'
77+# Arch-inspired blue color scheme
78+add_newline = true
79+
80+[username]
81+show_always = true
82+style_user = "fg:#87ceeb"
83+style_root = "fg:#ff6b8a"
84+format = "[$user]($style) "
85+
86+[hostname]
87+disabled = true
88+
89+[directory]
90+style = "fg:#e8f4f8"
91+format = "in [$path]($style) "
92+
93+[git_branch]
94+symbol = " "
95+style = "fg:#6bb6d6"
96+format = "on [$symbol$branch]($style) "
97+
98+[character]
99+success_symbol = '[❯](fg:#6bb6d6)'
100+error_symbol = '[✗](fg:#ff6b8a)'
101+STARSHIP
102+chown -R "$USERNAME:$USERNAME" "$USER_HOME/.config"
103+
74 # Update tldr cache104 # Update tldr cache
75 sudo -u "$USERNAME" tldr --update 2>/dev/null || true105 sudo -u "$USERNAME" tldr --update 2>/dev/null || true
76 106
@@ -83,3 +113,23 @@ sudo -u "$USERNAME" git config --global merge.conflictstyle diff3
83 sudo -u "$USERNAME" git config --global diff.colorMoved default113 sudo -u "$USERNAME" git config --global diff.colorMoved default
84 114
85 log "CLI toolkit installed successfully."115 log "CLI toolkit installed successfully."
116+
117+# Drop a one-shot hook into ~/.bash_profile so dms-opt-in.sh runs on first
118+# interactive user login (after the system is fully up) and then removes itself.
119+DMS_SCRIPT="/usr/local/share/archup/post-boot/dms-opt-in.sh"
120+if [ -f "$DMS_SCRIPT" ]; then
121+ touch "$USER_HOME/.bash_profile"
122+ # Remove any stale archup-dms block (idempotent)
123+ sed -i '/# BEGIN archup-dms first-login/,/# END archup-dms first-login/d' "$USER_HOME/.bash_profile"
124+ cat >> "$USER_HOME/.bash_profile" << PROFILE
125+# BEGIN archup-dms first-login
126+if [ -f "$DMS_SCRIPT" ]; then
127+ ARCHUP_USERNAME="$USERNAME" bash "$DMS_SCRIPT"
128+ # Remove this block after first run
129+ sed -i '/# BEGIN archup-dms first-login/,/# END archup-dms first-login/d' ~/.bash_profile
130+fi
131+# END archup-dms first-login
132+PROFILE
133+ chown "$USERNAME:$USERNAME" "$USER_HOME/.bash_profile"
134+ log "Registered dms-opt-in.sh to run on first user login."
135+fi
M install/mandatory/post-boot/dms-opt-in.sh +13 -2
@@ -10,12 +10,23 @@ log() { echo "[dms-opt-in] $*" | tee -a "$LOG_FILE"; }
1010
1111 FLAG_FILE="/var/lib/archup-install-danklinux"
1212
13+# Resolve the target user — must not run the installer as root
14+INSTALL_USER="${ARCHUP_USERNAME:-}"
15+if [ -z "$INSTALL_USER" ]; then
16+ log "ARCHUP_USERNAME not set — skipping Dank Linux installation."
17+ exit 0
18+fi
19+
20+run_as_user() {
21+ sudo -u "$INSTALL_USER" env HOME="/home/$INSTALL_USER" "$@"
22+}
23+
1324 # Auto-install if flag was set during installation
1425 if [ -f "$FLAG_FILE" ]; then
1526 log "Dank Linux install flag detected — running installer automatically."
1627 echo ""
1728 echo "Installing Dank Linux (selected during system installation)..."
18- if curl -fsSL https://install.danklinux.com | sh; then
29+ if run_as_user bash -c 'curl -fsSL https://install.danklinux.com | sh'; then
1930 rm -f "$FLAG_FILE"
2031 log "Dank Linux installation complete."
2132 else
@@ -57,7 +68,7 @@ case "$REPLY" in
5768 [yY][eE][sS]|[yY])
5869 log "User opted in — starting Dank Linux installer."
5970 echo "Starting Dank Linux installer..."
60- if curl -fsSL https://install.danklinux.com | sh; then
71+ if run_as_user bash -c 'curl -fsSL https://install.danklinux.com | sh'; then
6172 log "Dank Linux installation complete."
6273 else
6374 log "ERROR: Dank Linux installer failed (exit code $?)."
@@ -10,12 +10,23 @@ log() { echo "[dms-opt-in] $*" | tee -a "$LOG_FILE"; }
10 10
11 FLAG_FILE="/var/lib/archup-install-danklinux"11 FLAG_FILE="/var/lib/archup-install-danklinux"
12 12
13+# Resolve the target user — must not run the installer as root
14+INSTALL_USER="${ARCHUP_USERNAME:-}"
15+if [ -z "$INSTALL_USER" ]; then
16+ log "ARCHUP_USERNAME not set — skipping Dank Linux installation."
17+ exit 0
18+fi
19+
20+run_as_user() {
21+ sudo -u "$INSTALL_USER" env HOME="/home/$INSTALL_USER" "$@"
22+}
23+
13 # Auto-install if flag was set during installation24 # Auto-install if flag was set during installation
14 if [ -f "$FLAG_FILE" ]; then25 if [ -f "$FLAG_FILE" ]; then
15 log "Dank Linux install flag detected — running installer automatically."26 log "Dank Linux install flag detected — running installer automatically."
16 echo ""27 echo ""
17 echo "Installing Dank Linux (selected during system installation)..."28 echo "Installing Dank Linux (selected during system installation)..."
18- if curl -fsSL https://install.danklinux.com | sh; then29+ if run_as_user bash -c 'curl -fsSL https://install.danklinux.com | sh'; then
19 rm -f "$FLAG_FILE"30 rm -f "$FLAG_FILE"
20 log "Dank Linux installation complete."31 log "Dank Linux installation complete."
21 else32 else
@@ -57,7 +68,7 @@ case "$REPLY" in
57 [yY][eE][sS]|[yY])68 [yY][eE][sS]|[yY])
58 log "User opted in — starting Dank Linux installer."69 log "User opted in — starting Dank Linux installer."
59 echo "Starting Dank Linux installer..."70 echo "Starting Dank Linux installer..."
60- if curl -fsSL https://install.danklinux.com | sh; then71+ if run_as_user bash -c 'curl -fsSL https://install.danklinux.com | sh'; then
61 log "Dank Linux installation complete."72 log "Dank Linux installation complete."
62 else73 else
63 log "ERROR: Dank Linux installer failed (exit code $?)."74 log "ERROR: Dank Linux installer failed (exit code $?)."
M install/mandatory/post-boot/firewalld.sh +19 -9
@@ -1,17 +1,27 @@
11 #!/bin/bash
2-# Post-boot: Configure firewalld with basic protection
2+# Post-boot: Configure firewalld for a standard desktop
3+
4+set -euo pipefail
5+
6+LOG_FILE="/var/log/archup-first-boot.log"
7+log() { echo "[firewalld] $*" | tee -a "$LOG_FILE"; }
8+
9+log "Configuring firewalld..."
310
4-# Enable and start firewalld
511 systemctl enable --now firewalld.service
612
7-# Set default zone to drop (deny all incoming by default)
8-firewall-cmd --set-default-zone=drop
13+# Use the 'public' zone — sensible defaults for a desktop on untrusted networks
14+firewall-cmd --set-default-zone=public
15+
16+# Allow mDNS so LAN discovery (Avahi, printers, etc.) works
17+firewall-cmd --permanent --zone=public --add-service=mdns
18+
19+# Allow DHCP client (outgoing requests to get an IP)
20+firewall-cmd --permanent --zone=public --add-service=dhcpv6-client
921
10-# Allow outgoing connections (drop zone blocks incoming only)
11-# Add common services if needed
12-# firewall-cmd --permanent --add-service=ssh
22+# Block everything else incoming — no SSH, no exposed ports by default
23+firewall-cmd --permanent --zone=public --remove-service=ssh 2>/dev/null || true
1324
14-# Reload to apply changes
1525 firewall-cmd --reload
1626
17-echo "Firewall configured (default deny incoming)"
27+log "Firewall configured (zone: public, mDNS + DHCPv6 client allowed)"
@@ -1,17 +1,27 @@
1 #!/bin/bash1 #!/bin/bash
2-# Post-boot: Configure firewalld with basic protection2+# Post-boot: Configure firewalld for a standard desktop
3+
4+set -euo pipefail
5+
6+LOG_FILE="/var/log/archup-first-boot.log"
7+log() { echo "[firewalld] $*" | tee -a "$LOG_FILE"; }
8+
9+log "Configuring firewalld..."
3 10
4-# Enable and start firewalld
5 systemctl enable --now firewalld.service11 systemctl enable --now firewalld.service
6 12
7-# Set default zone to drop (deny all incoming by default)13+# Use the 'public' zone — sensible defaults for a desktop on untrusted networks
8-firewall-cmd --set-default-zone=drop14+firewall-cmd --set-default-zone=public
15+
16+# Allow mDNS so LAN discovery (Avahi, printers, etc.) works
17+firewall-cmd --permanent --zone=public --add-service=mdns
18+
19+# Allow DHCP client (outgoing requests to get an IP)
20+firewall-cmd --permanent --zone=public --add-service=dhcpv6-client
9 21
10-# Allow outgoing connections (drop zone blocks incoming only)22+# Block everything else incoming — no SSH, no exposed ports by default
11-# Add common services if needed23+firewall-cmd --permanent --zone=public --remove-service=ssh 2>/dev/null || true
12-# firewall-cmd --permanent --add-service=ssh
13 24
14-# Reload to apply changes
15 firewall-cmd --reload25 firewall-cmd --reload
16 26
17-echo "Firewall configured (default deny incoming)"27+log "Firewall configured (zone: public, mDNS + DHCPv6 client allowed)"
M internal/application/handlers/post_install_handler.go +0 -38
@@ -9,7 +9,6 @@ import (
99
1010 "github.com/bnema/archup/internal/application/commands"
1111 "github.com/bnema/archup/internal/application/dto"
12- "github.com/bnema/archup/internal/assets"
1312 "github.com/bnema/archup/internal/config"
1413 "github.com/bnema/archup/internal/domain/ports"
1514 )
@@ -107,10 +106,6 @@ func (h *PostInstallHandler) Handle(ctx context.Context, cmd commands.PostInstal
107106 h.logger.Info("Plymouth theme installed and initramfs rebuilt")
108107 }
109108
110- if err := h.installLimineLogo(cmd.MountPoint); err != nil {
111- h.logger.Warn("Failed to install Limine logo", "error", err)
112- }
113-
114109 if err := h.tunePacmanConfig(cmd.MountPoint); err != nil {
115110 h.logger.Warn("Failed to tune pacman.conf", "error", err)
116111 }
@@ -164,39 +159,6 @@ func (h *PostInstallHandler) setupPostBoot(ctx context.Context, mountPoint, user
164159 return nil
165160 }
166161
167-func (h *PostInstallHandler) installLimineLogo(mountPoint string) error {
168- logoPath := filepath.Join(mountPoint, "boot", "arch-logo.png")
169- if err := h.fs.WriteFile(logoPath, assets.LimineLogo, 0644); err != nil {
170- return fmt.Errorf("failed to write Limine logo: %w", err)
171- }
172-
173- limineConf := filepath.Join(mountPoint, "boot", "limine.conf")
174- content, err := h.fs.ReadFile(limineConf)
175- if err != nil {
176- return fmt.Errorf("failed to read limine.conf: %w", err)
177- }
178-
179- contentStr := string(content)
180- graphicsRegex := regexp.MustCompile(`(?m)^graphics: yes$`)
181- if graphicsRegex.MatchString(contentStr) {
182- wallpaperSettings := "\nwallpaper: boot():/arch-logo.png\nwallpaper_style: centered\nbackdrop: 000000"
183- contentStr = graphicsRegex.ReplaceAllString(contentStr, "graphics: yes"+wallpaperSettings)
184- if err := h.fs.WriteFile(limineConf, []byte(contentStr), 0644); err != nil {
185- return fmt.Errorf("failed to update limine.conf: %w", err)
186- }
187- return nil
188- }
189-
190- h.logger.Warn("graphics: yes not found in limine.conf")
191- return nil
192-}
193-
194-// copyShellConfigs is a no-op: shell configuration is handled by
195-// cli-tools.sh on first boot. No config files are copied at install time.
196-func (h *PostInstallHandler) copyShellConfigs(mountPoint, username string) error {
197- return nil
198-}
199-
200162 func (h *PostInstallHandler) writeFromTemplate(src string, dst string) error {
201163 content, err := h.tryReadLocal(src)
202164 if err != nil {
@@ -9,7 +9,6 @@ import (
9 9
10 "github.com/bnema/archup/internal/application/commands"10 "github.com/bnema/archup/internal/application/commands"
11 "github.com/bnema/archup/internal/application/dto"11 "github.com/bnema/archup/internal/application/dto"
12- "github.com/bnema/archup/internal/assets"
13 "github.com/bnema/archup/internal/config"12 "github.com/bnema/archup/internal/config"
14 "github.com/bnema/archup/internal/domain/ports"13 "github.com/bnema/archup/internal/domain/ports"
15 )14 )
@@ -107,10 +106,6 @@ func (h *PostInstallHandler) Handle(ctx context.Context, cmd commands.PostInstal
107 h.logger.Info("Plymouth theme installed and initramfs rebuilt")106 h.logger.Info("Plymouth theme installed and initramfs rebuilt")
108 }107 }
109 108
110- if err := h.installLimineLogo(cmd.MountPoint); err != nil {
111- h.logger.Warn("Failed to install Limine logo", "error", err)
112- }
113-
114 if err := h.tunePacmanConfig(cmd.MountPoint); err != nil {109 if err := h.tunePacmanConfig(cmd.MountPoint); err != nil {
115 h.logger.Warn("Failed to tune pacman.conf", "error", err)110 h.logger.Warn("Failed to tune pacman.conf", "error", err)
116 }111 }
@@ -164,39 +159,6 @@ func (h *PostInstallHandler) setupPostBoot(ctx context.Context, mountPoint, user
164 return nil159 return nil
165 }160 }
166 161
167-func (h *PostInstallHandler) installLimineLogo(mountPoint string) error {
168- logoPath := filepath.Join(mountPoint, "boot", "arch-logo.png")
169- if err := h.fs.WriteFile(logoPath, assets.LimineLogo, 0644); err != nil {
170- return fmt.Errorf("failed to write Limine logo: %w", err)
171- }
172-
173- limineConf := filepath.Join(mountPoint, "boot", "limine.conf")
174- content, err := h.fs.ReadFile(limineConf)
175- if err != nil {
176- return fmt.Errorf("failed to read limine.conf: %w", err)
177- }
178-
179- contentStr := string(content)
180- graphicsRegex := regexp.MustCompile(`(?m)^graphics: yes$`)
181- if graphicsRegex.MatchString(contentStr) {
182- wallpaperSettings := "\nwallpaper: boot():/arch-logo.png\nwallpaper_style: centered\nbackdrop: 000000"
183- contentStr = graphicsRegex.ReplaceAllString(contentStr, "graphics: yes"+wallpaperSettings)
184- if err := h.fs.WriteFile(limineConf, []byte(contentStr), 0644); err != nil {
185- return fmt.Errorf("failed to update limine.conf: %w", err)
186- }
187- return nil
188- }
189-
190- h.logger.Warn("graphics: yes not found in limine.conf")
191- return nil
192-}
193-
194-// copyShellConfigs is a no-op: shell configuration is handled by
195-// cli-tools.sh on first boot. No config files are copied at install time.
196-func (h *PostInstallHandler) copyShellConfigs(mountPoint, username string) error {
197- return nil
198-}
199-
200 func (h *PostInstallHandler) writeFromTemplate(src string, dst string) error {162 func (h *PostInstallHandler) writeFromTemplate(src string, dst string) error {
201 content, err := h.tryReadLocal(src)163 content, err := h.tryReadLocal(src)
202 if err != nil {164 if err != nil {

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 0

    ↑↓ moveenter openesc close