fix(cachyos): add pacman-key --init and MkdirAll before host/chroot CachyOS repo setup
- commit
- b39b9c4754e5ec9fbd0f0d5152f8067ef75a4a2a
- author
- brice · · 2026-02-27 18:20 UTC
- parent
- ea4c673
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
6 files · +79 -44
M internal/application/handlers/bootloader_handler_test.go +2 -2
| @@ -28,8 +28,8 @@ func TestBootloaderHandler_Handle_Limine(t *testing.T) { | |||
| 28 | 28 | mockFS.EXPECT().Exists(gomock.Any()).Return(true, nil).AnyTimes() | |
| 29 | 29 | mockExec.EXPECT().Execute(gomock.Any(), "blkid", "-s", "UUID", "-o", "value", gomock.Any()).Return([]byte("uuid"), nil).AnyTimes() | |
| 30 | 30 | mockExec.EXPECT().Execute(gomock.Any(), "cp", gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() | |
| 31 | - | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), "mkinitcpio", "-P").Return([]byte{}, nil).AnyTimes() | |
| 32 | - | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), "efibootmgr", gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() | |
| 31 | + | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() | |
| 32 | + | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() | |
| 33 | 33 | ||
| 34 | 34 | handler := NewBootloaderHandler(mockFS, mockExec, mockChrExec, mockLogger) | |
| 35 | 35 | ||
| @@ -28,8 +28,8 @@ func TestBootloaderHandler_Handle_Limine(t *testing.T) { | |||||
| 28 | mockFS.EXPECT().Exists(gomock.Any()).Return(true, nil).AnyTimes() | 28 | mockFS.EXPECT().Exists(gomock.Any()).Return(true, nil).AnyTimes() | ||
| 29 | mockExec.EXPECT().Execute(gomock.Any(), "blkid", "-s", "UUID", "-o", "value", gomock.Any()).Return([]byte("uuid"), nil).AnyTimes() | 29 | mockExec.EXPECT().Execute(gomock.Any(), "blkid", "-s", "UUID", "-o", "value", gomock.Any()).Return([]byte("uuid"), nil).AnyTimes() | ||
| 30 | mockExec.EXPECT().Execute(gomock.Any(), "cp", gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() | 30 | mockExec.EXPECT().Execute(gomock.Any(), "cp", gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() | ||
| 31 | - | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), "mkinitcpio", "-P").Return([]byte{}, nil).AnyTimes() | 31 | + | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() |
| 32 | - | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), "efibootmgr", gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() | 32 | + | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() |
| 33 | 33 | ||||
| 34 | handler := NewBootloaderHandler(mockFS, mockExec, mockChrExec, mockLogger) | 34 | handler := NewBootloaderHandler(mockFS, mockExec, mockChrExec, mockLogger) | ||
| 35 | 35 | ||||
M internal/application/handlers/configure_system_handler_test.go +1 -0
| @@ -21,6 +21,7 @@ func TestConfigureSystemHandler_Handle_Success(t *testing.T) { | |||
| 21 | 21 | mockLogger.EXPECT().Warn(gomock.Any(), gomock.Any()).AnyTimes() | |
| 22 | 22 | mockLogger.EXPECT().LogPath().Return("/var/log/archup-install.log").AnyTimes() | |
| 23 | 23 | mockFS.EXPECT().WriteFile(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() | |
| 24 | + | mockFS.EXPECT().MkdirAll(gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | |
| 24 | 25 | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() | |
| 25 | 26 | mockChrExec.EXPECT().ExecuteInChrootWithStdin(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | |
| 26 | 27 | mockChrExec.EXPECT().ChrootSystemctl(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | |
| @@ -21,6 +21,7 @@ func TestConfigureSystemHandler_Handle_Success(t *testing.T) { | |||||
| 21 | mockLogger.EXPECT().Warn(gomock.Any(), gomock.Any()).AnyTimes() | 21 | mockLogger.EXPECT().Warn(gomock.Any(), gomock.Any()).AnyTimes() | ||
| 22 | mockLogger.EXPECT().LogPath().Return("/var/log/archup-install.log").AnyTimes() | 22 | mockLogger.EXPECT().LogPath().Return("/var/log/archup-install.log").AnyTimes() | ||
| 23 | mockFS.EXPECT().WriteFile(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() | 23 | mockFS.EXPECT().WriteFile(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() | ||
| 24 | + | mockFS.EXPECT().MkdirAll(gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | |||
| 24 | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() | 25 | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() | ||
| 25 | mockChrExec.EXPECT().ExecuteInChrootWithStdin(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | 26 | mockChrExec.EXPECT().ExecuteInChrootWithStdin(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | ||
| 26 | mockChrExec.EXPECT().ChrootSystemctl(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | 27 | mockChrExec.EXPECT().ChrootSystemctl(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | ||
M internal/application/handlers/install_base_handler.go +11 -0
| @@ -129,10 +129,16 @@ func (h *InstallBaseHandler) setupCachyOSOnHost(ctx context.Context) error { | |||
| 129 | 129 | cachyOSKeyID = "F3B607488DB35A47" | |
| 130 | 130 | keyserver = "keyserver.ubuntu.com" | |
| 131 | 131 | hostPacmanConf = "/etc/pacman.conf" | |
| 132 | + | cachyOSMirrorlistDir = "/etc/pacman.d" | |
| 132 | 133 | cachyOSMirrorlistPath = "/etc/pacman.d/cachyos-mirrorlist" | |
| 133 | 134 | cachyOSMirrorlist = "## CachyOS mirrorlist\nServer = https://mirror.cachyos.org/repo/$arch/$repo\n" | |
| 134 | 135 | ) | |
| 135 | 136 | ||
| 137 | + | // Ensure the pacman keyring is initialized before any key operations. | |
| 138 | + | if _, err := h.cmdExec.Execute(ctx, "pacman-key", "--init"); err != nil { | |
| 139 | + | return fmt.Errorf("failed to init pacman keyring on host: %w", err) | |
| 140 | + | } | |
| 141 | + | ||
| 136 | 142 | // Only fetch from keyserver if key is not already present. | |
| 137 | 143 | if _, err := h.cmdExec.Execute(ctx, "pacman-key", "--list-keys", cachyOSKeyID); err != nil { | |
| 138 | 144 | if _, err := h.cmdExec.Execute(ctx, "pacman-key", "--recv-keys", | |
| @@ -146,6 +152,11 @@ func (h *InstallBaseHandler) setupCachyOSOnHost(ctx context.Context) error { | |||
| 146 | 152 | return fmt.Errorf("failed to sign CachyOS key on host: %w", err) | |
| 147 | 153 | } | |
| 148 | 154 | ||
| 155 | + | // Ensure /etc/pacman.d exists before writing the mirrorlist. | |
| 156 | + | if err := h.fs.MkdirAll(cachyOSMirrorlistDir, 0755); err != nil { | |
| 157 | + | return fmt.Errorf("failed to create pacman.d directory on host: %w", err) | |
| 158 | + | } | |
| 159 | + | ||
| 149 | 160 | // Write static mirrorlist — no versioned package URLs that can go stale. | |
| 150 | 161 | if err := h.fs.WriteFile(cachyOSMirrorlistPath, []byte(cachyOSMirrorlist), 0644); err != nil { | |
| 151 | 162 | return fmt.Errorf("failed to write host CachyOS mirrorlist: %w", err) | |
| @@ -129,10 +129,16 @@ func (h *InstallBaseHandler) setupCachyOSOnHost(ctx context.Context) error { | |||||
| 129 | cachyOSKeyID = "F3B607488DB35A47" | 129 | cachyOSKeyID = "F3B607488DB35A47" | ||
| 130 | keyserver = "keyserver.ubuntu.com" | 130 | keyserver = "keyserver.ubuntu.com" | ||
| 131 | hostPacmanConf = "/etc/pacman.conf" | 131 | hostPacmanConf = "/etc/pacman.conf" | ||
| 132 | + | cachyOSMirrorlistDir = "/etc/pacman.d" | |||
| 132 | cachyOSMirrorlistPath = "/etc/pacman.d/cachyos-mirrorlist" | 133 | cachyOSMirrorlistPath = "/etc/pacman.d/cachyos-mirrorlist" | ||
| 133 | cachyOSMirrorlist = "## CachyOS mirrorlist\nServer = https://mirror.cachyos.org/repo/$arch/$repo\n" | 134 | cachyOSMirrorlist = "## CachyOS mirrorlist\nServer = https://mirror.cachyos.org/repo/$arch/$repo\n" | ||
| 134 | ) | 135 | ) | ||
| 135 | 136 | ||||
| 137 | + | // Ensure the pacman keyring is initialized before any key operations. | |||
| 138 | + | if _, err := h.cmdExec.Execute(ctx, "pacman-key", "--init"); err != nil { | |||
| 139 | + | return fmt.Errorf("failed to init pacman keyring on host: %w", err) | |||
| 140 | + | } | |||
| 141 | + | ||||
| 136 | // Only fetch from keyserver if key is not already present. | 142 | // Only fetch from keyserver if key is not already present. | ||
| 137 | if _, err := h.cmdExec.Execute(ctx, "pacman-key", "--list-keys", cachyOSKeyID); err != nil { | 143 | if _, err := h.cmdExec.Execute(ctx, "pacman-key", "--list-keys", cachyOSKeyID); err != nil { | ||
| 138 | if _, err := h.cmdExec.Execute(ctx, "pacman-key", "--recv-keys", | 144 | if _, err := h.cmdExec.Execute(ctx, "pacman-key", "--recv-keys", | ||
| @@ -146,6 +152,11 @@ func (h *InstallBaseHandler) setupCachyOSOnHost(ctx context.Context) error { | |||||
| 146 | return fmt.Errorf("failed to sign CachyOS key on host: %w", err) | 152 | return fmt.Errorf("failed to sign CachyOS key on host: %w", err) | ||
| 147 | } | 153 | } | ||
| 148 | 154 | ||||
| 155 | + | // Ensure /etc/pacman.d exists before writing the mirrorlist. | |||
| 156 | + | if err := h.fs.MkdirAll(cachyOSMirrorlistDir, 0755); err != nil { | |||
| 157 | + | return fmt.Errorf("failed to create pacman.d directory on host: %w", err) | |||
| 158 | + | } | |||
| 159 | + | ||||
| 149 | // Write static mirrorlist — no versioned package URLs that can go stale. | 160 | // Write static mirrorlist — no versioned package URLs that can go stale. | ||
| 150 | if err := h.fs.WriteFile(cachyOSMirrorlistPath, []byte(cachyOSMirrorlist), 0644); err != nil { | 161 | if err := h.fs.WriteFile(cachyOSMirrorlistPath, []byte(cachyOSMirrorlist), 0644); err != nil { | ||
| 151 | return fmt.Errorf("failed to write host CachyOS mirrorlist: %w", err) | 162 | return fmt.Errorf("failed to write host CachyOS mirrorlist: %w", err) | ||
M internal/application/handlers/repos_handler.go +11 -0
| @@ -213,6 +213,11 @@ func (h *ReposHandler) setupCachyOSRepo(ctx context.Context, mountPoint string) | |||
| 213 | 213 | cachyOSMirrorlist = "## CachyOS mirrorlist\nServer = https://mirror.cachyos.org/repo/$arch/$repo\n" | |
| 214 | 214 | ) | |
| 215 | 215 | ||
| 216 | + | // Ensure keyring is initialized inside the chroot. | |
| 217 | + | if _, err := h.chrExec.ExecuteInChroot(ctx, mountPoint, "pacman-key", "--init"); err != nil { | |
| 218 | + | return fmt.Errorf("failed to init pacman keyring in chroot: %w", err) | |
| 219 | + | } | |
| 220 | + | ||
| 216 | 221 | // Only fetch from keyserver if key is not already present in chroot. | |
| 217 | 222 | if _, err := h.chrExec.ExecuteInChroot(ctx, mountPoint, "pacman-key", "--list-keys", cachyOSKeyID); err != nil { | |
| 218 | 223 | if _, err := h.chrExec.ExecuteInChroot(ctx, mountPoint, "pacman-key", "--recv-keys", | |
| @@ -225,6 +230,12 @@ func (h *ReposHandler) setupCachyOSRepo(ctx context.Context, mountPoint string) | |||
| 225 | 230 | return fmt.Errorf("failed to sign CachyOS key: %w", err) | |
| 226 | 231 | } | |
| 227 | 232 | ||
| 233 | + | // Ensure /etc/pacman.d exists inside the chroot before writing mirrorlist. | |
| 234 | + | mirrorlistDir := filepath.Join(mountPoint, "etc", "pacman.d") | |
| 235 | + | if err := h.fs.MkdirAll(mirrorlistDir, 0755); err != nil { | |
| 236 | + | return fmt.Errorf("failed to create pacman.d in chroot: %w", err) | |
| 237 | + | } | |
| 238 | + | ||
| 228 | 239 | // Write static mirrorlist — no versioned package URLs that can go stale. | |
| 229 | 240 | mirrorlistPath := filepath.Join(mountPoint, "etc", "pacman.d", "cachyos-mirrorlist") | |
| 230 | 241 | if err := h.fs.WriteFile(mirrorlistPath, []byte(cachyOSMirrorlist), 0644); err != nil { | |
| @@ -213,6 +213,11 @@ func (h *ReposHandler) setupCachyOSRepo(ctx context.Context, mountPoint string) | |||||
| 213 | cachyOSMirrorlist = "## CachyOS mirrorlist\nServer = https://mirror.cachyos.org/repo/$arch/$repo\n" | 213 | cachyOSMirrorlist = "## CachyOS mirrorlist\nServer = https://mirror.cachyos.org/repo/$arch/$repo\n" | ||
| 214 | ) | 214 | ) | ||
| 215 | 215 | ||||
| 216 | + | // Ensure keyring is initialized inside the chroot. | |||
| 217 | + | if _, err := h.chrExec.ExecuteInChroot(ctx, mountPoint, "pacman-key", "--init"); err != nil { | |||
| 218 | + | return fmt.Errorf("failed to init pacman keyring in chroot: %w", err) | |||
| 219 | + | } | |||
| 220 | + | ||||
| 216 | // Only fetch from keyserver if key is not already present in chroot. | 221 | // Only fetch from keyserver if key is not already present in chroot. | ||
| 217 | if _, err := h.chrExec.ExecuteInChroot(ctx, mountPoint, "pacman-key", "--list-keys", cachyOSKeyID); err != nil { | 222 | if _, err := h.chrExec.ExecuteInChroot(ctx, mountPoint, "pacman-key", "--list-keys", cachyOSKeyID); err != nil { | ||
| 218 | if _, err := h.chrExec.ExecuteInChroot(ctx, mountPoint, "pacman-key", "--recv-keys", | 223 | if _, err := h.chrExec.ExecuteInChroot(ctx, mountPoint, "pacman-key", "--recv-keys", | ||
| @@ -225,6 +230,12 @@ func (h *ReposHandler) setupCachyOSRepo(ctx context.Context, mountPoint string) | |||||
| 225 | return fmt.Errorf("failed to sign CachyOS key: %w", err) | 230 | return fmt.Errorf("failed to sign CachyOS key: %w", err) | ||
| 226 | } | 231 | } | ||
| 227 | 232 | ||||
| 233 | + | // Ensure /etc/pacman.d exists inside the chroot before writing mirrorlist. | |||
| 234 | + | mirrorlistDir := filepath.Join(mountPoint, "etc", "pacman.d") | |||
| 235 | + | if err := h.fs.MkdirAll(mirrorlistDir, 0755); err != nil { | |||
| 236 | + | return fmt.Errorf("failed to create pacman.d in chroot: %w", err) | |||
| 237 | + | } | |||
| 238 | + | ||||
| 228 | // Write static mirrorlist — no versioned package URLs that can go stale. | 239 | // Write static mirrorlist — no versioned package URLs that can go stale. | ||
| 229 | mirrorlistPath := filepath.Join(mountPoint, "etc", "pacman.d", "cachyos-mirrorlist") | 240 | mirrorlistPath := filepath.Join(mountPoint, "etc", "pacman.d", "cachyos-mirrorlist") | ||
| 230 | if err := h.fs.WriteFile(mirrorlistPath, []byte(cachyOSMirrorlist), 0644); err != nil { | 241 | if err := h.fs.WriteFile(mirrorlistPath, []byte(cachyOSMirrorlist), 0644); err != nil { | ||
M internal/application/handlers/repos_handler_test.go +53 -42
| @@ -12,6 +12,10 @@ import ( | |||
| 12 | 12 | "go.uber.org/mock/gomock" | |
| 13 | 13 | ) | |
| 14 | 14 | ||
| 15 | + | func errNotFound(name string) error { | |
| 16 | + | return fmt.Errorf("%s: not found", name) | |
| 17 | + | } | |
| 18 | + | ||
| 15 | 19 | func TestReposHandler_Handle_Minimal(t *testing.T) { | |
| 16 | 20 | ctrl := gomock.NewController(t) | |
| 17 | 21 | defer ctrl.Finish() | |
| @@ -21,6 +25,10 @@ func TestReposHandler_Handle_Minimal(t *testing.T) { | |||
| 21 | 25 | mockLogger := mocks.NewMockLogger(ctrl) | |
| 22 | 26 | ||
| 23 | 27 | mockLogger.EXPECT().Info(gomock.Any(), gomock.Any()).AnyTimes() | |
| 28 | + | mockLogger.EXPECT().Warn(gomock.Any(), gomock.Any()).AnyTimes() | |
| 29 | + | ||
| 30 | + | // extra.packages read fails gracefully (no file present) | |
| 31 | + | mockFS.EXPECT().ReadFile(gomock.Any()).Return(nil, errNotFound("extra.packages")).AnyTimes() | |
| 24 | 32 | ||
| 25 | 33 | handler := NewReposHandler(mockFS, mockChrExec, mockLogger) | |
| 26 | 34 | ||
| @@ -37,19 +45,15 @@ func TestReposHandler_Handle_Minimal(t *testing.T) { | |||
| 37 | 45 | if err != nil { | |
| 38 | 46 | t.Fatalf("expected no error, got %v", err) | |
| 39 | 47 | } | |
| 40 | - | ||
| 41 | 48 | if !result.Success { | |
| 42 | 49 | t.Error("expected success") | |
| 43 | 50 | } | |
| 44 | - | ||
| 45 | 51 | if result.Multilib { | |
| 46 | 52 | t.Error("expected multilib to be disabled") | |
| 47 | 53 | } | |
| 48 | - | ||
| 49 | 54 | if result.Chaotic { | |
| 50 | 55 | t.Error("expected chaotic to be disabled") | |
| 51 | 56 | } | |
| 52 | - | ||
| 53 | 57 | if result.AURHelper != "paru" { | |
| 54 | 58 | t.Errorf("expected paru helper, got %s", result.AURHelper) | |
| 55 | 59 | } | |
| @@ -64,13 +68,21 @@ func TestReposHandler_Handle_AllEnabled(t *testing.T) { | |||
| 64 | 68 | mockLogger := mocks.NewMockLogger(ctrl) | |
| 65 | 69 | ||
| 66 | 70 | mockLogger.EXPECT().Info(gomock.Any(), gomock.Any()).AnyTimes() | |
| 67 | - | mockFS.EXPECT().ReadFile(gomock.Any()).Return([]byte("[core]\n#[multilib]\n#Include = /etc/pacman.d/mirrorlist\n"), nil).AnyTimes() | |
| 71 | + | mockLogger.EXPECT().Warn(gomock.Any(), gomock.Any()).AnyTimes() | |
| 72 | + | ||
| 73 | + | mockFS.EXPECT().ReadFile(gomock.Any()).Return( | |
| 74 | + | []byte("[core]\n#[multilib]\n#Include = /etc/pacman.d/mirrorlist\n"), nil, | |
| 75 | + | ).AnyTimes() | |
| 68 | 76 | mockFS.EXPECT().WriteFile(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | |
| 77 | + | mockFS.EXPECT().MkdirAll(gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | |
| 78 | + | ||
| 79 | + | // Chaotic keyring key ops (chaotic uses --recv-key singular, pacman -U for keyring) | |
| 69 | 80 | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), "pacman-key", "--recv-key", gomock.Any(), "--keyserver", gomock.Any()).Return([]byte{}, nil).AnyTimes() | |
| 70 | 81 | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), "pacman-key", "--lsign-key", gomock.Any()).Return([]byte{}, nil).AnyTimes() | |
| 71 | 82 | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), "pacman", "-U", "--noconfirm", gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() | |
| 72 | 83 | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), "pacman", "-Sy", "--noconfirm").Return([]byte{}, nil).AnyTimes() | |
| 73 | 84 | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), "pacman", "-S", "--noconfirm", gomock.Any()).Return([]byte{}, nil).AnyTimes() | |
| 85 | + | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), "pacman", "-S", "--noconfirm", "--needed", gomock.Any()).Return([]byte{}, nil).AnyTimes() | |
| 74 | 86 | ||
| 75 | 87 | handler := NewReposHandler(mockFS, mockChrExec, mockLogger) | |
| 76 | 88 | ||
| @@ -87,19 +99,15 @@ func TestReposHandler_Handle_AllEnabled(t *testing.T) { | |||
| 87 | 99 | if err != nil { | |
| 88 | 100 | t.Fatalf("expected no error, got %v", err) | |
| 89 | 101 | } | |
| 90 | - | ||
| 91 | 102 | if !result.Success { | |
| 92 | 103 | t.Error("expected success") | |
| 93 | 104 | } | |
| 94 | - | ||
| 95 | 105 | if !result.Multilib { | |
| 96 | 106 | t.Error("expected multilib to be enabled") | |
| 97 | 107 | } | |
| 98 | - | ||
| 99 | 108 | if !result.Chaotic { | |
| 100 | 109 | t.Error("expected chaotic to be enabled") | |
| 101 | 110 | } | |
| 102 | - | ||
| 103 | 111 | if result.AURHelper != "yay" { | |
| 104 | 112 | t.Errorf("expected yay helper, got %s", result.AURHelper) | |
| 105 | 113 | } | |
| @@ -115,36 +123,40 @@ func TestReposHandler_Handle_CachyOSKernel_AddsCachyOSRepo(t *testing.T) { | |||
| 115 | 123 | ||
| 116 | 124 | mockLogger.EXPECT().Info(gomock.Any(), gomock.Any()).AnyTimes() | |
| 117 | 125 | mockLogger.EXPECT().Warn(gomock.Any(), gomock.Any()).AnyTimes() | |
| 118 | - | // extra.packages read will fail gracefully | |
| 119 | - | mockFS.EXPECT().ReadFile(gomock.Not("/mnt/etc/pacman.conf")).Return(nil, fmt.Errorf("not found")).AnyTimes() | |
| 120 | - | ||
| 121 | - | // Expect: recv CachyOS key | |
| 122 | - | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), "/mnt", "pacman-key", "--recv-key", | |
| 123 | - | "F3B607488DB35A47", "--keyserver", "keyserver.ubuntu.com").Return([]byte{}, nil) | |
| 124 | - | ||
| 125 | - | // Expect: lsign CachyOS key | |
| 126 | - | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), "/mnt", "pacman-key", "--lsign-key", | |
| 127 | - | "F3B607488DB35A47").Return([]byte{}, nil) | |
| 128 | 126 | ||
| 129 | - | // Expect: pacman -U for CachyOS packages (4 URLs) | |
| 130 | - | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), "/mnt", "pacman", "-U", "--noconfirm", | |
| 131 | - | "https://mirror.cachyos.org/repo/x86_64/cachyos/cachyos-keyring-20240331-1-any.pkg.tar.zst", | |
| 132 | - | "https://mirror.cachyos.org/repo/x86_64/cachyos/cachyos-mirrorlist-18-1-any.pkg.tar.zst", | |
| 133 | - | "https://mirror.cachyos.org/repo/x86_64/cachyos/cachyos-v3-mirrorlist-18-1-any.pkg.tar.zst", | |
| 134 | - | "https://mirror.cachyos.org/repo/x86_64/cachyos/cachyos-v4-mirrorlist-6-1-any.pkg.tar.zst", | |
| 135 | - | ).Return([]byte{}, nil) | |
| 127 | + | // extra.packages read fails gracefully; pacman.conf read succeeds | |
| 128 | + | mockFS.EXPECT().ReadFile("/mnt/etc/pacman.conf").Return( | |
| 129 | + | []byte("[core]\nInclude = /etc/pacman.d/mirrorlist\n"), nil, | |
| 130 | + | ) | |
| 131 | + | mockFS.EXPECT().ReadFile(gomock.Any()).Return(nil, errNotFound("extra.packages")).AnyTimes() | |
| 136 | 132 | ||
| 137 | - | // Expect: ReadFile for pacman.conf | |
| 138 | - | mockFS.EXPECT().ReadFile("/mnt/etc/pacman.conf").Return([]byte("[core]\nInclude = /etc/pacman.d/mirrorlist\n"), nil) | |
| 133 | + | // MkdirAll for /mnt/etc/pacman.d | |
| 134 | + | mockFS.EXPECT().MkdirAll(gomock.Any(), gomock.Any()).Return(nil) | |
| 139 | 135 | ||
| 140 | - | // Expect: WriteFile with content containing [cachyos] | |
| 136 | + | // WriteFile: mirrorlist + pacman.conf | |
| 137 | + | mockFS.EXPECT().WriteFile("/mnt/etc/pacman.d/cachyos-mirrorlist", gomock.Any(), gomock.Any()).Return(nil) | |
| 141 | 138 | mockFS.EXPECT().WriteFile("/mnt/etc/pacman.conf", gomock.Any(), gomock.Any()).DoAndReturn( | |
| 142 | 139 | func(path string, data []byte, perm interface{}) error { | |
| 143 | 140 | if !strings.Contains(string(data), "[cachyos]") { | |
| 144 | 141 | t.Errorf("expected pacman.conf to contain [cachyos], got:\n%s", string(data)) | |
| 145 | 142 | } | |
| 146 | 143 | return nil | |
| 147 | - | }) | |
| 144 | + | }, | |
| 145 | + | ) | |
| 146 | + | ||
| 147 | + | // pacman-key --init | |
| 148 | + | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), "/mnt", "pacman-key", "--init").Return([]byte{}, nil) | |
| 149 | + | // --list-keys: key not present → triggers --recv-keys | |
| 150 | + | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), "/mnt", "pacman-key", "--list-keys", "F3B607488DB35A47").Return(nil, errNotFound("key")) | |
| 151 | + | // --recv-keys | |
| 152 | + | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), "/mnt", "pacman-key", "--recv-keys", | |
| 153 | + | "F3B607488DB35A47", "--keyserver", "keyserver.ubuntu.com").Return([]byte{}, nil) | |
| 154 | + | // --lsign-key | |
| 155 | + | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), "/mnt", "pacman-key", "--lsign-key", | |
| 156 | + | "F3B607488DB35A47").Return([]byte{}, nil) | |
| 157 | + | ||
| 158 | + | // No pacman -Sy here: CachyOS-only (no multilib, no chaotic) — sync is skipped in repos phase | |
| 159 | + | // (chroot sync only runs when multilib or chaotic are enabled) | |
| 148 | 160 | ||
| 149 | 161 | handler := NewReposHandler(mockFS, mockChrExec, mockLogger) | |
| 150 | 162 | ||
| @@ -161,7 +173,6 @@ func TestReposHandler_Handle_CachyOSKernel_AddsCachyOSRepo(t *testing.T) { | |||
| 161 | 173 | if err != nil { | |
| 162 | 174 | t.Fatalf("expected no error, got %v", err) | |
| 163 | 175 | } | |
| 164 | - | ||
| 165 | 176 | if !result.Success { | |
| 166 | 177 | t.Error("expected success") | |
| 167 | 178 | } | |
| @@ -176,20 +187,21 @@ func TestReposHandler_Handle_WithAdditionalRepos(t *testing.T) { | |||
| 176 | 187 | mockLogger := mocks.NewMockLogger(ctrl) | |
| 177 | 188 | ||
| 178 | 189 | mockLogger.EXPECT().Info(gomock.Any(), gomock.Any()).AnyTimes() | |
| 190 | + | mockLogger.EXPECT().Warn(gomock.Any(), gomock.Any()).AnyTimes() | |
| 179 | 191 | ||
| 180 | - | handler := NewReposHandler(mockFS, mockChrExec, mockLogger) | |
| 192 | + | mockFS.EXPECT().ReadFile(gomock.Any()).Return(nil, errNotFound("extra.packages")).AnyTimes() | |
| 181 | 193 | ||
| 182 | - | additionalRepos := []string{ | |
| 183 | - | "https://example.com/archup", | |
| 184 | - | "https://custom.repo/packages", | |
| 185 | - | } | |
| 194 | + | handler := NewReposHandler(mockFS, mockChrExec, mockLogger) | |
| 186 | 195 | ||
| 187 | 196 | cmd := commands.SetupRepositoriesCommand{ | |
| 188 | - | MountPoint: "/mnt", | |
| 189 | - | EnableMultilib: false, | |
| 190 | - | EnableChaotic: false, | |
| 191 | - | AURHelper: packages.AURHelperParu, | |
| 192 | - | AdditionalRepos: additionalRepos, | |
| 197 | + | MountPoint: "/mnt", | |
| 198 | + | EnableMultilib: false, | |
| 199 | + | EnableChaotic: false, | |
| 200 | + | AURHelper: packages.AURHelperParu, | |
| 201 | + | AdditionalRepos: []string{ | |
| 202 | + | "https://example.com/archup", | |
| 203 | + | "https://custom.repo/packages", | |
| 204 | + | }, | |
| 193 | 205 | } | |
| 194 | 206 | ||
| 195 | 207 | result, err := handler.Handle(context.Background(), cmd) | |
| @@ -197,7 +209,6 @@ func TestReposHandler_Handle_WithAdditionalRepos(t *testing.T) { | |||
| 197 | 209 | if err != nil { | |
| 198 | 210 | t.Fatalf("expected no error, got %v", err) | |
| 199 | 211 | } | |
| 200 | - | ||
| 201 | 212 | if !result.Success { | |
| 202 | 213 | t.Error("expected success") | |
| 203 | 214 | } | |
| @@ -12,6 +12,10 @@ import ( | |||||
| 12 | "go.uber.org/mock/gomock" | 12 | "go.uber.org/mock/gomock" | ||
| 13 | ) | 13 | ) | ||
| 14 | 14 | ||||
| 15 | + | func errNotFound(name string) error { | |||
| 16 | + | return fmt.Errorf("%s: not found", name) | |||
| 17 | + | } | |||
| 18 | + | ||||
| 15 | func TestReposHandler_Handle_Minimal(t *testing.T) { | 19 | func TestReposHandler_Handle_Minimal(t *testing.T) { | ||
| 16 | ctrl := gomock.NewController(t) | 20 | ctrl := gomock.NewController(t) | ||
| 17 | defer ctrl.Finish() | 21 | defer ctrl.Finish() | ||
| @@ -21,6 +25,10 @@ func TestReposHandler_Handle_Minimal(t *testing.T) { | |||||
| 21 | mockLogger := mocks.NewMockLogger(ctrl) | 25 | mockLogger := mocks.NewMockLogger(ctrl) | ||
| 22 | 26 | ||||
| 23 | mockLogger.EXPECT().Info(gomock.Any(), gomock.Any()).AnyTimes() | 27 | mockLogger.EXPECT().Info(gomock.Any(), gomock.Any()).AnyTimes() | ||
| 28 | + | mockLogger.EXPECT().Warn(gomock.Any(), gomock.Any()).AnyTimes() | |||
| 29 | + | ||||
| 30 | + | // extra.packages read fails gracefully (no file present) | |||
| 31 | + | mockFS.EXPECT().ReadFile(gomock.Any()).Return(nil, errNotFound("extra.packages")).AnyTimes() | |||
| 24 | 32 | ||||
| 25 | handler := NewReposHandler(mockFS, mockChrExec, mockLogger) | 33 | handler := NewReposHandler(mockFS, mockChrExec, mockLogger) | ||
| 26 | 34 | ||||
| @@ -37,19 +45,15 @@ func TestReposHandler_Handle_Minimal(t *testing.T) { | |||||
| 37 | if err != nil { | 45 | if err != nil { | ||
| 38 | t.Fatalf("expected no error, got %v", err) | 46 | t.Fatalf("expected no error, got %v", err) | ||
| 39 | } | 47 | } | ||
| 40 | - | ||||
| 41 | if !result.Success { | 48 | if !result.Success { | ||
| 42 | t.Error("expected success") | 49 | t.Error("expected success") | ||
| 43 | } | 50 | } | ||
| 44 | - | ||||
| 45 | if result.Multilib { | 51 | if result.Multilib { | ||
| 46 | t.Error("expected multilib to be disabled") | 52 | t.Error("expected multilib to be disabled") | ||
| 47 | } | 53 | } | ||
| 48 | - | ||||
| 49 | if result.Chaotic { | 54 | if result.Chaotic { | ||
| 50 | t.Error("expected chaotic to be disabled") | 55 | t.Error("expected chaotic to be disabled") | ||
| 51 | } | 56 | } | ||
| 52 | - | ||||
| 53 | if result.AURHelper != "paru" { | 57 | if result.AURHelper != "paru" { | ||
| 54 | t.Errorf("expected paru helper, got %s", result.AURHelper) | 58 | t.Errorf("expected paru helper, got %s", result.AURHelper) | ||
| 55 | } | 59 | } | ||
| @@ -64,13 +68,21 @@ func TestReposHandler_Handle_AllEnabled(t *testing.T) { | |||||
| 64 | mockLogger := mocks.NewMockLogger(ctrl) | 68 | mockLogger := mocks.NewMockLogger(ctrl) | ||
| 65 | 69 | ||||
| 66 | mockLogger.EXPECT().Info(gomock.Any(), gomock.Any()).AnyTimes() | 70 | mockLogger.EXPECT().Info(gomock.Any(), gomock.Any()).AnyTimes() | ||
| 67 | - | mockFS.EXPECT().ReadFile(gomock.Any()).Return([]byte("[core]\n#[multilib]\n#Include = /etc/pacman.d/mirrorlist\n"), nil).AnyTimes() | 71 | + | mockLogger.EXPECT().Warn(gomock.Any(), gomock.Any()).AnyTimes() |
| 72 | + | ||||
| 73 | + | mockFS.EXPECT().ReadFile(gomock.Any()).Return( | |||
| 74 | + | []byte("[core]\n#[multilib]\n#Include = /etc/pacman.d/mirrorlist\n"), nil, | |||
| 75 | + | ).AnyTimes() | |||
| 68 | mockFS.EXPECT().WriteFile(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | 76 | mockFS.EXPECT().WriteFile(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | ||
| 77 | + | mockFS.EXPECT().MkdirAll(gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | |||
| 78 | + | ||||
| 79 | + | // Chaotic keyring key ops (chaotic uses --recv-key singular, pacman -U for keyring) | |||
| 69 | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), "pacman-key", "--recv-key", gomock.Any(), "--keyserver", gomock.Any()).Return([]byte{}, nil).AnyTimes() | 80 | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), "pacman-key", "--recv-key", gomock.Any(), "--keyserver", gomock.Any()).Return([]byte{}, nil).AnyTimes() | ||
| 70 | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), "pacman-key", "--lsign-key", gomock.Any()).Return([]byte{}, nil).AnyTimes() | 81 | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), "pacman-key", "--lsign-key", gomock.Any()).Return([]byte{}, nil).AnyTimes() | ||
| 71 | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), "pacman", "-U", "--noconfirm", gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() | 82 | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), "pacman", "-U", "--noconfirm", gomock.Any(), gomock.Any()).Return([]byte{}, nil).AnyTimes() | ||
| 72 | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), "pacman", "-Sy", "--noconfirm").Return([]byte{}, nil).AnyTimes() | 83 | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), "pacman", "-Sy", "--noconfirm").Return([]byte{}, nil).AnyTimes() | ||
| 73 | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), "pacman", "-S", "--noconfirm", gomock.Any()).Return([]byte{}, nil).AnyTimes() | 84 | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), "pacman", "-S", "--noconfirm", gomock.Any()).Return([]byte{}, nil).AnyTimes() | ||
| 85 | + | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), gomock.Any(), "pacman", "-S", "--noconfirm", "--needed", gomock.Any()).Return([]byte{}, nil).AnyTimes() | |||
| 74 | 86 | ||||
| 75 | handler := NewReposHandler(mockFS, mockChrExec, mockLogger) | 87 | handler := NewReposHandler(mockFS, mockChrExec, mockLogger) | ||
| 76 | 88 | ||||
| @@ -87,19 +99,15 @@ func TestReposHandler_Handle_AllEnabled(t *testing.T) { | |||||
| 87 | if err != nil { | 99 | if err != nil { | ||
| 88 | t.Fatalf("expected no error, got %v", err) | 100 | t.Fatalf("expected no error, got %v", err) | ||
| 89 | } | 101 | } | ||
| 90 | - | ||||
| 91 | if !result.Success { | 102 | if !result.Success { | ||
| 92 | t.Error("expected success") | 103 | t.Error("expected success") | ||
| 93 | } | 104 | } | ||
| 94 | - | ||||
| 95 | if !result.Multilib { | 105 | if !result.Multilib { | ||
| 96 | t.Error("expected multilib to be enabled") | 106 | t.Error("expected multilib to be enabled") | ||
| 97 | } | 107 | } | ||
| 98 | - | ||||
| 99 | if !result.Chaotic { | 108 | if !result.Chaotic { | ||
| 100 | t.Error("expected chaotic to be enabled") | 109 | t.Error("expected chaotic to be enabled") | ||
| 101 | } | 110 | } | ||
| 102 | - | ||||
| 103 | if result.AURHelper != "yay" { | 111 | if result.AURHelper != "yay" { | ||
| 104 | t.Errorf("expected yay helper, got %s", result.AURHelper) | 112 | t.Errorf("expected yay helper, got %s", result.AURHelper) | ||
| 105 | } | 113 | } | ||
| @@ -115,36 +123,40 @@ func TestReposHandler_Handle_CachyOSKernel_AddsCachyOSRepo(t *testing.T) { | |||||
| 115 | 123 | ||||
| 116 | mockLogger.EXPECT().Info(gomock.Any(), gomock.Any()).AnyTimes() | 124 | mockLogger.EXPECT().Info(gomock.Any(), gomock.Any()).AnyTimes() | ||
| 117 | mockLogger.EXPECT().Warn(gomock.Any(), gomock.Any()).AnyTimes() | 125 | mockLogger.EXPECT().Warn(gomock.Any(), gomock.Any()).AnyTimes() | ||
| 118 | - | // extra.packages read will fail gracefully | |||
| 119 | - | mockFS.EXPECT().ReadFile(gomock.Not("/mnt/etc/pacman.conf")).Return(nil, fmt.Errorf("not found")).AnyTimes() | |||
| 120 | - | ||||
| 121 | - | // Expect: recv CachyOS key | |||
| 122 | - | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), "/mnt", "pacman-key", "--recv-key", | |||
| 123 | - | "F3B607488DB35A47", "--keyserver", "keyserver.ubuntu.com").Return([]byte{}, nil) | |||
| 124 | - | ||||
| 125 | - | // Expect: lsign CachyOS key | |||
| 126 | - | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), "/mnt", "pacman-key", "--lsign-key", | |||
| 127 | - | "F3B607488DB35A47").Return([]byte{}, nil) | |||
| 128 | 126 | ||||
| 129 | - | // Expect: pacman -U for CachyOS packages (4 URLs) | 127 | + | // extra.packages read fails gracefully; pacman.conf read succeeds |
| 130 | - | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), "/mnt", "pacman", "-U", "--noconfirm", | 128 | + | mockFS.EXPECT().ReadFile("/mnt/etc/pacman.conf").Return( |
| 131 | - | "https://mirror.cachyos.org/repo/x86_64/cachyos/cachyos-keyring-20240331-1-any.pkg.tar.zst", | 129 | + | []byte("[core]\nInclude = /etc/pacman.d/mirrorlist\n"), nil, |
| 132 | - | "https://mirror.cachyos.org/repo/x86_64/cachyos/cachyos-mirrorlist-18-1-any.pkg.tar.zst", | 130 | + | ) |
| 133 | - | "https://mirror.cachyos.org/repo/x86_64/cachyos/cachyos-v3-mirrorlist-18-1-any.pkg.tar.zst", | 131 | + | mockFS.EXPECT().ReadFile(gomock.Any()).Return(nil, errNotFound("extra.packages")).AnyTimes() |
| 134 | - | "https://mirror.cachyos.org/repo/x86_64/cachyos/cachyos-v4-mirrorlist-6-1-any.pkg.tar.zst", | |||
| 135 | - | ).Return([]byte{}, nil) | |||
| 136 | 132 | ||||
| 137 | - | // Expect: ReadFile for pacman.conf | 133 | + | // MkdirAll for /mnt/etc/pacman.d |
| 138 | - | mockFS.EXPECT().ReadFile("/mnt/etc/pacman.conf").Return([]byte("[core]\nInclude = /etc/pacman.d/mirrorlist\n"), nil) | 134 | + | mockFS.EXPECT().MkdirAll(gomock.Any(), gomock.Any()).Return(nil) |
| 139 | 135 | ||||
| 140 | - | // Expect: WriteFile with content containing [cachyos] | 136 | + | // WriteFile: mirrorlist + pacman.conf |
| 137 | + | mockFS.EXPECT().WriteFile("/mnt/etc/pacman.d/cachyos-mirrorlist", gomock.Any(), gomock.Any()).Return(nil) | |||
| 141 | mockFS.EXPECT().WriteFile("/mnt/etc/pacman.conf", gomock.Any(), gomock.Any()).DoAndReturn( | 138 | mockFS.EXPECT().WriteFile("/mnt/etc/pacman.conf", gomock.Any(), gomock.Any()).DoAndReturn( | ||
| 142 | func(path string, data []byte, perm interface{}) error { | 139 | func(path string, data []byte, perm interface{}) error { | ||
| 143 | if !strings.Contains(string(data), "[cachyos]") { | 140 | if !strings.Contains(string(data), "[cachyos]") { | ||
| 144 | t.Errorf("expected pacman.conf to contain [cachyos], got:\n%s", string(data)) | 141 | t.Errorf("expected pacman.conf to contain [cachyos], got:\n%s", string(data)) | ||
| 145 | } | 142 | } | ||
| 146 | return nil | 143 | return nil | ||
| 147 | - | }) | 144 | + | }, |
| 145 | + | ) | |||
| 146 | + | ||||
| 147 | + | // pacman-key --init | |||
| 148 | + | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), "/mnt", "pacman-key", "--init").Return([]byte{}, nil) | |||
| 149 | + | // --list-keys: key not present → triggers --recv-keys | |||
| 150 | + | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), "/mnt", "pacman-key", "--list-keys", "F3B607488DB35A47").Return(nil, errNotFound("key")) | |||
| 151 | + | // --recv-keys | |||
| 152 | + | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), "/mnt", "pacman-key", "--recv-keys", | |||
| 153 | + | "F3B607488DB35A47", "--keyserver", "keyserver.ubuntu.com").Return([]byte{}, nil) | |||
| 154 | + | // --lsign-key | |||
| 155 | + | mockChrExec.EXPECT().ExecuteInChroot(gomock.Any(), "/mnt", "pacman-key", "--lsign-key", | |||
| 156 | + | "F3B607488DB35A47").Return([]byte{}, nil) | |||
| 157 | + | ||||
| 158 | + | // No pacman -Sy here: CachyOS-only (no multilib, no chaotic) — sync is skipped in repos phase | |||
| 159 | + | // (chroot sync only runs when multilib or chaotic are enabled) | |||
| 148 | 160 | ||||
| 149 | handler := NewReposHandler(mockFS, mockChrExec, mockLogger) | 161 | handler := NewReposHandler(mockFS, mockChrExec, mockLogger) | ||
| 150 | 162 | ||||
| @@ -161,7 +173,6 @@ func TestReposHandler_Handle_CachyOSKernel_AddsCachyOSRepo(t *testing.T) { | |||||
| 161 | if err != nil { | 173 | if err != nil { | ||
| 162 | t.Fatalf("expected no error, got %v", err) | 174 | t.Fatalf("expected no error, got %v", err) | ||
| 163 | } | 175 | } | ||
| 164 | - | ||||
| 165 | if !result.Success { | 176 | if !result.Success { | ||
| 166 | t.Error("expected success") | 177 | t.Error("expected success") | ||
| 167 | } | 178 | } | ||
| @@ -176,20 +187,21 @@ func TestReposHandler_Handle_WithAdditionalRepos(t *testing.T) { | |||||
| 176 | mockLogger := mocks.NewMockLogger(ctrl) | 187 | mockLogger := mocks.NewMockLogger(ctrl) | ||
| 177 | 188 | ||||
| 178 | mockLogger.EXPECT().Info(gomock.Any(), gomock.Any()).AnyTimes() | 189 | mockLogger.EXPECT().Info(gomock.Any(), gomock.Any()).AnyTimes() | ||
| 190 | + | mockLogger.EXPECT().Warn(gomock.Any(), gomock.Any()).AnyTimes() | |||
| 179 | 191 | ||||
| 180 | - | handler := NewReposHandler(mockFS, mockChrExec, mockLogger) | 192 | + | mockFS.EXPECT().ReadFile(gomock.Any()).Return(nil, errNotFound("extra.packages")).AnyTimes() |
| 181 | 193 | ||||
| 182 | - | additionalRepos := []string{ | 194 | + | handler := NewReposHandler(mockFS, mockChrExec, mockLogger) |
| 183 | - | "https://example.com/archup", | |||
| 184 | - | "https://custom.repo/packages", | |||
| 185 | - | } | |||
| 186 | 195 | ||||
| 187 | cmd := commands.SetupRepositoriesCommand{ | 196 | cmd := commands.SetupRepositoriesCommand{ | ||
| 188 | - | MountPoint: "/mnt", | 197 | + | MountPoint: "/mnt", |
| 189 | - | EnableMultilib: false, | 198 | + | EnableMultilib: false, |
| 190 | - | EnableChaotic: false, | 199 | + | EnableChaotic: false, |
| 191 | - | AURHelper: packages.AURHelperParu, | 200 | + | AURHelper: packages.AURHelperParu, |
| 192 | - | AdditionalRepos: additionalRepos, | 201 | + | AdditionalRepos: []string{ |
| 202 | + | "https://example.com/archup", | |||
| 203 | + | "https://custom.repo/packages", | |||
| 204 | + | }, | |||
| 193 | } | 205 | } | ||
| 194 | 206 | ||||
| 195 | result, err := handler.Handle(context.Background(), cmd) | 207 | result, err := handler.Handle(context.Background(), cmd) | ||
| @@ -197,7 +209,6 @@ func TestReposHandler_Handle_WithAdditionalRepos(t *testing.T) { | |||||
| 197 | if err != nil { | 209 | if err != nil { | ||
| 198 | t.Fatalf("expected no error, got %v", err) | 210 | t.Fatalf("expected no error, got %v", err) | ||
| 199 | } | 211 | } | ||
| 200 | - | ||||
| 201 | if !result.Success { | 212 | if !result.Success { | ||
| 202 | t.Error("expected success") | 213 | t.Error("expected success") | ||
| 203 | } | 214 | } | ||
M internal/phases/systemconfig_test.go +1 -0
| @@ -229,6 +229,7 @@ func TestConfigPhaseExecute(t *testing.T) { | |||
| 229 | 229 | mockChrExec.EXPECT().ChrootExecWithStdin(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | |
| 230 | 230 | mockChrExec.EXPECT().ChrootSystemctl(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | |
| 231 | 231 | mockFS.EXPECT().WriteFile(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | |
| 232 | + | mockFS.EXPECT().MkdirAll(gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | |
| 232 | 233 | ||
| 233 | 234 | tmpDir := t.TempDir() | |
| 234 | 235 | logPath := filepath.Join(tmpDir, "test.log") | |
| @@ -229,6 +229,7 @@ func TestConfigPhaseExecute(t *testing.T) { | |||||
| 229 | mockChrExec.EXPECT().ChrootExecWithStdin(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | 229 | mockChrExec.EXPECT().ChrootExecWithStdin(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | ||
| 230 | mockChrExec.EXPECT().ChrootSystemctl(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | 230 | mockChrExec.EXPECT().ChrootSystemctl(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | ||
| 231 | mockFS.EXPECT().WriteFile(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | 231 | mockFS.EXPECT().WriteFile(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | ||
| 232 | + | mockFS.EXPECT().MkdirAll(gomock.Any(), gomock.Any()).Return(nil).AnyTimes() | |||
| 232 | 233 | ||||
| 233 | tmpDir := t.TempDir() | 234 | tmpDir := t.TempDir() | ||
| 234 | logPath := filepath.Join(tmpDir, "test.log") | 235 | logPath := filepath.Join(tmpDir, "test.log") | ||