bastion 0.53.2
ci / personal-data (push) Successful in 5s
ci / test (push) Successful in 3m4s
ci / fuzz (push) Successful in 3m45s

This commit is contained in:
Privatae
2026-10-20 04:42:14 +00:00
commit e4c9b69b46
471 changed files with 159794 additions and 0 deletions
+85
View File
@@ -0,0 +1,85 @@
package main
// Verified releases: the self-updater checks the binary's SHA-256 against the
// signed manifest before anything is swapped. Driven through maybeSelfUpdate
// with a signed manifest served on loopback; a digest that does not match the
// downloaded bytes must leave the running binary exactly as it was.
import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"net/http"
"net/http/httptest"
"os"
"runtime"
"sync/atomic"
"testing"
)
func TestADigestMismatchNeverSwapsTheBinary(t *testing.T) {
uiTestConfigDir(t) // a local, unanchored box: the directive gate passes
freshVersionState(t)
t.Cleanup(func() { clearDirectiveRefusal("self-update") })
clientVersion = "0.1.0"
self, err := resolvedSelf()
if err != nil {
t.Fatal(err)
}
before, err := os.ReadFile(self)
if err != nil {
t.Fatal(err)
}
payload := []byte("not the bastion")
right := sha256.Sum256(payload)
other := sha256.Sum256([]byte("some other build"))
cases := []struct{ name, digest string }{
{"another build's digest", hex.EncodeToString(other[:])},
{"no digest", ""},
{"a truncated digest", hex.EncodeToString(right[:])[:63]},
{"half the digest", hex.EncodeToString(right[:16])},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
var downloads atomic.Int64
mux := http.NewServeMux()
var srv *httptest.Server
mux.HandleFunc("/version.json", func(w http.ResponseWriter, r *http.Request) {
key := runtime.GOOS + "-" + runtime.GOARCH
if runtime.GOOS == "windows" {
key += ".exe"
}
_ = json.NewEncoder(w).Encode(map[string]any{
"version": "0.2.0",
"binaries": map[string]any{key: map[string]any{"url": srv.URL + "/dl", "sha256": c.digest}},
})
})
mux.HandleFunc("/dl", func(w http.ResponseWriter, r *http.Request) {
downloads.Add(1)
_, _ = w.Write(payload)
})
srv = httptest.NewServer(signedStub(releaseKindBastion, mux))
defer srv.Close()
manifestURL = srv.URL + "/version.json"
// A swap would exit this process; returning at all is the first half
// of the assertion.
maybeSelfUpdate("h.host.privatae.ai", "", []byte(`{"update":{"version":"0.2.0"}}`))
if downloads.Load() != 1 {
t.Fatalf("the update must get as far as the download for this to test the digest (%d downloads)", downloads.Load())
}
after, err := os.ReadFile(self)
if err != nil {
t.Fatal(err)
}
if sha256.Sum256(after) != sha256.Sum256(before) {
t.Fatal("the running binary changed after a digest mismatch")
}
if _, err := os.Stat(self + ".old"); err == nil {
t.Fatal("the running binary was moved aside after a digest mismatch")
}
})
}
}