feat(post-install): add installation verification gate with warnings
- commit
- adcf282ed8fc36ed4aaf60e293a5322763e94e07
- author
- brice · · 2026-02-27 05:38 UTC
- parent
- cb324d6
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
5 files · +148 -3
M internal/application/commands/post_install.go +1 -0
| @@ -9,4 +9,5 @@ type PostInstallCommand struct { | |||
| 9 | 9 | PlymouthTheme string // Plymouth theme to install (optional) | |
| 10 | 10 | InstallDankLinux bool // Whether to write the Dank Linux flag file for first-boot auto-install | |
| 11 | 11 | TargetDisk string // Target disk for bootloader hook (e.g. /dev/sda) | |
| 12 | + | Encrypted bool // Whether disk encryption is enabled | |
| 12 | 13 | } | |
| @@ -9,4 +9,5 @@ type PostInstallCommand struct { | |||||
| 9 | PlymouthTheme string // Plymouth theme to install (optional) | 9 | PlymouthTheme string // Plymouth theme to install (optional) | ||
| 10 | InstallDankLinux bool // Whether to write the Dank Linux flag file for first-boot auto-install | 10 | InstallDankLinux bool // Whether to write the Dank Linux flag file for first-boot auto-install | ||
| 11 | TargetDisk string // Target disk for bootloader hook (e.g. /dev/sda) | 11 | TargetDisk string // Target disk for bootloader hook (e.g. /dev/sda) | ||
| 12 | + | Encrypted bool // Whether disk encryption is enabled | |||
| 12 | } | 13 | } | ||
M internal/application/dto/post_install_result.go +4 -3
| @@ -2,7 +2,8 @@ package dto | |||
| 2 | 2 | ||
| 3 | 3 | // PostInstallResult is the result of post-installation tasks | |
| 4 | 4 | type PostInstallResult struct { | |
| 5 | - | Success bool | |
| 6 | - | TasksRun []string | |
| 7 | - | ErrorDetail string | |
| 5 | + | Success bool | |
| 6 | + | TasksRun []string | |
| 7 | + | ErrorDetail string | |
| 8 | + | VerificationWarnings []string | |
| 8 | 9 | } | |
| @@ -2,7 +2,8 @@ package dto | |||||
| 2 | 2 | ||||
| 3 | // PostInstallResult is the result of post-installation tasks | 3 | // PostInstallResult is the result of post-installation tasks | ||
| 4 | type PostInstallResult struct { | 4 | type PostInstallResult struct { | ||
| 5 | - | Success bool | 5 | + | Success bool |
| 6 | - | TasksRun []string | 6 | + | TasksRun []string |
| 7 | - | ErrorDetail string | 7 | + | ErrorDetail string |
| 8 | + | VerificationWarnings []string | |||
| 8 | } | 9 | } | ||
M internal/application/handlers/post_install_handler.go +23 -0
| @@ -114,6 +114,11 @@ func (h *PostInstallHandler) Handle(ctx context.Context, cmd commands.PostInstal | |||
| 114 | 114 | } | |
| 115 | 115 | ||
| 116 | 116 | // Final cleanup and verification | |
| 117 | + | result.VerificationWarnings = h.verifyInstallation(cmd.MountPoint, cmd.Encrypted) | |
| 118 | + | if len(result.VerificationWarnings) > 0 { | |
| 119 | + | h.logger.Warn("Post-install verification warnings", "warnings", result.VerificationWarnings) | |
| 120 | + | } | |
| 121 | + | ||
| 117 | 122 | h.logger.Info("Post-installation tasks completed") | |
| 118 | 123 | result.Success = true | |
| 119 | 124 | ||
| @@ -285,6 +290,24 @@ func enablePacmanOption(conf, commented, replacement string) string { | |||
| 285 | 290 | return strings.ReplaceAll(conf, commented, replacement) | |
| 286 | 291 | } | |
| 287 | 292 | ||
| 293 | + | func (h *PostInstallHandler) verifyInstallation(mountPoint string, encrypted bool) []string { | |
| 294 | + | warnings := []string{} | |
| 295 | + | checks := []struct{ path, name string }{ | |
| 296 | + | {filepath.Join(mountPoint, "etc", "fstab"), "fstab"}, | |
| 297 | + | {filepath.Join(mountPoint, "boot", "limine.conf"), "limine.conf"}, | |
| 298 | + | {filepath.Join(mountPoint, "boot", "EFI", "BOOT", "BOOTX64.EFI"), "EFI boot file"}, | |
| 299 | + | } | |
| 300 | + | if encrypted { | |
| 301 | + | checks = append(checks, struct{ path, name string }{filepath.Join(mountPoint, "etc", "crypttab"), "crypttab"}) | |
| 302 | + | } | |
| 303 | + | for _, c := range checks { | |
| 304 | + | if _, err := h.fs.Stat(c.path); err != nil { | |
| 305 | + | warnings = append(warnings, fmt.Sprintf("missing %s: %s", c.name, c.path)) | |
| 306 | + | } | |
| 307 | + | } | |
| 308 | + | return warnings | |
| 309 | + | } | |
| 310 | + | ||
| 288 | 311 | func (h *PostInstallHandler) downloadTemplate(path string) ([]byte, error) { | |
| 289 | 312 | url := fmt.Sprintf("%s/%s", h.rawURL, path) | |
| 290 | 313 | h.logger.Info("Downloading template", "url", url) | |
| @@ -114,6 +114,11 @@ func (h *PostInstallHandler) Handle(ctx context.Context, cmd commands.PostInstal | |||||
| 114 | } | 114 | } | ||
| 115 | 115 | ||||
| 116 | // Final cleanup and verification | 116 | // Final cleanup and verification | ||
| 117 | + | result.VerificationWarnings = h.verifyInstallation(cmd.MountPoint, cmd.Encrypted) | |||
| 118 | + | if len(result.VerificationWarnings) > 0 { | |||
| 119 | + | h.logger.Warn("Post-install verification warnings", "warnings", result.VerificationWarnings) | |||
| 120 | + | } | |||
| 121 | + | ||||
| 117 | h.logger.Info("Post-installation tasks completed") | 122 | h.logger.Info("Post-installation tasks completed") | ||
| 118 | result.Success = true | 123 | result.Success = true | ||
| 119 | 124 | ||||
| @@ -285,6 +290,24 @@ func enablePacmanOption(conf, commented, replacement string) string { | |||||
| 285 | return strings.ReplaceAll(conf, commented, replacement) | 290 | return strings.ReplaceAll(conf, commented, replacement) | ||
| 286 | } | 291 | } | ||
| 287 | 292 | ||||
| 293 | + | func (h *PostInstallHandler) verifyInstallation(mountPoint string, encrypted bool) []string { | |||
| 294 | + | warnings := []string{} | |||
| 295 | + | checks := []struct{ path, name string }{ | |||
| 296 | + | {filepath.Join(mountPoint, "etc", "fstab"), "fstab"}, | |||
| 297 | + | {filepath.Join(mountPoint, "boot", "limine.conf"), "limine.conf"}, | |||
| 298 | + | {filepath.Join(mountPoint, "boot", "EFI", "BOOT", "BOOTX64.EFI"), "EFI boot file"}, | |||
| 299 | + | } | |||
| 300 | + | if encrypted { | |||
| 301 | + | checks = append(checks, struct{ path, name string }{filepath.Join(mountPoint, "etc", "crypttab"), "crypttab"}) | |||
| 302 | + | } | |||
| 303 | + | for _, c := range checks { | |||
| 304 | + | if _, err := h.fs.Stat(c.path); err != nil { | |||
| 305 | + | warnings = append(warnings, fmt.Sprintf("missing %s: %s", c.name, c.path)) | |||
| 306 | + | } | |||
| 307 | + | } | |||
| 308 | + | return warnings | |||
| 309 | + | } | |||
| 310 | + | ||||
| 288 | func (h *PostInstallHandler) downloadTemplate(path string) ([]byte, error) { | 311 | func (h *PostInstallHandler) downloadTemplate(path string) ([]byte, error) { | ||
| 289 | url := fmt.Sprintf("%s/%s", h.rawURL, path) | 312 | url := fmt.Sprintf("%s/%s", h.rawURL, path) | ||
| 290 | h.logger.Info("Downloading template", "url", url) | 313 | h.logger.Info("Downloading template", "url", url) | ||
M internal/application/handlers/post_install_handler_test.go +119 -0
| @@ -2,6 +2,7 @@ package handlers | |||
| 2 | 2 | ||
| 3 | 3 | import ( | |
| 4 | 4 | "context" | |
| 5 | + | "fmt" | |
| 5 | 6 | "net/http" | |
| 6 | 7 | "strings" | |
| 7 | 8 | "testing" | |
| @@ -40,6 +41,7 @@ func TestPostInstallHandler_Handle_NoScripts(t *testing.T) { | |||
| 40 | 41 | mockHTTP.EXPECT().Get(gomock.Any()).Return(newMockResponse(ctrl, http.StatusOK, []byte("content")), nil).AnyTimes() | |
| 41 | 42 | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() | |
| 42 | 43 | mockChrExec.EXPECT().ChrootSystemctl(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | |
| 44 | + | mockFS.EXPECT().Stat(gomock.Any()).Return(nil, nil).AnyTimes() | |
| 43 | 45 | ||
| 44 | 46 | handler := NewPostInstallHandler(mockFS, mockHTTP, mockChrExec, mockScriptExec, mockLogger, "https://raw.githubusercontent.com/bnema/archup/dev") | |
| 45 | 47 | ||
| @@ -86,6 +88,7 @@ func TestPostInstallHandler_Handle_WithScripts(t *testing.T) { | |||
| 86 | 88 | mockHTTP.EXPECT().Get(gomock.Any()).Return(newMockResponse(ctrl, http.StatusOK, []byte("content")), nil).AnyTimes() | |
| 87 | 89 | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() | |
| 88 | 90 | mockChrExec.EXPECT().ChrootSystemctl(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | |
| 91 | + | mockFS.EXPECT().Stat(gomock.Any()).Return(nil, nil).AnyTimes() | |
| 89 | 92 | ||
| 90 | 93 | handler := NewPostInstallHandler(mockFS, mockHTTP, mockChrExec, mockScriptExec, mockLogger, "https://raw.githubusercontent.com/bnema/archup/dev") | |
| 91 | 94 | ||
| @@ -135,6 +138,7 @@ func TestPostInstallHandler_Handle_WithPlymouth(t *testing.T) { | |||
| 135 | 138 | mockHTTP.EXPECT().Get(gomock.Any()).Return(newMockResponse(ctrl, http.StatusOK, []byte("content")), nil).AnyTimes() | |
| 136 | 139 | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() | |
| 137 | 140 | mockChrExec.EXPECT().ChrootSystemctl(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | |
| 141 | + | mockFS.EXPECT().Stat(gomock.Any()).Return(nil, nil).AnyTimes() | |
| 138 | 142 | ||
| 139 | 143 | handler := NewPostInstallHandler(mockFS, mockHTTP, mockChrExec, mockScriptExec, mockLogger, "https://raw.githubusercontent.com/bnema/archup/dev") | |
| 140 | 144 | ||
| @@ -185,6 +189,7 @@ func TestPostInstallHandler_Handle_WithDankLinux(t *testing.T) { | |||
| 185 | 189 | mockHTTP.EXPECT().Get(gomock.Any()).Return(newMockResponse(ctrl, http.StatusOK, []byte("content")), nil).AnyTimes() | |
| 186 | 190 | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() | |
| 187 | 191 | mockChrExec.EXPECT().ChrootSystemctl(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | |
| 192 | + | mockFS.EXPECT().Stat(gomock.Any()).Return(nil, nil).AnyTimes() | |
| 188 | 193 | ||
| 189 | 194 | handler := NewPostInstallHandler(mockFS, mockHTTP, mockChrExec, mockScriptExec, mockLogger, "https://raw.githubusercontent.com/bnema/archup/dev") | |
| 190 | 195 | ||
| @@ -235,6 +240,7 @@ func TestPostInstallHandler_Handle_TunesPacman(t *testing.T) { | |||
| 235 | 240 | mockHTTP.EXPECT().Get(gomock.Any()).Return(newMockResponse(ctrl, http.StatusOK, []byte("content")), nil).AnyTimes() | |
| 236 | 241 | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() | |
| 237 | 242 | mockChrExec.EXPECT().ChrootSystemctl(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | |
| 243 | + | mockFS.EXPECT().Stat(gomock.Any()).Return(nil, nil).AnyTimes() | |
| 238 | 244 | ||
| 239 | 245 | // ReadFile for pacman.conf returns commented options; other reads return generic content | |
| 240 | 246 | mockFS.EXPECT().ReadFile(gomock.Eq("/mnt/etc/pacman.conf")).Return([]byte(pacmanContent), nil).AnyTimes() | |
| @@ -305,6 +311,7 @@ func TestPostInstallHandler_Handle_InstallsLimineHook(t *testing.T) { | |||
| 305 | 311 | mockHTTP.EXPECT().Get(gomock.Any()).Return(newMockResponse(ctrl, http.StatusOK, []byte(hookTemplate)), nil).AnyTimes() | |
| 306 | 312 | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() | |
| 307 | 313 | mockChrExec.EXPECT().ChrootSystemctl(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | |
| 314 | + | mockFS.EXPECT().Stat(gomock.Any()).Return(nil, nil).AnyTimes() | |
| 308 | 315 | ||
| 309 | 316 | hookWritten := false | |
| 310 | 317 | mockFS.EXPECT().WriteFile(gomock.Eq(hookFile), gomock.Any(), gomock.Any()).DoAndReturn( | |
| @@ -389,6 +396,7 @@ func TestPostInstallHandler_Handle_EnablesSnapperSync(t *testing.T) { | |||
| 389 | 396 | }).AnyTimes() | |
| 390 | 397 | // Catch-all for any other ChrootSystemctl calls | |
| 391 | 398 | mockChrExec.EXPECT().ChrootSystemctl(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | |
| 399 | + | mockFS.EXPECT().Stat(gomock.Any()).Return(nil, nil).AnyTimes() | |
| 392 | 400 | ||
| 393 | 401 | handler := NewPostInstallHandler(mockFS, mockHTTP, mockChrExec, mockScriptExec, mockLogger, "https://raw.githubusercontent.com/bnema/archup/dev") | |
| 394 | 402 | ||
| @@ -439,6 +447,7 @@ func TestPostInstallHandler_Handle_Everything(t *testing.T) { | |||
| 439 | 447 | mockHTTP.EXPECT().Get(gomock.Any()).Return(newMockResponse(ctrl, http.StatusOK, []byte("content")), nil).AnyTimes() | |
| 440 | 448 | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() | |
| 441 | 449 | mockChrExec.EXPECT().ChrootSystemctl(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | |
| 450 | + | mockFS.EXPECT().Stat(gomock.Any()).Return(nil, nil).AnyTimes() | |
| 442 | 451 | ||
| 443 | 452 | handler := NewPostInstallHandler(mockFS, mockHTTP, mockChrExec, mockScriptExec, mockLogger, "https://raw.githubusercontent.com/bnema/archup/dev") | |
| 444 | 453 | ||
| @@ -477,3 +486,113 @@ func TestPostInstallHandler_Handle_Everything(t *testing.T) { | |||
| 477 | 486 | t.Error("expected plymouth-theme-bgrt task") | |
| 478 | 487 | } | |
| 479 | 488 | } | |
| 489 | + | ||
| 490 | + | func TestPostInstallHandler_Handle_RunsVerification(t *testing.T) { | |
| 491 | + | ctrl := gomock.NewController(t) | |
| 492 | + | defer ctrl.Finish() | |
| 493 | + | ||
| 494 | + | mockFS := mocks.NewMockFileSystem(ctrl) | |
| 495 | + | mockHTTP := mocks.NewMockHTTPClient(ctrl) | |
| 496 | + | mockChrExec := mocks.NewMockChrootExecutor(ctrl) | |
| 497 | + | mockScriptExec := mocks.NewMockScriptExecutor(ctrl) | |
| 498 | + | mockLogger := mocks.NewMockLogger(ctrl) | |
| 499 | + | ||
| 500 | + | mockLogger.EXPECT().Info(gomock.Any(), gomock.Any()).AnyTimes() | |
| 501 | + | mockLogger.EXPECT().Warn(gomock.Any(), gomock.Any()).AnyTimes() | |
| 502 | + | mockLogger.EXPECT().LogPath().Return("/var/log/archup-install.log").AnyTimes() | |
| 503 | + | mockFS.EXPECT().Exists(gomock.Any()).Return(false, nil).AnyTimes() | |
| 504 | + | mockFS.EXPECT().ReadFile(gomock.Any()).Return([]byte("graphics: yes"), nil).AnyTimes() | |
| 505 | + | mockFS.EXPECT().WriteFile(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | |
| 506 | + | mockFS.EXPECT().MkdirAll(gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | |
| 507 | + | mockHTTP.EXPECT().Get(gomock.Any()).Return(newMockResponse(ctrl, http.StatusOK, []byte("content")), nil).AnyTimes() | |
| 508 | + | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() | |
| 509 | + | mockChrExec.EXPECT().ChrootSystemctl(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | |
| 510 | + | ||
| 511 | + | // Stat returns nil (files exist) for the checked paths | |
| 512 | + | mockFS.EXPECT().Stat(gomock.Any()).Return(nil, nil).AnyTimes() | |
| 513 | + | ||
| 514 | + | handler := NewPostInstallHandler(mockFS, mockHTTP, mockChrExec, mockScriptExec, mockLogger, "https://raw.githubusercontent.com/bnema/archup/dev") | |
| 515 | + | ||
| 516 | + | cmd := commands.PostInstallCommand{ | |
| 517 | + | MountPoint: "/mnt", | |
| 518 | + | Username: "testuser", | |
| 519 | + | RunPostBootScripts: false, | |
| 520 | + | PlymouthTheme: "", | |
| 521 | + | Encrypted: false, | |
| 522 | + | } | |
| 523 | + | ||
| 524 | + | result, err := handler.Handle(context.Background(), cmd) | |
| 525 | + | ||
| 526 | + | if err != nil { | |
| 527 | + | t.Fatalf("expected no error, got %v", err) | |
| 528 | + | } | |
| 529 | + | ||
| 530 | + | if !result.Success { | |
| 531 | + | t.Error("expected success") | |
| 532 | + | } | |
| 533 | + | ||
| 534 | + | if len(result.VerificationWarnings) != 0 { | |
| 535 | + | t.Errorf("expected no verification warnings, got: %v", result.VerificationWarnings) | |
| 536 | + | } | |
| 537 | + | } | |
| 538 | + | ||
| 539 | + | func TestPostInstallHandler_Handle_VerificationWarnsOnMissingFiles(t *testing.T) { | |
| 540 | + | ctrl := gomock.NewController(t) | |
| 541 | + | defer ctrl.Finish() | |
| 542 | + | ||
| 543 | + | mockFS := mocks.NewMockFileSystem(ctrl) | |
| 544 | + | mockHTTP := mocks.NewMockHTTPClient(ctrl) | |
| 545 | + | mockChrExec := mocks.NewMockChrootExecutor(ctrl) | |
| 546 | + | mockScriptExec := mocks.NewMockScriptExecutor(ctrl) | |
| 547 | + | mockLogger := mocks.NewMockLogger(ctrl) | |
| 548 | + | ||
| 549 | + | mockLogger.EXPECT().Info(gomock.Any(), gomock.Any()).AnyTimes() | |
| 550 | + | mockLogger.EXPECT().Warn(gomock.Any(), gomock.Any()).AnyTimes() | |
| 551 | + | mockLogger.EXPECT().LogPath().Return("/var/log/archup-install.log").AnyTimes() | |
| 552 | + | mockFS.EXPECT().Exists(gomock.Any()).Return(false, nil).AnyTimes() | |
| 553 | + | mockFS.EXPECT().ReadFile(gomock.Any()).Return([]byte("graphics: yes"), nil).AnyTimes() | |
| 554 | + | mockFS.EXPECT().WriteFile(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | |
| 555 | + | mockFS.EXPECT().MkdirAll(gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | |
| 556 | + | mockHTTP.EXPECT().Get(gomock.Any()).Return(newMockResponse(ctrl, http.StatusOK, []byte("content")), nil).AnyTimes() | |
| 557 | + | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() | |
| 558 | + | mockChrExec.EXPECT().ChrootSystemctl(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | |
| 559 | + | ||
| 560 | + | // limine.conf is missing; all other Stat calls succeed | |
| 561 | + | mockFS.EXPECT().Stat(gomock.Eq("/mnt/boot/limine.conf")).Return(nil, fmt.Errorf("not found")) | |
| 562 | + | mockFS.EXPECT().Stat(gomock.Any()).Return(nil, nil).AnyTimes() | |
| 563 | + | ||
| 564 | + | handler := NewPostInstallHandler(mockFS, mockHTTP, mockChrExec, mockScriptExec, mockLogger, "https://raw.githubusercontent.com/bnema/archup/dev") | |
| 565 | + | ||
| 566 | + | cmd := commands.PostInstallCommand{ | |
| 567 | + | MountPoint: "/mnt", | |
| 568 | + | Username: "testuser", | |
| 569 | + | RunPostBootScripts: false, | |
| 570 | + | PlymouthTheme: "", | |
| 571 | + | Encrypted: false, | |
| 572 | + | } | |
| 573 | + | ||
| 574 | + | result, err := handler.Handle(context.Background(), cmd) | |
| 575 | + | ||
| 576 | + | if err != nil { | |
| 577 | + | t.Fatalf("expected no error, got %v", err) | |
| 578 | + | } | |
| 579 | + | ||
| 580 | + | if !result.Success { | |
| 581 | + | t.Error("expected success even with verification warnings") | |
| 582 | + | } | |
| 583 | + | ||
| 584 | + | if len(result.VerificationWarnings) == 0 { | |
| 585 | + | t.Error("expected verification warnings for missing limine.conf") | |
| 586 | + | } | |
| 587 | + | ||
| 588 | + | found := false | |
| 589 | + | for _, w := range result.VerificationWarnings { | |
| 590 | + | if strings.Contains(w, "limine.conf") { | |
| 591 | + | found = true | |
| 592 | + | break | |
| 593 | + | } | |
| 594 | + | } | |
| 595 | + | if !found { | |
| 596 | + | t.Errorf("expected warning about limine.conf, got: %v", result.VerificationWarnings) | |
| 597 | + | } | |
| 598 | + | } | |
| @@ -2,6 +2,7 @@ package handlers | |||||
| 2 | 2 | ||||
| 3 | import ( | 3 | import ( | ||
| 4 | "context" | 4 | "context" | ||
| 5 | + | "fmt" | |||
| 5 | "net/http" | 6 | "net/http" | ||
| 6 | "strings" | 7 | "strings" | ||
| 7 | "testing" | 8 | "testing" | ||
| @@ -40,6 +41,7 @@ func TestPostInstallHandler_Handle_NoScripts(t *testing.T) { | |||||
| 40 | mockHTTP.EXPECT().Get(gomock.Any()).Return(newMockResponse(ctrl, http.StatusOK, []byte("content")), nil).AnyTimes() | 41 | mockHTTP.EXPECT().Get(gomock.Any()).Return(newMockResponse(ctrl, http.StatusOK, []byte("content")), nil).AnyTimes() | ||
| 41 | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() | 42 | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() | ||
| 42 | mockChrExec.EXPECT().ChrootSystemctl(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | 43 | mockChrExec.EXPECT().ChrootSystemctl(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | ||
| 44 | + | mockFS.EXPECT().Stat(gomock.Any()).Return(nil, nil).AnyTimes() | |||
| 43 | 45 | ||||
| 44 | handler := NewPostInstallHandler(mockFS, mockHTTP, mockChrExec, mockScriptExec, mockLogger, "https://raw.githubusercontent.com/bnema/archup/dev") | 46 | handler := NewPostInstallHandler(mockFS, mockHTTP, mockChrExec, mockScriptExec, mockLogger, "https://raw.githubusercontent.com/bnema/archup/dev") | ||
| 45 | 47 | ||||
| @@ -86,6 +88,7 @@ func TestPostInstallHandler_Handle_WithScripts(t *testing.T) { | |||||
| 86 | mockHTTP.EXPECT().Get(gomock.Any()).Return(newMockResponse(ctrl, http.StatusOK, []byte("content")), nil).AnyTimes() | 88 | mockHTTP.EXPECT().Get(gomock.Any()).Return(newMockResponse(ctrl, http.StatusOK, []byte("content")), nil).AnyTimes() | ||
| 87 | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() | 89 | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() | ||
| 88 | mockChrExec.EXPECT().ChrootSystemctl(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | 90 | mockChrExec.EXPECT().ChrootSystemctl(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | ||
| 91 | + | mockFS.EXPECT().Stat(gomock.Any()).Return(nil, nil).AnyTimes() | |||
| 89 | 92 | ||||
| 90 | handler := NewPostInstallHandler(mockFS, mockHTTP, mockChrExec, mockScriptExec, mockLogger, "https://raw.githubusercontent.com/bnema/archup/dev") | 93 | handler := NewPostInstallHandler(mockFS, mockHTTP, mockChrExec, mockScriptExec, mockLogger, "https://raw.githubusercontent.com/bnema/archup/dev") | ||
| 91 | 94 | ||||
| @@ -135,6 +138,7 @@ func TestPostInstallHandler_Handle_WithPlymouth(t *testing.T) { | |||||
| 135 | mockHTTP.EXPECT().Get(gomock.Any()).Return(newMockResponse(ctrl, http.StatusOK, []byte("content")), nil).AnyTimes() | 138 | mockHTTP.EXPECT().Get(gomock.Any()).Return(newMockResponse(ctrl, http.StatusOK, []byte("content")), nil).AnyTimes() | ||
| 136 | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() | 139 | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() | ||
| 137 | mockChrExec.EXPECT().ChrootSystemctl(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | 140 | mockChrExec.EXPECT().ChrootSystemctl(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | ||
| 141 | + | mockFS.EXPECT().Stat(gomock.Any()).Return(nil, nil).AnyTimes() | |||
| 138 | 142 | ||||
| 139 | handler := NewPostInstallHandler(mockFS, mockHTTP, mockChrExec, mockScriptExec, mockLogger, "https://raw.githubusercontent.com/bnema/archup/dev") | 143 | handler := NewPostInstallHandler(mockFS, mockHTTP, mockChrExec, mockScriptExec, mockLogger, "https://raw.githubusercontent.com/bnema/archup/dev") | ||
| 140 | 144 | ||||
| @@ -185,6 +189,7 @@ func TestPostInstallHandler_Handle_WithDankLinux(t *testing.T) { | |||||
| 185 | mockHTTP.EXPECT().Get(gomock.Any()).Return(newMockResponse(ctrl, http.StatusOK, []byte("content")), nil).AnyTimes() | 189 | mockHTTP.EXPECT().Get(gomock.Any()).Return(newMockResponse(ctrl, http.StatusOK, []byte("content")), nil).AnyTimes() | ||
| 186 | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() | 190 | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() | ||
| 187 | mockChrExec.EXPECT().ChrootSystemctl(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | 191 | mockChrExec.EXPECT().ChrootSystemctl(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | ||
| 192 | + | mockFS.EXPECT().Stat(gomock.Any()).Return(nil, nil).AnyTimes() | |||
| 188 | 193 | ||||
| 189 | handler := NewPostInstallHandler(mockFS, mockHTTP, mockChrExec, mockScriptExec, mockLogger, "https://raw.githubusercontent.com/bnema/archup/dev") | 194 | handler := NewPostInstallHandler(mockFS, mockHTTP, mockChrExec, mockScriptExec, mockLogger, "https://raw.githubusercontent.com/bnema/archup/dev") | ||
| 190 | 195 | ||||
| @@ -235,6 +240,7 @@ func TestPostInstallHandler_Handle_TunesPacman(t *testing.T) { | |||||
| 235 | mockHTTP.EXPECT().Get(gomock.Any()).Return(newMockResponse(ctrl, http.StatusOK, []byte("content")), nil).AnyTimes() | 240 | mockHTTP.EXPECT().Get(gomock.Any()).Return(newMockResponse(ctrl, http.StatusOK, []byte("content")), nil).AnyTimes() | ||
| 236 | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() | 241 | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() | ||
| 237 | mockChrExec.EXPECT().ChrootSystemctl(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | 242 | mockChrExec.EXPECT().ChrootSystemctl(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | ||
| 243 | + | mockFS.EXPECT().Stat(gomock.Any()).Return(nil, nil).AnyTimes() | |||
| 238 | 244 | ||||
| 239 | // ReadFile for pacman.conf returns commented options; other reads return generic content | 245 | // ReadFile for pacman.conf returns commented options; other reads return generic content | ||
| 240 | mockFS.EXPECT().ReadFile(gomock.Eq("/mnt/etc/pacman.conf")).Return([]byte(pacmanContent), nil).AnyTimes() | 246 | mockFS.EXPECT().ReadFile(gomock.Eq("/mnt/etc/pacman.conf")).Return([]byte(pacmanContent), nil).AnyTimes() | ||
| @@ -305,6 +311,7 @@ func TestPostInstallHandler_Handle_InstallsLimineHook(t *testing.T) { | |||||
| 305 | mockHTTP.EXPECT().Get(gomock.Any()).Return(newMockResponse(ctrl, http.StatusOK, []byte(hookTemplate)), nil).AnyTimes() | 311 | mockHTTP.EXPECT().Get(gomock.Any()).Return(newMockResponse(ctrl, http.StatusOK, []byte(hookTemplate)), nil).AnyTimes() | ||
| 306 | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() | 312 | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() | ||
| 307 | mockChrExec.EXPECT().ChrootSystemctl(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | 313 | mockChrExec.EXPECT().ChrootSystemctl(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | ||
| 314 | + | mockFS.EXPECT().Stat(gomock.Any()).Return(nil, nil).AnyTimes() | |||
| 308 | 315 | ||||
| 309 | hookWritten := false | 316 | hookWritten := false | ||
| 310 | mockFS.EXPECT().WriteFile(gomock.Eq(hookFile), gomock.Any(), gomock.Any()).DoAndReturn( | 317 | mockFS.EXPECT().WriteFile(gomock.Eq(hookFile), gomock.Any(), gomock.Any()).DoAndReturn( | ||
| @@ -389,6 +396,7 @@ func TestPostInstallHandler_Handle_EnablesSnapperSync(t *testing.T) { | |||||
| 389 | }).AnyTimes() | 396 | }).AnyTimes() | ||
| 390 | // Catch-all for any other ChrootSystemctl calls | 397 | // Catch-all for any other ChrootSystemctl calls | ||
| 391 | mockChrExec.EXPECT().ChrootSystemctl(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | 398 | mockChrExec.EXPECT().ChrootSystemctl(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | ||
| 399 | + | mockFS.EXPECT().Stat(gomock.Any()).Return(nil, nil).AnyTimes() | |||
| 392 | 400 | ||||
| 393 | handler := NewPostInstallHandler(mockFS, mockHTTP, mockChrExec, mockScriptExec, mockLogger, "https://raw.githubusercontent.com/bnema/archup/dev") | 401 | handler := NewPostInstallHandler(mockFS, mockHTTP, mockChrExec, mockScriptExec, mockLogger, "https://raw.githubusercontent.com/bnema/archup/dev") | ||
| 394 | 402 | ||||
| @@ -439,6 +447,7 @@ func TestPostInstallHandler_Handle_Everything(t *testing.T) { | |||||
| 439 | mockHTTP.EXPECT().Get(gomock.Any()).Return(newMockResponse(ctrl, http.StatusOK, []byte("content")), nil).AnyTimes() | 447 | mockHTTP.EXPECT().Get(gomock.Any()).Return(newMockResponse(ctrl, http.StatusOK, []byte("content")), nil).AnyTimes() | ||
| 440 | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() | 448 | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() | ||
| 441 | mockChrExec.EXPECT().ChrootSystemctl(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | 449 | mockChrExec.EXPECT().ChrootSystemctl(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | ||
| 450 | + | mockFS.EXPECT().Stat(gomock.Any()).Return(nil, nil).AnyTimes() | |||
| 442 | 451 | ||||
| 443 | handler := NewPostInstallHandler(mockFS, mockHTTP, mockChrExec, mockScriptExec, mockLogger, "https://raw.githubusercontent.com/bnema/archup/dev") | 452 | handler := NewPostInstallHandler(mockFS, mockHTTP, mockChrExec, mockScriptExec, mockLogger, "https://raw.githubusercontent.com/bnema/archup/dev") | ||
| 444 | 453 | ||||
| @@ -477,3 +486,113 @@ func TestPostInstallHandler_Handle_Everything(t *testing.T) { | |||||
| 477 | t.Error("expected plymouth-theme-bgrt task") | 486 | t.Error("expected plymouth-theme-bgrt task") | ||
| 478 | } | 487 | } | ||
| 479 | } | 488 | } | ||
| 489 | + | ||||
| 490 | + | func TestPostInstallHandler_Handle_RunsVerification(t *testing.T) { | |||
| 491 | + | ctrl := gomock.NewController(t) | |||
| 492 | + | defer ctrl.Finish() | |||
| 493 | + | ||||
| 494 | + | mockFS := mocks.NewMockFileSystem(ctrl) | |||
| 495 | + | mockHTTP := mocks.NewMockHTTPClient(ctrl) | |||
| 496 | + | mockChrExec := mocks.NewMockChrootExecutor(ctrl) | |||
| 497 | + | mockScriptExec := mocks.NewMockScriptExecutor(ctrl) | |||
| 498 | + | mockLogger := mocks.NewMockLogger(ctrl) | |||
| 499 | + | ||||
| 500 | + | mockLogger.EXPECT().Info(gomock.Any(), gomock.Any()).AnyTimes() | |||
| 501 | + | mockLogger.EXPECT().Warn(gomock.Any(), gomock.Any()).AnyTimes() | |||
| 502 | + | mockLogger.EXPECT().LogPath().Return("/var/log/archup-install.log").AnyTimes() | |||
| 503 | + | mockFS.EXPECT().Exists(gomock.Any()).Return(false, nil).AnyTimes() | |||
| 504 | + | mockFS.EXPECT().ReadFile(gomock.Any()).Return([]byte("graphics: yes"), nil).AnyTimes() | |||
| 505 | + | mockFS.EXPECT().WriteFile(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | |||
| 506 | + | mockFS.EXPECT().MkdirAll(gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | |||
| 507 | + | mockHTTP.EXPECT().Get(gomock.Any()).Return(newMockResponse(ctrl, http.StatusOK, []byte("content")), nil).AnyTimes() | |||
| 508 | + | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() | |||
| 509 | + | mockChrExec.EXPECT().ChrootSystemctl(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | |||
| 510 | + | ||||
| 511 | + | // Stat returns nil (files exist) for the checked paths | |||
| 512 | + | mockFS.EXPECT().Stat(gomock.Any()).Return(nil, nil).AnyTimes() | |||
| 513 | + | ||||
| 514 | + | handler := NewPostInstallHandler(mockFS, mockHTTP, mockChrExec, mockScriptExec, mockLogger, "https://raw.githubusercontent.com/bnema/archup/dev") | |||
| 515 | + | ||||
| 516 | + | cmd := commands.PostInstallCommand{ | |||
| 517 | + | MountPoint: "/mnt", | |||
| 518 | + | Username: "testuser", | |||
| 519 | + | RunPostBootScripts: false, | |||
| 520 | + | PlymouthTheme: "", | |||
| 521 | + | Encrypted: false, | |||
| 522 | + | } | |||
| 523 | + | ||||
| 524 | + | result, err := handler.Handle(context.Background(), cmd) | |||
| 525 | + | ||||
| 526 | + | if err != nil { | |||
| 527 | + | t.Fatalf("expected no error, got %v", err) | |||
| 528 | + | } | |||
| 529 | + | ||||
| 530 | + | if !result.Success { | |||
| 531 | + | t.Error("expected success") | |||
| 532 | + | } | |||
| 533 | + | ||||
| 534 | + | if len(result.VerificationWarnings) != 0 { | |||
| 535 | + | t.Errorf("expected no verification warnings, got: %v", result.VerificationWarnings) | |||
| 536 | + | } | |||
| 537 | + | } | |||
| 538 | + | ||||
| 539 | + | func TestPostInstallHandler_Handle_VerificationWarnsOnMissingFiles(t *testing.T) { | |||
| 540 | + | ctrl := gomock.NewController(t) | |||
| 541 | + | defer ctrl.Finish() | |||
| 542 | + | ||||
| 543 | + | mockFS := mocks.NewMockFileSystem(ctrl) | |||
| 544 | + | mockHTTP := mocks.NewMockHTTPClient(ctrl) | |||
| 545 | + | mockChrExec := mocks.NewMockChrootExecutor(ctrl) | |||
| 546 | + | mockScriptExec := mocks.NewMockScriptExecutor(ctrl) | |||
| 547 | + | mockLogger := mocks.NewMockLogger(ctrl) | |||
| 548 | + | ||||
| 549 | + | mockLogger.EXPECT().Info(gomock.Any(), gomock.Any()).AnyTimes() | |||
| 550 | + | mockLogger.EXPECT().Warn(gomock.Any(), gomock.Any()).AnyTimes() | |||
| 551 | + | mockLogger.EXPECT().LogPath().Return("/var/log/archup-install.log").AnyTimes() | |||
| 552 | + | mockFS.EXPECT().Exists(gomock.Any()).Return(false, nil).AnyTimes() | |||
| 553 | + | mockFS.EXPECT().ReadFile(gomock.Any()).Return([]byte("graphics: yes"), nil).AnyTimes() | |||
| 554 | + | mockFS.EXPECT().WriteFile(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | |||
| 555 | + | mockFS.EXPECT().MkdirAll(gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | |||
| 556 | + | mockHTTP.EXPECT().Get(gomock.Any()).Return(newMockResponse(ctrl, http.StatusOK, []byte("content")), nil).AnyTimes() | |||
| 557 | + | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() | |||
| 558 | + | mockChrExec.EXPECT().ChrootSystemctl(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | |||
| 559 | + | ||||
| 560 | + | // limine.conf is missing; all other Stat calls succeed | |||
| 561 | + | mockFS.EXPECT().Stat(gomock.Eq("/mnt/boot/limine.conf")).Return(nil, fmt.Errorf("not found")) | |||
| 562 | + | mockFS.EXPECT().Stat(gomock.Any()).Return(nil, nil).AnyTimes() | |||
| 563 | + | ||||
| 564 | + | handler := NewPostInstallHandler(mockFS, mockHTTP, mockChrExec, mockScriptExec, mockLogger, "https://raw.githubusercontent.com/bnema/archup/dev") | |||
| 565 | + | ||||
| 566 | + | cmd := commands.PostInstallCommand{ | |||
| 567 | + | MountPoint: "/mnt", | |||
| 568 | + | Username: "testuser", | |||
| 569 | + | RunPostBootScripts: false, | |||
| 570 | + | PlymouthTheme: "", | |||
| 571 | + | Encrypted: false, | |||
| 572 | + | } | |||
| 573 | + | ||||
| 574 | + | result, err := handler.Handle(context.Background(), cmd) | |||
| 575 | + | ||||
| 576 | + | if err != nil { | |||
| 577 | + | t.Fatalf("expected no error, got %v", err) | |||
| 578 | + | } | |||
| 579 | + | ||||
| 580 | + | if !result.Success { | |||
| 581 | + | t.Error("expected success even with verification warnings") | |||
| 582 | + | } | |||
| 583 | + | ||||
| 584 | + | if len(result.VerificationWarnings) == 0 { | |||
| 585 | + | t.Error("expected verification warnings for missing limine.conf") | |||
| 586 | + | } | |||
| 587 | + | ||||
| 588 | + | found := false | |||
| 589 | + | for _, w := range result.VerificationWarnings { | |||
| 590 | + | if strings.Contains(w, "limine.conf") { | |||
| 591 | + | found = true | |||
| 592 | + | break | |||
| 593 | + | } | |||
| 594 | + | } | |||
| 595 | + | if !found { | |||
| 596 | + | t.Errorf("expected warning about limine.conf, got: %v", result.VerificationWarnings) | |||
| 597 | + | } | |||
| 598 | + | } | |||
M internal/interfaces/tui/handlers/install_handler.go +1 -0
| @@ -217,6 +217,7 @@ func CreateInstallationCommand(app AppContext, formData models.FormData) tea.Cmd | |||
| 217 | 217 | RunPostBootScripts: true, | |
| 218 | 218 | InstallDankLinux: formData.InstallDankLinux, | |
| 219 | 219 | TargetDisk: formData.TargetDisk, | |
| 220 | + | Encrypted: parseEncryptionType(formData.EncryptionType) != disk.EncryptionTypeNone, | |
| 220 | 221 | } | |
| 221 | 222 | if _, err := svc.RunPostInstall(ctx, postCmd); err != nil { | |
| 222 | 223 | logger.Error("Post-installation failed", "error", err) | |
| @@ -217,6 +217,7 @@ func CreateInstallationCommand(app AppContext, formData models.FormData) tea.Cmd | |||||
| 217 | RunPostBootScripts: true, | 217 | RunPostBootScripts: true, | ||
| 218 | InstallDankLinux: formData.InstallDankLinux, | 218 | InstallDankLinux: formData.InstallDankLinux, | ||
| 219 | TargetDisk: formData.TargetDisk, | 219 | TargetDisk: formData.TargetDisk, | ||
| 220 | + | Encrypted: parseEncryptionType(formData.EncryptionType) != disk.EncryptionTypeNone, | |||
| 220 | } | 221 | } | ||
| 221 | if _, err := svc.RunPostInstall(ctx, postCmd); err != nil { | 222 | if _, err := svc.RunPostInstall(ctx, postCmd); err != nil { | ||
| 222 | logger.Error("Post-installation failed", "error", err) | 223 | logger.Error("Post-installation failed", "error", err) | ||