diff --git a/.github/workflows/autoupdate.yaml b/.github/workflows/autoupdate.yaml index 4afcf8d..83f5afb 100644 --- a/.github/workflows/autoupdate.yaml +++ b/.github/workflows/autoupdate.yaml @@ -14,7 +14,6 @@ jobs: autoupdate: uses: lukaszraczylo/shared-actions/.github/workflows/go-autoupdate.yaml@main with: - go-version: "1.24" + go-version: ">=1.24" release-workflow: "release.yml" - secrets: - pat-token: ${{ secrets.HOMEBREW_TAP_TOKEN }} + secrets: inherit diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 0fe75ce..25d7b99 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -9,8 +9,14 @@ on: - "**" - "!main" +permissions: + contents: write + actions: write + pull-requests: write + security-events: write + jobs: pr-checks: uses: lukaszraczylo/shared-actions/.github/workflows/go-pr.yaml@main with: - go-version: "1.24" + go-version: ">=1.24" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7b69c99..9bb21e8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,5 +17,5 @@ jobs: release: uses: lukaszraczylo/shared-actions/.github/workflows/go-release.yaml@main with: - go-version: "1.24" + go-version: ">=1.24" secrets: inherit diff --git a/cmd/lolcathost/main.go b/cmd/lolcathost/main.go index 61a733b..7999ceb 100644 --- a/cmd/lolcathost/main.go +++ b/cmd/lolcathost/main.go @@ -204,7 +204,7 @@ func runList() { fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n", status, e.Domain, e.IP, e.Alias, e.Group) } - w.Flush() + _ = w.Flush() } func runOn(alias string) { diff --git a/internal/client/client.go b/internal/client/client.go index 90d2219..6025a9d 100644 --- a/internal/client/client.go +++ b/internal/client/client.go @@ -44,7 +44,7 @@ func (c *Client) Connect() error { // Close existing connection if any if c.conn != nil { - c.conn.Close() + _ = c.conn.Close() c.conn = nil c.reader = nil } @@ -83,7 +83,7 @@ func (c *Client) send(req *protocol.Request) (*protocol.Response, error) { } // Set deadline - c.conn.SetDeadline(time.Now().Add(c.timeout)) + _ = c.conn.SetDeadline(time.Now().Add(c.timeout)) // Send request data, err := json.Marshal(req) diff --git a/internal/config/config.go b/internal/config/config.go index 8fecbb8..d67196b 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -167,7 +167,7 @@ func (m *Manager) watchLoop() { func (m *Manager) Stop() { close(m.stopCh) if m.watcher != nil { - m.watcher.Close() + _ = m.watcher.Close() } } @@ -338,76 +338,6 @@ func (c *Config) DeleteHost(alias string) bool { return false } -// UpdateHost updates an existing host by alias. -func (c *Config) UpdateHost(oldAlias, domain, ip, newAlias, groupName string) error { - // Find the host - var foundGroup int = -1 - var foundHost int = -1 - for i := range c.Groups { - for j := range c.Groups[i].Hosts { - if c.Groups[i].Hosts[j].Alias == oldAlias { - foundGroup = i - foundHost = j - break - } - } - if foundHost >= 0 { - break - } - } - - if foundHost < 0 { - return fmt.Errorf("alias not found: %s", oldAlias) - } - - // Check for duplicate alias if alias is changing - if oldAlias != newAlias { - if existing, _ := c.FindHostByAlias(newAlias); existing != nil { - return fmt.Errorf("alias already exists: %s", newAlias) - } - } - - // Get current enabled state - enabled := c.Groups[foundGroup].Hosts[foundHost].Enabled - - // If group is changing, move to new group - if c.Groups[foundGroup].Name != groupName { - // Remove from old group - c.Groups[foundGroup].Hosts = append(c.Groups[foundGroup].Hosts[:foundHost], c.Groups[foundGroup].Hosts[foundHost+1:]...) - - // Add to new group - host := Host{ - Domain: domain, - IP: ip, - Alias: newAlias, - Enabled: enabled, - } - - // Find or create target group - found := false - for i := range c.Groups { - if c.Groups[i].Name == groupName { - c.Groups[i].Hosts = append(c.Groups[i].Hosts, host) - found = true - break - } - } - if !found { - c.Groups = append(c.Groups, Group{ - Name: groupName, - Hosts: []Host{host}, - }) - } - } else { - // Update in place - c.Groups[foundGroup].Hosts[foundHost].Domain = domain - c.Groups[foundGroup].Hosts[foundHost].IP = ip - c.Groups[foundGroup].Hosts[foundHost].Alias = newAlias - } - - return nil -} - // ApplyPreset applies a preset to the configuration. func (c *Config) ApplyPreset(name string) error { preset := c.FindPreset(name) @@ -482,6 +412,7 @@ func (m *Manager) Save() error { return fmt.Errorf("failed to marshal config: %w", err) } + // #nosec G306 -- config file should be world-readable if err := os.WriteFile(m.path, data, 0644); err != nil { return fmt.Errorf("failed to write config: %w", err) } @@ -492,6 +423,7 @@ func (m *Manager) Save() error { // CreateDefault creates a default configuration file. func CreateDefault(path string) error { dir := filepath.Dir(path) + // #nosec G301 -- config directory should be world-readable if err := os.MkdirAll(dir, 0755); err != nil { return fmt.Errorf("failed to create config directory: %w", err) } @@ -533,6 +465,7 @@ func CreateDefault(path string) error { return fmt.Errorf("failed to marshal default config: %w", err) } + // #nosec G306 -- config file should be world-readable if err := os.WriteFile(path, data, 0644); err != nil { return fmt.Errorf("failed to write default config: %w", err) } diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 552ca40..b75ca78 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -432,77 +432,6 @@ func TestConfig_DeleteHost(t *testing.T) { }) } -func TestConfig_UpdateHost(t *testing.T) { - t.Run("update in same group", func(t *testing.T) { - cfg := &Config{ - Groups: []Group{ - {Name: "dev", Hosts: []Host{{Domain: "old.com", IP: "127.0.0.1", Alias: "test"}}}, - }, - } - err := cfg.UpdateHost("test", "new.com", "192.168.1.1", "test", "dev") - require.NoError(t, err) - assert.Equal(t, "new.com", cfg.Groups[0].Hosts[0].Domain) - assert.Equal(t, "192.168.1.1", cfg.Groups[0].Hosts[0].IP) - }) - - t.Run("move to different group", func(t *testing.T) { - cfg := &Config{ - Groups: []Group{ - {Name: "source", Hosts: []Host{{Domain: "a.com", IP: "127.0.0.1", Alias: "test"}}}, - {Name: "target", Hosts: []Host{}}, - }, - } - err := cfg.UpdateHost("test", "a.com", "127.0.0.1", "test", "target") - require.NoError(t, err) - assert.Len(t, cfg.Groups[0].Hosts, 0) - assert.Len(t, cfg.Groups[1].Hosts, 1) - }) - - t.Run("move to new group", func(t *testing.T) { - cfg := &Config{ - Groups: []Group{ - {Name: "source", Hosts: []Host{{Domain: "a.com", IP: "127.0.0.1", Alias: "test"}}}, - }, - } - err := cfg.UpdateHost("test", "a.com", "127.0.0.1", "test", "newgroup") - require.NoError(t, err) - assert.Len(t, cfg.Groups, 2) - assert.Equal(t, "newgroup", cfg.Groups[1].Name) - }) - - t.Run("change alias", func(t *testing.T) { - cfg := &Config{ - Groups: []Group{ - {Name: "dev", Hosts: []Host{{Domain: "a.com", IP: "127.0.0.1", Alias: "old"}}}, - }, - } - err := cfg.UpdateHost("old", "a.com", "127.0.0.1", "new", "dev") - require.NoError(t, err) - assert.Equal(t, "new", cfg.Groups[0].Hosts[0].Alias) - }) - - t.Run("alias conflict error", func(t *testing.T) { - cfg := &Config{ - Groups: []Group{ - {Name: "dev", Hosts: []Host{ - {Domain: "a.com", Alias: "a"}, - {Domain: "b.com", Alias: "b"}, - }}, - }, - } - err := cfg.UpdateHost("a", "a.com", "127.0.0.1", "b", "dev") - assert.Error(t, err) - assert.Contains(t, err.Error(), "alias already exists") - }) - - t.Run("host not found error", func(t *testing.T) { - cfg := &Config{Groups: []Group{}} - err := cfg.UpdateHost("nonexistent", "a.com", "127.0.0.1", "new", "dev") - assert.Error(t, err) - assert.Contains(t, err.Error(), "alias not found") - }) -} - func TestConfig_AddPreset(t *testing.T) { t.Run("add new preset", func(t *testing.T) { cfg := &Config{Presets: []Preset{}} diff --git a/internal/daemon/daemon.go b/internal/daemon/daemon.go index 7fa32a9..9d325cd 100644 --- a/internal/daemon/daemon.go +++ b/internal/daemon/daemon.go @@ -44,7 +44,7 @@ func New(configPath string) (*Daemon, error) { cfg.EnsureDefaultGroup() // Save if we added a default group if len(cfg.Groups) == 1 && cfg.Groups[0].Name == "default" && len(cfg.Groups[0].Hosts) == 0 { - cfgManager.Save() + _ = cfgManager.Save() } } diff --git a/internal/daemon/hosts.go b/internal/daemon/hosts.go index 9f561d4..7cdc8fc 100644 --- a/internal/daemon/hosts.go +++ b/internal/daemon/hosts.go @@ -178,13 +178,14 @@ func (m *HostsManager) buildManagedSection(entries []HostEntry) string { func (m *HostsManager) writeAtomic(content string) error { // Write to temp file first tmpFile := m.hostsPath + ".tmp" + // #nosec G306 -- hosts file must be world-readable if err := os.WriteFile(tmpFile, []byte(content), 0644); err != nil { return err } // Rename atomically if err := os.Rename(tmpFile, m.hostsPath); err != nil { - os.Remove(tmpFile) + _ = os.Remove(tmpFile) return err } @@ -193,6 +194,7 @@ func (m *HostsManager) writeAtomic(content string) error { // CreateBackup creates a backup of the current hosts file. func (m *HostsManager) CreateBackup() error { + // #nosec G301 -- backup directory should be world-readable for recovery if err := os.MkdirAll(m.backupDir, 0755); err != nil { return fmt.Errorf("failed to create backup directory: %w", err) } @@ -205,6 +207,7 @@ func (m *HostsManager) CreateBackup() error { timestamp := time.Now().Format("20060102-150405") backupPath := filepath.Join(m.backupDir, fmt.Sprintf("hosts.%s.bak", timestamp)) + // #nosec G306 -- backup files should be world-readable for recovery if err := os.WriteFile(backupPath, content, 0644); err != nil { return fmt.Errorf("failed to write backup: %w", err) } @@ -243,7 +246,7 @@ func (m *HostsManager) cleanupBackups() error { // Remove oldest backups for i := MaxBackups; i < len(backups); i++ { path := filepath.Join(m.backupDir, backups[i].Name()) - os.Remove(path) + _ = os.Remove(path) } return nil @@ -301,6 +304,7 @@ func (m *HostsManager) GetBackupContent(name string) (string, error) { return "", fmt.Errorf("invalid backup name") } + // #nosec G304 -- backupPath is validated above: filepath.Base(name) == name and prefix/suffix checks content, err := os.ReadFile(backupPath) if err != nil { return "", fmt.Errorf("failed to read backup: %w", err) @@ -318,6 +322,7 @@ func (m *HostsManager) RestoreBackup(name string) error { return fmt.Errorf("invalid backup name") } + // #nosec G304 -- backupPath is validated above: filepath.Base(name) == name and prefix/suffix checks content, err := os.ReadFile(backupPath) if err != nil { return fmt.Errorf("failed to read backup: %w", err) diff --git a/internal/daemon/peercred_darwin.go b/internal/daemon/peercred_darwin.go index c9100c7..852a838 100644 --- a/internal/daemon/peercred_darwin.go +++ b/internal/daemon/peercred_darwin.go @@ -24,7 +24,7 @@ func (s *Server) getPeerCredentials(conn net.Conn) *PeerCredentials { } var creds *PeerCredentials - rawConn.Control(func(fd uintptr) { + _ = rawConn.Control(func(fd uintptr) { xucred, err := unix.GetsockoptXucred(int(fd), unix.SOL_LOCAL, unix.LOCAL_PEERCRED) if err != nil { return @@ -33,6 +33,7 @@ func (s *Server) getPeerCredentials(conn net.Conn) *PeerCredentials { // Get PID separately using LOCAL_PEERPID var pid int32 pidLen := uint32(unsafe.Sizeof(pid)) + // #nosec G103 -- unsafe required for low-level syscall to get peer PID _, _, errno := syscall.Syscall6( syscall.SYS_GETSOCKOPT, fd, diff --git a/internal/daemon/security.go b/internal/daemon/security.go index 7659dad..68e185f 100644 --- a/internal/daemon/security.go +++ b/internal/daemon/security.go @@ -114,10 +114,12 @@ type AuditEntry struct { func NewAuditLogger(path string) (*AuditLogger, error) { // Ensure directory exists dir := path[:len(path)-len("/audit.log")] + // #nosec G301 -- log directory should be world-readable if err := os.MkdirAll(dir, 0755); err != nil { return nil, fmt.Errorf("failed to create log directory: %w", err) } + // #nosec G304,G302 -- path is from constant AuditLogPath; audit log should be world-readable file, err := os.OpenFile(path, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644) if err != nil { return nil, fmt.Errorf("failed to open audit log: %w", err) diff --git a/internal/daemon/security_test.go b/internal/daemon/security_test.go index 4bf1ca4..ad90122 100644 --- a/internal/daemon/security_test.go +++ b/internal/daemon/security_test.go @@ -1,6 +1,7 @@ package daemon import ( + "fmt" "os" "path/filepath" "testing" @@ -145,26 +146,31 @@ func TestPeerCredentials(t *testing.T) { // Matrix test for rate limiting func TestRateLimiter_Matrix(t *testing.T) { - limits := []int{1, 5, 10, 100} - windows := []time.Duration{10 * time.Millisecond, 100 * time.Millisecond, time.Second} + testCases := []struct { + limit int + window time.Duration + }{ + {1, time.Second}, + {5, time.Second}, + {10, time.Second}, + {100, time.Second}, + } - for _, limit := range limits { - for _, window := range windows { - t.Run( - "limit="+string(rune('0'+limit))+"_window="+window.String(), - func(t *testing.T) { - rl := NewRateLimiter(limit, window) + for _, tc := range testCases { + t.Run( + fmt.Sprintf("limit=%d_window=%s", tc.limit, tc.window), + func(t *testing.T) { + rl := NewRateLimiter(tc.limit, tc.window) - // Should allow exactly 'limit' requests - for i := 0; i < limit; i++ { - assert.True(t, rl.Allow(1)) - } + // Should allow exactly 'limit' requests + for i := 0; i < tc.limit; i++ { + assert.True(t, rl.Allow(1), "request %d should be allowed", i) + } - // Next should be blocked - assert.False(t, rl.Allow(1)) - }, - ) - } + // Next should be blocked + assert.False(t, rl.Allow(1), "request after limit should be blocked") + }, + ) } } diff --git a/internal/daemon/server.go b/internal/daemon/server.go index b39a159..eb46aff 100644 --- a/internal/daemon/server.go +++ b/internal/daemon/server.go @@ -48,7 +48,7 @@ func NewServer(socketPath string, cfgManager *config.Manager) *Server { // Start starts the server. func (s *Server) Start() error { // Remove existing socket - os.Remove(s.socketPath) + _ = os.Remove(s.socketPath) listener, err := net.Listen("unix", s.socketPath) if err != nil { @@ -56,14 +56,15 @@ func (s *Server) Start() error { } // Set socket permissions: 0660 root:lolcathost + // #nosec G302 -- socket must be group-accessible for lolcathost group members if err := os.Chmod(s.socketPath, 0660); err != nil { - listener.Close() + _ = listener.Close() return fmt.Errorf("failed to set socket permissions: %w", err) } // Set socket group to lolcathost (GID 850) if err := os.Chown(s.socketPath, 0, 850); err != nil { - listener.Close() + _ = listener.Close() return fmt.Errorf("failed to set socket ownership: %w", err) } @@ -94,13 +95,13 @@ func (s *Server) Stop() error { close(s.stopCh) if s.listener != nil { - s.listener.Close() + _ = s.listener.Close() } - os.Remove(s.socketPath) + _ = os.Remove(s.socketPath) if s.auditLogger != nil { - s.auditLogger.Close() + _ = s.auditLogger.Close() } return nil @@ -200,7 +201,7 @@ func (s *Server) isAuthorized(creds *PeerCredentials) bool { func (s *Server) writeResponse(conn net.Conn, resp *protocol.Response) { data, _ := json.Marshal(resp) data = append(data, '\n') - conn.Write(data) + _, _ = conn.Write(data) } func (s *Server) handleRequest(req *protocol.Request, creds *PeerCredentials) *protocol.Response { @@ -492,7 +493,7 @@ func (s *Server) handleRollback(req *protocol.Request) *protocol.Response { } // Flush DNS after restore - s.flusher.Flush() + _ = s.flusher.Flush() resp, _ := protocol.NewOKResponse(map[string]string{"restored": payload.BackupName}) return resp diff --git a/internal/installer/installer.go b/internal/installer/installer.go index ee7f794..a645431 100644 --- a/internal/installer/installer.go +++ b/internal/installer/installer.go @@ -168,7 +168,7 @@ func (i *Installer) Uninstall() error { } // Remove socket - os.Remove(SocketPath) + _ = os.Remove(SocketPath) // Note: We don't remove the group, logs, or backups // The user may want to keep these @@ -225,6 +225,7 @@ func (i *Installer) createGroupDarwin() error { } for _, args := range cmds { + // #nosec G204 -- args are hardcoded dscl commands with the constant GroupName if err := exec.Command(args[0], args[1:]...).Run(); err != nil { return fmt.Errorf("command %v failed: %w", args, err) } @@ -315,6 +316,7 @@ func (i *Installer) createDirectories() error { for _, dir := range dirs { i.log(" Creating directory '%s'...", dir) + // #nosec G301 -- system directories should be world-readable if err := os.MkdirAll(dir, 0755); err != nil { return fmt.Errorf("failed to create %s: %w", dir, err) } @@ -340,21 +342,23 @@ func (i *Installer) installLaunchDaemon() error { // Unload if already loaded (do this before writing plist) i.log(" Stopping existing daemon if running...") - exec.Command("launchctl", "bootout", "system/com.lolcathost.daemon").Run() + _ = exec.Command("launchctl", "bootout", "system/com.lolcathost.daemon").Run() // Give launchd time to fully unload the service time.Sleep(500 * time.Millisecond) // Remove old plist to ensure clean state - os.Remove(plistPath) + _ = os.Remove(plistPath) i.log(" Writing LaunchDaemon plist...") + // #nosec G306 -- plist files are world-readable by convention if err := os.WriteFile(plistPath, []byte(plistContent), 0644); err != nil { return fmt.Errorf("failed to write plist: %w", err) } // Bootstrap the daemon i.log(" Starting daemon...") + // #nosec G204 -- plistPath is constructed from constant LaunchDaemonDir cmd := exec.Command("launchctl", "bootstrap", "system", plistPath) output, err := cmd.CombinedOutput() if err != nil { @@ -376,10 +380,10 @@ func (i *Installer) uninstallLaunchDaemon() { plistPath := filepath.Join(LaunchDaemonDir, "com.lolcathost.daemon.plist") i.log(" Stopping daemon...") - exec.Command("launchctl", "bootout", "system/com.lolcathost.daemon").Run() + _ = exec.Command("launchctl", "bootout", "system/com.lolcathost.daemon").Run() i.log(" Removing LaunchDaemon plist...") - os.Remove(plistPath) + _ = os.Remove(plistPath) } func (i *Installer) installSystemdService() error { @@ -387,6 +391,7 @@ func (i *Installer) installSystemdService() error { unitContent := fmt.Sprintf(SystemdUnit, i.binaryPath) i.log(" Writing systemd unit...") + // #nosec G306 -- systemd unit files are world-readable by convention if err := os.WriteFile(unitPath, []byte(unitContent), 0644); err != nil { return fmt.Errorf("failed to write unit file: %w", err) } @@ -408,12 +413,12 @@ func (i *Installer) installSystemdService() error { func (i *Installer) uninstallSystemdService() { i.log(" Stopping and disabling service...") - exec.Command("systemctl", "disable", "--now", "lolcathost.service").Run() + _ = exec.Command("systemctl", "disable", "--now", "lolcathost.service").Run() i.log(" Removing systemd unit...") - os.Remove(filepath.Join(SystemdDir, "lolcathost.service")) + _ = os.Remove(filepath.Join(SystemdDir, "lolcathost.service")) - exec.Command("systemctl", "daemon-reload").Run() + _ = exec.Command("systemctl", "daemon-reload").Run() } func (i *Installer) createDefaultConfig() error { @@ -430,6 +435,7 @@ func (i *Installer) createDefaultConfig() error { // Create config directory configDir := filepath.Dir(configPath) + // #nosec G301 -- config directory should be world-readable if err := os.MkdirAll(configDir, 0755); err != nil { return fmt.Errorf("failed to create config directory: %w", err) } diff --git a/internal/tui/app.go b/internal/tui/app.go index 3d3389f..6f4e6f4 100644 --- a/internal/tui/app.go +++ b/internal/tui/app.go @@ -354,7 +354,7 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.setError(fmt.Sprintf("Refresh failed: %v", msg.err)) // Mark as disconnected to trigger reconnect m.connected = false - m.client.Close() + _ = m.client.Close() } else { // Always update the list, even if entries is nil/empty m.list.SetItems(msg.entries) @@ -603,7 +603,7 @@ func (m *Model) handleFormKey(msg tea.KeyMsg) tea.Cmd { oldAlias := m.form.EditAlias() return tea.Sequence( func() tea.Msg { - m.client.Delete(oldAlias) + _ = m.client.Delete(oldAlias) return nil }, m.addHost(domain, ip, "", group), // Empty alias = auto-generate @@ -678,7 +678,7 @@ func (m *Model) handlePresetFormKey(msg tea.KeyMsg) tea.Cmd { oldName := m.presetPicker.EditName() return tea.Sequence( func() tea.Msg { - m.client.DeletePreset(oldName) + _ = m.client.DeletePreset(oldName) return nil }, m.addPreset(name, enable, disable), @@ -1136,11 +1136,6 @@ func (m *Model) confirmDeleteView() string { return dialogStyle.Render(sb.String()) } -// Run starts the TUI application. -func Run(socketPath string) error { - return RunWithVersion(socketPath, "dev", "", "") -} - // RunWithVersion starts the TUI application with version info for update checking. func RunWithVersion(socketPath, version, githubOwner, githubRepo string) error { m := NewModel(socketPath) diff --git a/internal/version/checker.go b/internal/version/checker.go index 24519bf..82aef25 100644 --- a/internal/version/checker.go +++ b/internal/version/checker.go @@ -76,6 +76,7 @@ func (c *Checker) CheckForUpdate(ctx context.Context) *UpdateInfo { // fetchLatestRelease fetches the latest release info from GitHub API func (c *Checker) fetchLatestRelease(ctx context.Context) (*ReleaseInfo, error) { + // #nosec G107 -- URL is constructed from hardcoded constant and validated owner/repo url := fmt.Sprintf(githubReleasesURL, c.owner, c.repo) req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) @@ -145,15 +146,9 @@ func parseVersion(v string) []int { for _, p := range parts { var num int - fmt.Sscanf(p, "%d", &num) + _, _ = fmt.Sscanf(p, "%d", &num) result = append(result, num) } return result } - -// FormatUpdateMessage formats a user-friendly update notification -func (u *UpdateInfo) FormatUpdateMessage() string { - return fmt.Sprintf("New version available: %s (current: %s) - %s", - u.LatestVersion, u.CurrentVersion, u.ReleaseURL) -} diff --git a/internal/version/checker_test.go b/internal/version/checker_test.go index a7ba712..4ab7790 100644 --- a/internal/version/checker_test.go +++ b/internal/version/checker_test.go @@ -76,19 +76,6 @@ func TestIsNewerVersion(t *testing.T) { } } -func TestUpdateInfo_FormatUpdateMessage(t *testing.T) { - info := &UpdateInfo{ - CurrentVersion: "1.0.0", - LatestVersion: "1.1.0", - ReleaseURL: "https://github.com/lukaszraczylo/lolcathost/releases/tag/v1.1.0", - } - - msg := info.FormatUpdateMessage() - assert.Contains(t, msg, "1.0.0") - assert.Contains(t, msg, "1.1.0") - assert.Contains(t, msg, "https://github.com") -} - func TestNewChecker(t *testing.T) { checker := NewChecker("lukaszraczylo", "lolcathost", "v1.0.0")