main 6af0a61

preflight_handler.go RawHistoryFolder

1package handlers
2
3import (
4	"context"
5	"strings"
6
7	"github.com/bnema/archup/internal/application/commands"
8	"github.com/bnema/archup/internal/application/dto"
9	"github.com/bnema/archup/internal/domain/ports"
10	"github.com/bnema/archup/internal/domain/system"
11)
12
13// PreflightHandler handles preflight checks
14type PreflightHandler struct {
15	fs      ports.FileSystem
16	cmdExec ports.CommandExecutor
17	logger  ports.Logger
18	rules   *system.SystemValidationRules
19}
20
21// NewPreflightHandler creates a new preflight handler
22func NewPreflightHandler(fs ports.FileSystem, cmdExec ports.CommandExecutor, logger ports.Logger) *PreflightHandler {
23	return &PreflightHandler{
24		fs:      fs,
25		cmdExec: cmdExec,
26		logger:  logger,
27		rules:   system.NewSystemValidationRules(),
28	}
29}
30
31// Handle executes preflight checks
32func (h *PreflightHandler) Handle(ctx context.Context, cmd commands.PreflightCommand) (*dto.PreflightResult, error) {
33	h.logger.Info("Starting preflight checks")
34
35	result := &dto.PreflightResult{
36		SystemInfo:     &dto.SystemInfo{},
37		CPUInfo:        &dto.CPUInfo{},
38		ChecksPassed:   true,
39		Warnings:       []string{},
40		CriticalErrors: []string{},
41	}
42
43	// Check if running as root
44	if output, err := h.cmdExec.Execute(ctx, "id", "-u"); err == nil {
45		if strings.TrimSpace(string(output)) != "0" {
46			result.CriticalErrors = append(result.CriticalErrors, "Must run as root user")
47			result.ChecksPassed = false
48			h.logger.Warn("Not running as root")
49		}
50	}
51
52	// Check for Arch Linux
53	if err := h.rules.ValidateArchLinux(ctx, h.fs); err != nil {
54		result.CriticalErrors = append(result.CriticalErrors, err.Error())
55		result.ChecksPassed = false
56		h.logger.Error("Not running on Arch Linux", "error", err)
57	}
58
59	// Detect distribution type
60	if distro, err := system.DetectDistribution(ctx, h.fs); err == nil {
61		result.SystemInfo.Distribution = distro.String()
62		h.logger.Info("Detected distribution", "distro", distro.String())
63
64		// Check for derivatives (must be vanilla Arch)
65		if err := h.rules.ValidateNotDerivative(ctx, h.fs); err != nil {
66			result.CriticalErrors = append(result.CriticalErrors, err.Error())
67			result.ChecksPassed = false
68			h.logger.Error("Derivative distribution detected", "error", err)
69		}
70	}
71
72	// Check architecture
73	if output, err := h.cmdExec.Execute(ctx, "uname", "-m"); err == nil && len(output) > 0 {
74		arch := strings.TrimSpace(string(output))
75		result.SystemInfo.Architecture = arch
76		h.logger.Info("Detected architecture", "arch", arch)
77
78		// Validate x86_64
79		if err := h.rules.ValidateArchitecture(arch); err != nil {
80			result.CriticalErrors = append(result.CriticalErrors, err.Error())
81			result.ChecksPassed = false
82			h.logger.Error("Invalid architecture", "error", err)
83		}
84	}
85
86	// Check UEFI boot
87	if err := h.rules.ValidateUEFIBoot(ctx, h.fs); err != nil {
88		result.CriticalErrors = append(result.CriticalErrors, err.Error())
89		result.ChecksPassed = false
90		result.SystemInfo.IsUEFI = false
91		h.logger.Error("Not booted in UEFI mode", "error", err)
92	} else {
93		result.SystemInfo.IsUEFI = true
94		h.logger.Info("UEFI boot mode confirmed")
95	}
96
97	// Check Secure Boot status
98	if enabled, err := h.rules.DetectSecureBoot(ctx, h.cmdExec); err == nil {
99		result.SystemInfo.SecureBootEnabled = enabled
100		if enabled {
101			h.logger.Warn("Secure Boot is enabled")
102		} else {
103			h.logger.Info("Secure Boot is disabled")
104		}
105
106		// Validate that Secure Boot is disabled
107		if err := h.rules.ValidateSecureBootDisabled(ctx, h.cmdExec); err != nil {
108			result.CriticalErrors = append(result.CriticalErrors, err.Error())
109			result.ChecksPassed = false
110			h.logger.Error("Secure Boot must be disabled", "error", err)
111		}
112	} else {
113		h.logger.Warn("Could not detect Secure Boot status", "error", err)
114	}
115
116	// Check internet connectivity (try DNS)
117	if _, err := h.cmdExec.Execute(ctx, "ping", "-c", "1", "archlinux.org"); err != nil {
118		result.Warnings = append(result.Warnings, "Could not verify internet connectivity")
119		h.logger.Warn("Internet connectivity check failed")
120	}
121
122	// Get CPU info
123	if output, err := h.cmdExec.Execute(ctx, "grep", "model name", "/proc/cpuinfo"); err == nil && len(output) > 0 {
124		model := strings.TrimSpace(string(output))
125		result.CPUInfo.Model = model
126		h.logger.Info("Detected CPU", "model", model)
127	}
128
129	if result.ChecksPassed {
130		h.logger.Info("Preflight checks passed")
131	} else {
132		h.logger.Error("Preflight checks failed", "errors", result.CriticalErrors)
133	}
134
135	return result, nil
136}

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