[mike@mwxm4]

This commit is contained in:
2026-08-12 17:03:43 +02:00
parent 4ad3d2e13d
commit 94f5ec969d
11 changed files with 847 additions and 209 deletions
+89 -25
View File
@@ -2,6 +2,9 @@
package main
import (
"context"
"crypto/sha256"
"encoding/hex"
"net/http"
"net/http/httptest"
"os"
@@ -142,65 +145,126 @@ func TestFileExists(t *testing.T) { // --------------------------------- must no
}
}
func TestGetchecksum(t *testing.T) { // ------------------------------------- checksums are read and validated
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/checksums.txt" {
http.NotFound(w, r)
return
}
w.Write([]byte("aabb gbld_1.0.0_linux_amd64\n" +
"0f0f gbld_1.0.0_windows_amd64.exe\n" +
"zzzz broken_sum\n"))
}))
defer srv.Close()
func TestUpdateFindSum(t *testing.T) { // ----------------------------------- checksums are read and validated
good := strings.Repeat("ab", 32) // 32 bytes, as a sha256 has
body := []byte(good + " gbld-linux-amd64\n" +
good + " *gbld-windows-amd64.exe\n" + // binary mode marks the name with '*'
"zzzz broken_sum\n")
client := &http.Client{Timeout: 5 * time.Second}
sum, err := getchecksum(client, srv.URL+"/checksums.txt", "gbld_1.0.0_linux_amd64")
sum, err := updateFindSum(body, "gbld-linux-amd64")
if err != nil {
t.Fatal(err)
}
if len(sum) != 2 || sum[0] != 0xaa || sum[1] != 0xbb {
if hex.EncodeToString(sum) != good {
t.Errorf("wrong checksum decoded: %x", sum)
}
if _, err := getchecksum(client, srv.URL+"/checksums.txt", "gbld_1.0.0_darwin_arm64"); err == nil {
if _, err := updateFindSum(body, "gbld-windows-amd64.exe"); err != nil {
t.Errorf("the '*' of binary mode belongs to the format, not to the name: %v", err)
}
if _, err := updateFindSum(body, "gbld-darwin-arm64"); err == nil {
t.Error("a missing entry must be an error - never update without a checksum")
}
if _, err := getchecksum(client, srv.URL+"/checksums.txt", "broken_sum"); err == nil {
if _, err := updateFindSum(body, "broken_sum"); err == nil {
t.Error("a malformed checksum must be an error")
}
if _, err := getchecksum(client, srv.URL+"/missing.txt", "gbld_1.0.0_linux_amd64"); err == nil {
t.Error("a missing checksums.txt must be an error")
if _, err := updateFindSum([]byte(strings.Repeat("ab", 16)+" gbld-linux-amd64\n"), "gbld-linux-amd64"); err == nil {
t.Error("a hash of the wrong length must be an error")
}
}
func TestDoupdateRejectsWrongChecksum(t *testing.T) { // ------------- a manipulated download is never applied
func TestUpdateChecksum(t *testing.T) { // ------------------------- the checksum comes out of the release itself
want := strings.Repeat("cd", 32)
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("this is not the binary you asked for"))
w.Write([]byte(want + " gbld-linux-amd64\n"))
}))
defer srv.Close()
err := doupdate(&http.Client{Timeout: 5 * time.Second}, srv.URL+"/gbld", []byte{0xde, 0xad, 0xbe, 0xef})
rel := updateRelease{TagName: "v1.2.3", Assets: []updateAsset{
{Name: "gbld-linux-amd64", URL: srv.URL + "/gbld-linux-amd64"},
{Name: updateChecksums, URL: srv.URL + "/" + updateChecksums},
}}
sum, err := selfUpdate.checksum(rel, "gbld-linux-amd64")
if err != nil {
t.Fatal(err)
}
if hex.EncodeToString(sum) != want {
t.Errorf("wrong checksum: %x", sum)
}
bare := updateRelease{TagName: "v1.2.3", Assets: rel.Assets[:1]} // no checksums.txt published
if _, err := selfUpdate.checksum(bare, "gbld-linux-amd64"); err == nil {
t.Error("a release without checksums must be refused")
}
}
func TestUpdateDownloadRejectsWrongChecksum(t *testing.T) { // ------ a manipulated download is never installed
body := []byte("this is not the binary you asked for")
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write(body)
}))
defer srv.Close()
dir := t.TempDir()
exe := filepath.Join(dir, "gbld")
a := &updateAsset{Name: "gbld-linux-amd64", Size: int64(len(body)), URL: srv.URL + "/gbld-linux-amd64"}
_, err := selfUpdate.download(a, exe, 0755, []byte{0xde, 0xad, 0xbe, 0xef})
if err == nil {
t.Fatal("update with a wrong checksum was accepted")
t.Fatal("a download with a wrong checksum was accepted")
}
if !strings.Contains(strings.ToLower(err.Error()), "checksum") {
t.Errorf("expected a checksum error, got: %v", err)
}
left, _ := filepath.Glob(filepath.Join(dir, "*"))
if len(left) != 0 {
t.Errorf("the rejected download was left behind: %v", left)
}
sum := sha256.Sum256(body) // the same bytes, now with the checksum that fits
tmp, err := selfUpdate.download(a, exe, 0755, sum[:])
if err != nil {
t.Fatalf("a matching checksum was refused: %v", err)
}
os.Remove(tmp)
}
func TestFetchStatus(t *testing.T) { // -------------------------------------- http errors must not be swallowed
func TestUpdateGetStatus(t *testing.T) { // ---------------------------------- http errors must not be swallowed
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
http.Error(w, "nope", http.StatusInternalServerError)
}))
defer srv.Close()
if _, err := fetch(&http.Client{Timeout: 5 * time.Second}, srv.URL, 1<<20); err == nil {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if _, err := updateGet(ctx, srv.URL); err == nil {
t.Error("http 500 was reported as success")
}
}
func TestUpdateCompare(t *testing.T) { // ------------------- versions are numbers, not strings: 1.21.10 > 1.21.9
for _, c := range []struct {
a, b string
want int
}{
{"1.21.10", "1.21.9", 1},
{"v1.21.0", "1.21.0", 0},
{"1.21", "1.21.0", 0},
{"1.21.0-rc1", "1.21.0", -1}, // not finished yet
{"1.9.0", "1.10.0", -1},
} {
if got := updateCompare(c.a, c.b); got != c.want {
t.Errorf("updateCompare(%q,%q) = %d, want %d", c.a, c.b, got, c.want)
}
if got := updateCompare(c.b, c.a); got != -c.want {
t.Errorf("updateCompare(%q,%q) = %d, want %d", c.b, c.a, got, -c.want)
}
}
}
func TestToolbox(t *testing.T) { // ------------------------------------------------ toolbox edge cases
if got := Shortstr("abcdef", 4); got != "ab.." {
t.Errorf("Shortstr: got %q", got)