Files
Nikhil ace9307878 feat: add browseros-cli self-updater (#605)
* feat: add browseros-cli self-updater

* fix: address review comments for 0327-cli_self_updater

* fix: address PR review comments for 0327-cli_self_updater

* fix: replace goreleaser with Makefile-based release build

Remove .goreleaser.yml (required Pro license for monorepo field) and
consolidate cross-compilation into `make release`. CI now uses the same
Makefile target, fixing a bug where POSTHOG_API_KEY was missing from
release ldflags.

* fix: address critical self-updater bugs from code review

- Fix SHA256 checksum mismatch: verify archive checksum before extraction
  instead of verifying extracted binary against archive hash (was always
  failing). Add VerifyChecksum() and integration test.
- Fix JSON field name mismatch: TypeScript was emitting camelCase
  (publishedAt, archiveFormat) but Go expected snake_case
  (published_at, archive_format). Manifest parsing was silently broken.
- Add decompression size limit (256 MB) to prevent zip/gzip bombs.
- Don't update LastCheckedAt on transient errors so retry happens on
  next CLI invocation instead of waiting 24h.
2026-03-27 14:52:54 -07:00

50 lines
1.1 KiB
Go

package update
import (
"bytes"
"crypto/sha256"
"encoding/hex"
"fmt"
"strings"
"github.com/minio/selfupdate"
)
func CheckPermissions(targetPath string) error {
options := selfupdate.Options{TargetPath: targetPath}
return options.CheckPermissions()
}
func VerifyChecksum(data []byte, expectedHex string) error {
expected, err := decodeChecksum(expectedHex)
if err != nil {
return err
}
actual := sha256.Sum256(data)
if !bytes.Equal(actual[:], expected) {
return fmt.Errorf(
"checksum mismatch: expected %s, got %s",
hex.EncodeToString(expected),
hex.EncodeToString(actual[:]),
)
}
return nil
}
func ApplyBinary(binary []byte, targetPath string) error {
options := selfupdate.Options{TargetPath: targetPath}
err := selfupdate.Apply(bytes.NewReader(binary), options)
if rollbackErr := selfupdate.RollbackError(err); rollbackErr != nil {
return fmt.Errorf("update failed and rollback failed: %w", rollbackErr)
}
return err
}
func decodeChecksum(checksumHex string) ([]byte, error) {
value := strings.TrimSpace(checksumHex)
if value == "" {
return nil, fmt.Errorf("missing checksum")
}
return hex.DecodeString(value)
}