feat(agent-go): consume panel-hosted Reality keys (persist keyMaterial, backfill unused-provided keys)

This commit is contained in:
aaaamoooo
2026-10-20 07:20:59 +00:00
parent 483b891306
commit f2b7d8e181
4 changed files with 219 additions and 5 deletions
+71 -1
View File
@@ -92,7 +92,12 @@ func realityKey(keyID string) (realityKeyPair, error) {
}
type artifacts struct {
RealityPublicKey *string `json:"realityPublicKey,omitempty"`
RealityPublicKey *string `json:"realityPublicKey,omitempty"`
KeyMaterial map[string]realityKeyPair `json:"keyMaterial,omitempty"`
// used records every keypair resolved during materialize (never
// serialized); applyResourceLocked diffs it against the payload-provided
// keys to compute the backfill reported to the panel.
used map[string]realityKeyPair
}
func (a *artifacts) toMap() map[string]interface{} {
@@ -100,6 +105,67 @@ func (a *artifacts) toMap() map[string]interface{} {
if a.RealityPublicKey != nil {
out["realityPublicKey"] = *a.RealityPublicKey
}
if len(a.KeyMaterial) > 0 {
out["keyMaterial"] = a.KeyMaterial
}
return out
}
// persistKeyMaterial merges panel-provided keypairs into keys.json before a
// resource is materialized. The panel is the source of truth: a provided
// pair replaces a divergent local entry, so a node restored from the panel
// store converges back to the hosted keypair. keys.json stays 0600 (saveKeys).
func persistKeyMaterial(material map[string]realityKeyPair) error {
if len(material) == 0 {
return nil
}
keys, err := loadKeys()
if err != nil {
return err
}
changed := false
for keyID, pair := range material {
if pair.PrivateKey == "" || pair.PublicKey == "" {
continue
}
stored := pair
if raw, ok := keys[keyID]; ok {
var existing realityKeyPair
if err := json.Unmarshal(raw, &existing); err == nil {
if existing.PrivateKey == pair.PrivateKey && existing.PublicKey == pair.PublicKey {
continue
}
if stored.CreatedAt == "" {
stored.CreatedAt = existing.CreatedAt
}
}
}
if stored.CreatedAt == "" {
stored.CreatedAt = isoNow()
}
encoded, err := json.Marshal(stored)
if err != nil {
return err
}
keys[keyID] = encoded
changed = true
}
if !changed {
return nil
}
return saveKeys(keys)
}
// backfillKeyMaterial returns the keypairs this apply actually used that the
// panel did not provide in the payload. The panel stores them on job
// completion, so keys that predate panel hosting migrate into the store.
func backfillKeyMaterial(used, provided map[string]realityKeyPair) map[string]realityKeyPair {
out := map[string]realityKeyPair{}
for keyID, pair := range used {
if _, ok := provided[keyID]; !ok {
out[keyID] = pair
}
}
return out
}
@@ -141,6 +207,10 @@ func materialize(value interface{}, art *artifacts) (interface{}, error) {
}
pub := pair.PublicKey
art.RealityPublicKey = &pub
if art.used == nil {
art.used = map[string]realityKeyPair{}
}
art.used[match[1]] = pair
return pair.PrivateKey, nil
default:
return value, nil