A bundle carries what a cluster would download — llmgw's release with its signed checksums, every llama.cpp build per architecture with GitHub's checksums, model files pinned and checked against Hugging Face's — into a directory or a tar whose manifest sha256 is carried apart. Import checks everything, the release against the signing key, before anything is put in the mirror. With offline.mirror set, nodes install llama.cpp from the mirror against checksums the control plane holds and sends over the agent stream; releases default to the mirror for node add, ctl upgrade and agent upgrades. server init and the setup form install from a bundle. The Helm chart runs one control plane with SQLite on a claim or an external PostgreSQL, Secrets for the agent certificate and admin token, Services, Ingress and ServiceMonitor; deploy/container/Dockerfile builds its image. GPU nodes stay outside Kubernetes, as docs/kubernetes.md explains. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
162 lines
5.1 KiB
Go
162 lines
5.1 KiB
Go
package release
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
)
|
|
|
|
func releaseServer(t *testing.T, version, asset string, body []byte, sum string) *httptest.Server {
|
|
t.Helper()
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
switch r.URL.Path {
|
|
case "/" + version + "/checksums.txt":
|
|
_, _ = w.Write([]byte(sum + " " + asset + "\n"))
|
|
case "/" + version + "/" + asset:
|
|
_, _ = w.Write(body)
|
|
default:
|
|
http.NotFound(w, r)
|
|
}
|
|
}))
|
|
t.Cleanup(srv.Close)
|
|
return srv
|
|
}
|
|
|
|
// unsigned has this build trust no key for the test: the checksum alone.
|
|
func unsigned(t *testing.T) {
|
|
t.Helper()
|
|
was := trustedPub
|
|
trustedPub = ""
|
|
t.Setenv("LLMGW_RELEASE_KEY", "")
|
|
t.Cleanup(func() { trustedPub = was })
|
|
}
|
|
|
|
func TestABinaryIsReplacedOnlyWithWhatTheReleasePublished(t *testing.T) {
|
|
unsigned(t)
|
|
dir := t.TempDir()
|
|
target := filepath.Join(dir, "llmgw")
|
|
_ = os.WriteFile(target, []byte("old"), 0o755)
|
|
body := []byte("new binary")
|
|
sum := sha256.Sum256(body)
|
|
asset := AssetName("v1.2.3", "linux", "amd64")
|
|
|
|
srv := releaseServer(t, "v1.2.3", asset, body, hex.EncodeToString(sum[:]))
|
|
backup, err := Install(t.Context(), srv.Client(), srv.URL, "v1.2.3", "linux", "amd64", target)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if b, _ := os.ReadFile(target); string(b) != "new binary" {
|
|
t.Errorf("target holds %q", b)
|
|
}
|
|
if b, _ := os.ReadFile(backup); string(b) != "old" {
|
|
t.Errorf("the old binary was not kept: %q", b)
|
|
}
|
|
|
|
// A download that does not match its checksum changes nothing.
|
|
bad := releaseServer(t, "v1.2.4", AssetName("v1.2.4", "linux", "amd64"), []byte("tampered"),
|
|
hex.EncodeToString(sum[:]))
|
|
if _, err := Install(t.Context(), bad.Client(), bad.URL, "v1.2.4", "linux", "amd64", target); err == nil {
|
|
t.Fatal("a binary not matching its checksum was installed")
|
|
}
|
|
if b, _ := os.ReadFile(target); string(b) != "new binary" {
|
|
t.Errorf("a failed install touched the binary: %q", b)
|
|
}
|
|
if _, err := Install(t.Context(), nil, srv.URL, "../../x", "linux", "amd64", target); err == nil {
|
|
t.Error("a version that is not one was fetched")
|
|
}
|
|
}
|
|
|
|
func TestReleasesAreFetchedOverHTTPSOrFromThisMachine(t *testing.T) {
|
|
unsigned(t)
|
|
for base, ok := range map[string]bool{
|
|
"https://gitea.example/releases/download": true,
|
|
"http://127.0.0.1:8080/r": true,
|
|
"http://localhost/r": true,
|
|
"http://gitea.example/releases/download": false,
|
|
"http://10.0.0.5/r": false,
|
|
"ftp://x/r": false,
|
|
"not a url": false,
|
|
} {
|
|
if err := CheckBase(base); (err == nil) != ok {
|
|
t.Errorf("%s: %v", base, err)
|
|
}
|
|
}
|
|
if _, err := Install(t.Context(), nil, "http://gitea.example/r", "v1.2.3", "linux", "amd64", "/nonexistent"); err == nil {
|
|
t.Error("a release over plain http was installed")
|
|
}
|
|
}
|
|
|
|
func TestASignedReleaseMayComeOverPlainHTTPFromAnOfflineMirror(t *testing.T) {
|
|
pub, priv, err := GenerateKey()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
t.Setenv("LLMGW_RELEASE_KEY", pub)
|
|
if err := CheckBase("http://10.0.0.5:8081/_llmgw/releases"); err != nil {
|
|
t.Fatalf("a mirror's plain HTTP was refused with a signing key trusted: %v", err)
|
|
}
|
|
|
|
// And what comes over it is still held to the signature.
|
|
body := []byte("the release")
|
|
sum := sha256.Sum256(body)
|
|
asset := AssetName("v1.2.3", "linux", "amd64")
|
|
sums := []byte(hex.EncodeToString(sum[:]) + " " + asset + "\n")
|
|
sig, _ := Sign(priv, sums)
|
|
_, other, _ := GenerateKey()
|
|
forged, _ := Sign(other, sums)
|
|
for _, tc := range []struct {
|
|
sig string
|
|
ok bool
|
|
}{{sig, true}, {forged, false}, {"", false}} {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
switch r.URL.Path {
|
|
case "/v1.2.3/checksums.txt":
|
|
_, _ = w.Write(sums)
|
|
case "/v1.2.3/" + SignatureName:
|
|
if tc.sig == "" {
|
|
http.NotFound(w, r)
|
|
return
|
|
}
|
|
_, _ = w.Write([]byte(tc.sig))
|
|
case "/v1.2.3/" + asset:
|
|
_, _ = w.Write(body)
|
|
default:
|
|
http.NotFound(w, r)
|
|
}
|
|
}))
|
|
c, err := FetchChecksums(t.Context(), srv.Client(), srv.URL, "v1.2.3")
|
|
if (err == nil) != tc.ok {
|
|
t.Errorf("signature %q: %v", tc.sig, err)
|
|
}
|
|
if err == nil {
|
|
if got, _ := c.For(asset); got != hex.EncodeToString(sum[:]) {
|
|
t.Errorf("the checksum read is %s", got)
|
|
}
|
|
if err := c.Verify(); err != nil {
|
|
t.Errorf("kept checksums do not verify again: %v", err)
|
|
}
|
|
}
|
|
srv.Close()
|
|
}
|
|
}
|
|
|
|
func TestFetchGivesOnlyACheckedBinary(t *testing.T) {
|
|
unsigned(t)
|
|
body := []byte("for another machine")
|
|
sum := sha256.Sum256(body)
|
|
asset := AssetName("v1.2.3", "linux", "arm64")
|
|
srv := releaseServer(t, "v1.2.3", asset, body, hex.EncodeToString(sum[:]))
|
|
got, err := Fetch(t.Context(), srv.Client(), srv.URL, "v1.2.3", "linux", "arm64")
|
|
if err != nil || string(got) != string(body) {
|
|
t.Fatalf("%q %v", got, err)
|
|
}
|
|
bad := releaseServer(t, "v1.2.3", asset, []byte("swapped"), hex.EncodeToString(sum[:]))
|
|
if _, err := Fetch(t.Context(), bad.Client(), bad.URL, "v1.2.3", "linux", "arm64"); err == nil {
|
|
t.Error("a binary not matching its checksum was given")
|
|
}
|
|
}
|