From d9888f1a56b3c2b4aaacb407dd3b148dd170fb66 Mon Sep 17 00:00:00 2001 From: Lukasz Raczylo Date: Tue, 9 Dec 2025 01:06:38 +0000 Subject: [PATCH] Cleanup (#14) * Codebase cleanup --- .github/workflows/autoupdate.yaml | 4 ++-- .github/workflows/pr.yaml | 6 ++++++ .github/workflows/release.yml | 2 +- .github/workflows/static.yml | 4 ++-- cmd/kportal/main.go | 4 ++-- internal/config/config.go | 1 + internal/config/mutator.go | 4 ++-- internal/config/watcher.go | 6 +++--- internal/converter/kftray.go | 2 ++ internal/forward/portcheck.go | 4 +++- internal/healthcheck/checker.go | 4 ++-- internal/httplog/logger.go | 1 + internal/httplog/proxy.go | 15 ++++++++------- internal/k8s/discovery.go | 2 +- internal/retry/backoff.go | 3 ++- internal/version/checker.go | 2 +- 16 files changed, 39 insertions(+), 25 deletions(-) diff --git a/.github/workflows/autoupdate.yaml b/.github/workflows/autoupdate.yaml index 9e7b3cb..77da16e 100644 --- a/.github/workflows/autoupdate.yaml +++ b/.github/workflows/autoupdate.yaml @@ -9,6 +9,7 @@ permissions: contents: write actions: write pull-requests: write + security-events: write jobs: autoupdate: @@ -16,5 +17,4 @@ jobs: with: 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 789b522..25d7b99 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -9,6 +9,12 @@ 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 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7ca4bd8..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.23" + go-version: ">=1.24" secrets: inherit diff --git a/.github/workflows/static.yml b/.github/workflows/static.yml index a9c7c55..99bc1dc 100644 --- a/.github/workflows/static.yml +++ b/.github/workflows/static.yml @@ -6,7 +6,7 @@ on: push: branches: ["main"] paths: - - 'docs/**' + - "docs/**" # Allows you to run this workflow manually from the Actions tab workflow_dispatch: @@ -39,7 +39,7 @@ jobs: uses: actions/upload-pages-artifact@v3 with: # Upload entire repository - path: 'docs/' + path: "docs/" - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v4 diff --git a/cmd/kportal/main.go b/cmd/kportal/main.go index 4bd223a..4cc9b8b 100644 --- a/cmd/kportal/main.go +++ b/cmd/kportal/main.go @@ -295,9 +295,9 @@ func main() { // Interactive mode with bubbletea bubbleTeaUI = ui.NewBubbleTeaUI(func(id string, enable bool) { if enable { - manager.EnableForward(id) + _ = manager.EnableForward(id) } else { - manager.DisableForward(id) + _ = manager.DisableForward(id) } }, appVersion) diff --git a/internal/config/config.go b/internal/config/config.go index 75f5df1..5c8c7b5 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -296,6 +296,7 @@ func LoadConfig(path string) (*Config, error) { return nil, fmt.Errorf("config file too large: %d bytes (max %d)", fileInfo.Size(), maxConfigSize) } + // #nosec G304 -- path is validated in main.go (no system dirs, absolute path) data, err := os.ReadFile(path) if err != nil { return nil, fmt.Errorf("failed to read config file: %w", err) diff --git a/internal/config/mutator.go b/internal/config/mutator.go index b16d13c..b8f3f97 100644 --- a/internal/config/mutator.go +++ b/internal/config/mutator.go @@ -264,8 +264,8 @@ func (m *Mutator) writeAtomic(cfg *Config) error { // Atomic rename if err := os.Rename(tmpFile, m.configPath); err != nil { - // Clean up temp file on failure - os.Remove(tmpFile) + // Clean up temp file on failure - error ignored as we're already handling the rename error + _ = os.Remove(tmpFile) return fmt.Errorf("failed to rename temp file: %w", err) } diff --git a/internal/config/watcher.go b/internal/config/watcher.go index f45cab7..6a4c963 100644 --- a/internal/config/watcher.go +++ b/internal/config/watcher.go @@ -33,7 +33,7 @@ func NewWatcher(configPath string, callback ReloadCallback, verbose bool) (*Watc absPath, err := filepath.Abs(configPath) if err != nil { - watcher.Close() + _ = watcher.Close() return nil, fmt.Errorf("failed to resolve absolute path: %w", err) } @@ -41,7 +41,7 @@ func NewWatcher(configPath string, callback ReloadCallback, verbose bool) (*Watc // (many editors delete and recreate files on save) dir := filepath.Dir(absPath) if err := watcher.Add(dir); err != nil { - watcher.Close() + _ = watcher.Close() return nil, fmt.Errorf("failed to watch directory %s: %w", dir, err) } @@ -63,7 +63,7 @@ func (w *Watcher) Start() { // Stop stops watching the configuration file and waits for the watch goroutine to exit. func (w *Watcher) Stop() { close(w.done) - w.watcher.Close() + _ = w.watcher.Close() w.wg.Wait() // Wait for watch goroutine to exit } diff --git a/internal/converter/kftray.go b/internal/converter/kftray.go index 6d83bf7..9c35c94 100644 --- a/internal/converter/kftray.go +++ b/internal/converter/kftray.go @@ -25,6 +25,7 @@ type KFTrayConfig struct { // ConvertKFTrayToKPortal converts kftray JSON configuration to kportal YAML format func ConvertKFTrayToKPortal(inputFile, outputFile string) error { // Read kftray JSON config + // #nosec G304 -- inputFile is from command line argument for explicit conversion data, err := os.ReadFile(inputFile) if err != nil { return fmt.Errorf("failed to read input file: %w", err) @@ -57,6 +58,7 @@ func ConvertKFTrayToKPortal(inputFile, outputFile string) error { // GetConversionSummary returns statistics about the kftray configuration func GetConversionSummary(inputFile string) (map[string]map[string]int, int, error) { + // #nosec G304 -- inputFile is from command line argument for explicit conversion data, err := os.ReadFile(inputFile) if err != nil { return nil, 0, fmt.Errorf("failed to read input file: %w", err) diff --git a/internal/forward/portcheck.go b/internal/forward/portcheck.go index 7c690b6..1b154b1 100644 --- a/internal/forward/portcheck.go +++ b/internal/forward/portcheck.go @@ -77,6 +77,7 @@ func getProcessNameByPID(pid string) string { // getProcessNameByPIDWindows retrieves the process name for a given PID on Windows func getProcessNameByPIDWindows(pid string) string { + // #nosec G204 -- pid is validated by isValidPID() to contain only digits cmd := exec.Command("tasklist", "/FI", fmt.Sprintf("PID eq %s", pid), "/FO", "CSV", "/NH") output, err := cmd.Output() if err != nil { @@ -145,7 +146,7 @@ func (pc *PortChecker) isPortAvailable(port int) bool { if err != nil { return false } - listener.Close() + _ = listener.Close() return true } @@ -166,6 +167,7 @@ func (pc *PortChecker) getProcessUsingPort(port int) string { func (pc *PortChecker) getProcessUsingPortUnix(port int) string { // Use lsof to find the process // lsof -i :PORT -sTCP:LISTEN -t returns PIDs + // #nosec G204 -- port is an integer from config validation, not user input cmd := exec.Command("lsof", "-i", fmt.Sprintf(":%d", port), "-sTCP:LISTEN", "-t") output, err := cmd.Output() if err != nil { diff --git a/internal/healthcheck/checker.go b/internal/healthcheck/checker.go index 2bcc17d..55b8b29 100644 --- a/internal/healthcheck/checker.go +++ b/internal/healthcheck/checker.go @@ -409,7 +409,7 @@ func (c *Checker) checkTCPDial(port int) error { if err != nil { return err } - conn.Close() + _ = conn.Close() return nil } @@ -427,7 +427,7 @@ func (c *Checker) checkDataTransfer(port int) error { // Set a short read deadline to detect hung connections // We don't expect to receive data, but we want to verify the connection isn't hung - conn.SetReadDeadline(time.Now().Add(c.timeout)) + _ = conn.SetReadDeadline(time.Now().Add(c.timeout)) // Try to read a small amount of data // Most servers will either: diff --git a/internal/httplog/logger.go b/internal/httplog/logger.go index 253b423..7250c6d 100644 --- a/internal/httplog/logger.go +++ b/internal/httplog/logger.go @@ -51,6 +51,7 @@ func NewLogger(forwardID, logFile string, maxBodyLen int) (*Logger, error) { // Log entries are delivered via callbacks to the UI l.output = io.Discard } else { + // #nosec G304 -- logFile is from config validation, not arbitrary user input f, err := os.OpenFile(logFile, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600) if err != nil { return nil, err diff --git a/internal/httplog/proxy.go b/internal/httplog/proxy.go index 20874cf..66fddc2 100644 --- a/internal/httplog/proxy.go +++ b/internal/httplog/proxy.go @@ -85,12 +85,13 @@ func (p *Proxy) Start() error { ErrorHandler: func(w http.ResponseWriter, r *http.Request, err error) { p.logError(r, err) w.WriteHeader(http.StatusBadGateway) - w.Write([]byte("Proxy error: " + err.Error())) + _, _ = w.Write([]byte("Proxy error: " + err.Error())) }, } p.server = &http.Server{ - Handler: proxy, + Handler: proxy, + ReadHeaderTimeout: 10 * time.Second, } p.running = true @@ -122,8 +123,8 @@ func (p *Proxy) Stop() error { defer cancel() if err := p.server.Shutdown(ctx); err != nil { - // Force close - p.server.Close() + // Force close - error ignored as we're already shutting down + _ = p.server.Close() } if err := p.logger.Close(); err != nil { @@ -173,7 +174,7 @@ func (t *loggingTransport) RoundTrip(req *http.Request) (*http.Response, error) reqEntry.Headers = flattenHeaders(req.Header) } - t.proxy.logger.Log(reqEntry) + _ = t.proxy.logger.Log(reqEntry) // Make the request resp, err := t.transport.RoundTrip(req) @@ -207,7 +208,7 @@ func (t *loggingTransport) RoundTrip(req *http.Request) (*http.Response, error) respEntry.Headers = flattenHeaders(resp.Header) } - t.proxy.logger.Log(respEntry) + _ = t.proxy.logger.Log(respEntry) return resp, nil } @@ -269,7 +270,7 @@ func (p *Proxy) logError(req *http.Request, err error) { Path: req.URL.Path, Error: err.Error(), } - p.logger.Log(entry) + _ = p.logger.Log(entry) } // flattenHeaders converts http.Header to map[string]string diff --git a/internal/k8s/discovery.go b/internal/k8s/discovery.go index deac9c3..5a30677 100644 --- a/internal/k8s/discovery.go +++ b/internal/k8s/discovery.go @@ -356,6 +356,6 @@ func CheckPortAvailability(port int) (bool, string, error) { } // Port is available, close the listener - listener.Close() + _ = listener.Close() return true, "", nil } diff --git a/internal/retry/backoff.go b/internal/retry/backoff.go index ad3f1de..55fef52 100644 --- a/internal/retry/backoff.go +++ b/internal/retry/backoff.go @@ -24,7 +24,8 @@ type Backoff struct { func NewBackoff() *Backoff { return &Backoff{ attempt: 0, - rng: rand.New(rand.NewSource(time.Now().UnixNano())), + // #nosec G404 -- math/rand is appropriate for backoff jitter; cryptographic randomness not needed + rng: rand.New(rand.NewSource(time.Now().UnixNano())), } } diff --git a/internal/version/checker.go b/internal/version/checker.go index fa42633..10aea73 100644 --- a/internal/version/checker.go +++ b/internal/version/checker.go @@ -144,7 +144,7 @@ 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) }