fix(update): check file close errors (#1336)

Md Mushfiqur Rahim and FromSi created

## What?

Checks file close errors during the update download and extraction flow.

The updater now handles `Close()` errors after writing the downloaded
release asset and after extracting binaries from `.tar.gz` and `.zip`
archives. Cleanup closes in error paths are explicitly ignored so they
do not mask the original copy error.

## Why?

Closes #716.

Some write failures can surface only when a file is closed. Ignoring
`Close()` could let the updater continue with an incomplete or unflushed
asset or extracted binary.

---------

Co-authored-by: FromSi <fromsi665@gmail.com>

Change summary

main.go | 24 +++++++++++++++++-------
1 file changed, 17 insertions(+), 7 deletions(-)

Detailed changes

main.go 🔗

@@ -3667,10 +3667,13 @@ func runUpdateCLI() (err error) { //nolint:gocyclo
 		return fmt.Errorf("could not create temp file: %w", err)
 	}
 	_, err = io.Copy(outFile, respAsset.Body)
-	outFile.Close() //nolint:errcheck,gosec
 	if err != nil {
+		_ = outFile.Close()
 		return fmt.Errorf("could not write asset to disk: %w", err)
 	}
+	if err := outFile.Close(); err != nil {
+		return fmt.Errorf("could not finalize asset file: %w", err)
+	}
 
 	// Determine the expected binary name based on the OS.
 	binaryName := "matcha"
@@ -3707,10 +3710,12 @@ func runUpdateCLI() (err error) { //nolint:gocyclo
 					return fmt.Errorf("could not create binary file: %w", err)
 				}
 				if _, err := io.Copy(out, tr); err != nil { //nolint:gosec
-					out.Close() //nolint:errcheck,gosec
+					_ = out.Close()
 					return fmt.Errorf("could not extract binary: %w", err)
 				}
-				out.Close()                                     //nolint:errcheck,gosec
+				if err := out.Close(); err != nil {
+					return fmt.Errorf("could not finalize extracted binary: %w", err)
+				}
 				if err := os.Chmod(binPath, 0755); err != nil { //nolint:gosec
 					return fmt.Errorf("could not make binary executable: %w", err)
 				}
@@ -3737,12 +3742,17 @@ func runUpdateCLI() (err error) { //nolint:gocyclo
 					return fmt.Errorf("could not create binary file: %w", err)
 				}
 				if _, err := io.Copy(out, rc); err != nil { //nolint:gosec
-					out.Close() //nolint:errcheck,gosec
-					rc.Close()  //nolint:errcheck,gosec
+					_ = out.Close()
+					_ = rc.Close()
 					return fmt.Errorf("could not extract binary: %w", err)
 				}
-				out.Close()                                     //nolint:errcheck,gosec
-				rc.Close()                                      //nolint:errcheck,gosec
+				if err := out.Close(); err != nil {
+					_ = rc.Close()
+					return fmt.Errorf("could not finalize extracted binary: %w", err)
+				}
+				if err := rc.Close(); err != nil {
+					return fmt.Errorf("could not close zip entry: %w", err)
+				}
 				if err := os.Chmod(binPath, 0755); err != nil { //nolint:gosec
 					return fmt.Errorf("could not make binary executable: %w", err)
 				}