From ba7f43fa418a50ea139526b4424dbf43fefd4cd6 Mon Sep 17 00:00:00 2001 From: wydrox <79707825+wydrox@users.noreply.github.com> Date: Mon, 20 Apr 2026 18:52:34 +0200 Subject: [PATCH] Wrap bare error returns in login package Add fmt.Errorf("context: %w", err) wrapping around exec/file-io/HTTP bare `return err` paths in copyFile, copyBrowserProfileSnapshot, and remoteDebugGetJSON so error traces identify the failing operation while remaining compatible with errors.Is/As. Walk-callback error bubble-ups, already-wrapped error passthroughs, and chromedp ActionFunc returns are left unwrapped per idiomatic Go. Audit notes: - No %v error wrapping was found in this package (spec called for %v -> %w conversion; it is a no-op here). - All errors.New calls use static strings (no dynamic context); left untouched per spec. - Add errors_test.go asserting errNoRemoteDebugEndpoint remains errors.Is-compatible when wrapped. --- internal/login/errors_test.go | 14 ++++++++++++++ internal/login/login.go | 14 +++++++------- internal/login/remote_debug.go | 2 +- 3 files changed, 22 insertions(+), 8 deletions(-) create mode 100644 internal/login/errors_test.go diff --git a/internal/login/errors_test.go b/internal/login/errors_test.go new file mode 100644 index 0000000..851489c --- /dev/null +++ b/internal/login/errors_test.go @@ -0,0 +1,14 @@ +package login + +import ( + "errors" + "fmt" + "testing" +) + +func TestNoRemoteDebugEndpointIsWrappable(t *testing.T) { + wrapped := fmt.Errorf("firstAvailableRemoteDebugEndpoint: %w", errNoRemoteDebugEndpoint) + if !errors.Is(wrapped, errNoRemoteDebugEndpoint) { + t.Fatalf("errors.Is should report wrapped error as errNoRemoteDebugEndpoint, got false") + } +} diff --git a/internal/login/login.go b/internal/login/login.go index 58219bc..b44883a 100644 --- a/internal/login/login.go +++ b/internal/login/login.go @@ -496,13 +496,13 @@ func ensureProfileExists(userDataDir, profileDirectory string) error { func copyBrowserProfileSnapshot(srcUserData, dstUserData, profileDirectory string) error { if err := os.MkdirAll(dstUserData, 0o700); err != nil { - return err + return fmt.Errorf("create snapshot user data dir: %w", err) } localStateSrc := filepath.Join(srcUserData, "Local State") localStateDst := filepath.Join(dstUserData, "Local State") if _, err := os.Stat(localStateSrc); err == nil { if err := copyFile(localStateSrc, localStateDst); err != nil { - return err + return fmt.Errorf("copy browser Local State: %w", err) } } srcProfile := filepath.Join(srcUserData, profileDirectory) @@ -557,23 +557,23 @@ func copyDirFiltered(src, dst string, skip func(rel string, d fs.DirEntry) bool) func copyFile(src, dst string) error { in, err := os.Open(src) if err != nil { - return err + return fmt.Errorf("open source file %s: %w", src, err) } defer func() { _ = in.Close() }() info, err := in.Stat() if err != nil { - return err + return fmt.Errorf("stat source file %s: %w", src, err) } if err := os.MkdirAll(filepath.Dir(dst), 0o700); err != nil { - return err + return fmt.Errorf("create destination dir for %s: %w", dst, err) } out, err := os.OpenFile(dst, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, info.Mode()) if err != nil { - return err + return fmt.Errorf("create destination file %s: %w", dst, err) } defer func() { _ = out.Close() }() if _, err := io.Copy(out, in); err != nil { - return err + return fmt.Errorf("copy file contents to %s: %w", dst, err) } return out.Chmod(info.Mode()) } diff --git a/internal/login/remote_debug.go b/internal/login/remote_debug.go index 4ab43ee..9aef477 100644 --- a/internal/login/remote_debug.go +++ b/internal/login/remote_debug.go @@ -216,7 +216,7 @@ func remoteDebugGetJSON(rawURL string, dest any) error { client := &http.Client{Timeout: 2 * time.Second} resp, err := client.Get(rawURL) if err != nil { - return err + return fmt.Errorf("GET %s: %w", rawURL, err) } defer func() { _ = resp.Body.Close() }() if resp.StatusCode < 200 || resp.StatusCode >= 300 {