feat(httpapi): harden control plane and speed up prefix refresh

Очередь job получила lease и fencing, телеметрия и прогресс deploy сохраняются, ревизия пишет manifest входов. Обновление префиксов не переписывает неизменённый снимок, большие наборы идут через COPY, а устаревшая ревизия не попадает в deploy. Бандл ноды кэшируется, prune и постановка job больше не держат горячий путь.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
DenozordecandCursor committed 2026-11-02 17:23:59 +07:00
1 parent 924f111e48
commit f8e0520817
197 files changed
+18655 -1416

No files matched your search

+92 -18
View File
@@ -11,44 +11,95 @@ import (
"encoding/json"
"fmt"
"io"
"path"
"strings"
)
// VerifiedContents is the result of verifying a downloaded bundle on evobgp-node.
// VerifiedContents contains only payloads covered by a verified signed manifest.
type VerifiedContents struct {
Manifest Manifest
Files map[string][]byte
}
// VerifyGzippedTar checks Ed25519 signature over manifest.json and SHA-256 of each file.
func VerifyGzippedTar(bundle []byte, pub ed25519.PublicKey) (*VerifiedContents, error) {
gr, err := gzip.NewReader(bytes.NewReader(bundle))
// VerifyGzippedTar verifies the unchanged signed manifest format with default limits.
func VerifyGzippedTar(raw []byte, pub ed25519.PublicKey) (*VerifiedContents, error) {
return VerifyGzippedTarWithLimits(raw, pub, Limits{})
}
// VerifyGzippedTarWithLimits verifies the signature and hashes under explicit
// compressed, expanded, per-entry and metadata budgets.
func VerifyGzippedTarWithLimits(raw []byte, pub ed25519.PublicKey, limits Limits) (*VerifiedContents, error) {
l, err := limits.Normalized()
if err != nil {
return nil, err
}
if int64(len(raw)) > l.MaxCompressedBytes {
return nil, ErrLimit
}
if len(pub) != ed25519.PublicKeySize {
return nil, fmt.Errorf("bundle: invalid public key size")
}
gr, err := gzip.NewReader(bytes.NewReader(raw))
if err != nil {
return nil, err
}
defer func() { _ = gr.Close() }()
var manifestRaw []byte
var sig []byte
files := make(map[string][]byte)
tr := tar.NewReader(gr)
decoded := &io.LimitedReader{R: gr, N: l.MaxExpandedBytes + 1}
tr := tar.NewReader(decoded)
var manifestRaw, sig []byte
files := map[string][]byte{}
seen := map[string]bool{}
count := 0
var logicalBytes int64
for {
hdr, err := tr.Next()
if decoded.N == 0 {
return nil, ErrLimit
}
if err == io.EOF {
break
}
if err != nil {
return nil, err
}
name := path.Clean(hdr.Name)
if strings.HasPrefix(name, "..") {
return nil, fmt.Errorf("bundle: illegal tar entry %q", hdr.Name)
count++
if count > l.MaxEntries {
return nil, ErrLimit
}
data, err := io.ReadAll(tr)
if err = validatePath(hdr.Name, l.MaxPathBytes); err != nil {
return nil, err
}
name := hdr.Name
folded := strings.ToLower(name)
if seen[folded] {
return nil, fmt.Errorf("bundle: duplicate tar entry %q", name)
}
seen[folded] = true
if hdr.Typeflag != tar.TypeReg && hdr.Typeflag != tar.TypeRegA {
return nil, fmt.Errorf("bundle: nonregular tar entry %q", name)
}
for key := range hdr.PAXRecords {
if strings.HasPrefix(key, "GNU.sparse.") {
return nil, fmt.Errorf("bundle: sparse entry %q is unsupported", name)
}
}
max := l.MaxFileBytes
if name == manifestName {
max = l.MaxManifestBytes
}
if name == sigFileName {
max = ed25519.SignatureSize
}
if hdr.Size < 0 || hdr.Size > max || hdr.Size >= decoded.N || hdr.Size > l.MaxExpandedBytes-logicalBytes {
return nil, ErrLimit
}
logicalBytes += hdr.Size
data, err := io.ReadAll(io.LimitReader(tr, max+1))
if err != nil {
return nil, err
}
if int64(len(data)) > max || decoded.N == 0 {
return nil, ErrLimit
}
switch name {
case manifestName:
manifestRaw = data
@@ -58,17 +109,36 @@ func VerifyGzippedTar(bundle []byte, pub ed25519.PublicKey) (*VerifiedContents,
files[name] = data
}
}
if len(manifestRaw) == 0 || len(sig) == 0 {
// tar EOF precedes the gzip trailer. Drain through the same byte budget so
// checksums, extra gzip members and trailing decompression are also bounded.
if _, err = io.Copy(io.Discard, decoded); err != nil {
return nil, err
}
if decoded.N == 0 {
return nil, ErrLimit
}
if len(manifestRaw) == 0 || len(sig) != ed25519.SignatureSize {
return nil, fmt.Errorf("bundle: missing manifest or signature")
}
if !ed25519.Verify(pub, manifestRaw, sig) {
return nil, fmt.Errorf("bundle: ed25519 signature mismatch")
}
var m Manifest
if err := json.Unmarshal(manifestRaw, &m); err != nil {
if err = json.Unmarshal(manifestRaw, &m); err != nil {
return nil, err
}
if len(m.Files) > l.MaxEntries-2 {
return nil, ErrLimit
}
listed := map[string]bool{}
for _, fe := range m.Files {
if err = validatePath(fe.Path, l.MaxPathBytes); err != nil {
return nil, err
}
if fe.Path == manifestName || fe.Path == sigFileName || listed[strings.ToLower(fe.Path)] {
return nil, fmt.Errorf("bundle: duplicate or reserved manifest path %q", fe.Path)
}
listed[strings.ToLower(fe.Path)] = true
body, ok := files[fe.Path]
if !ok {
return nil, fmt.Errorf("bundle: missing file %q", fe.Path)
@@ -78,10 +148,13 @@ func VerifyGzippedTar(bundle []byte, pub ed25519.PublicKey) (*VerifiedContents,
return nil, fmt.Errorf("bundle: checksum mismatch for %q", fe.Path)
}
}
if len(listed) != len(files) {
return nil, fmt.Errorf("bundle: payload is not covered by manifest")
}
return &VerifiedContents{Manifest: m, Files: files}, nil
}
// ParsePublicKeyHex decodes a 64-char hex Ed25519 public key (32 bytes).
// ParsePublicKeyHex decodes a 32-byte Ed25519 public key from hexadecimal.
func ParsePublicKeyHex(s string) (ed25519.PublicKey, error) {
s = strings.TrimSpace(strings.TrimPrefix(strings.TrimPrefix(s, "0x"), "0X"))
raw, err := hex.DecodeString(s)
@@ -94,7 +167,8 @@ func ParsePublicKeyHex(s string) (ed25519.PublicKey, error) {
return ed25519.PublicKey(raw), nil
}
// PublicKeyFromManifestBase64 uses the key embedded in the signed manifest (cross-check with expected pubkey optional).
// PublicKeyFromManifestBase64 decodes the manifest key. Callers must still trust
// an independently provisioned key when authenticating the bundle.
func PublicKeyFromManifestBase64(m *Manifest) (ed25519.PublicKey, error) {
if m.PublicKeyB64 == "" {
return nil, fmt.Errorf("bundle: manifest missing public_key_base64")