From c912bcab6e739a09c56e415eb07115c5415e976a Mon Sep 17 00:00:00 2001 From: jochen Date: Wed, 28 Oct 2026 10:01:38 +0100 Subject: [PATCH] The node agent finds a drifted own secret's running file by its id as the node runs it, its module's name first (issue 1126, cause C4; review round 2) Pins mesh-sdk 3028c7e (delivery.OwnNeedName). The fixtures carry the id shape captured from novox's shadow answer. --- go.mod | 2 +- go.sum | 4 ++-- internal/ownresync/ownresync.go | 8 ++++++-- internal/ownresync/ownresync_test.go | 22 ++++++++++++---------- 4 files changed, 21 insertions(+), 15 deletions(-) diff --git a/go.mod b/go.mod index 051a57f..7f2612f 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/novox/mesh-host go 1.26.0 require ( - git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261028084903-1062b33d32c5 + git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261028090029-3028c7ec4ed2 github.com/nats-io/nats-server/v2 v2.11.17 github.com/nats-io/nats.go v1.54.0 golang.org/x/crypto v0.57.0 diff --git a/go.sum b/go.sum index 048d56b..a460d12 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261028084903-1062b33d32c5 h1:FRNW0kjmm2SYVbEAeG9IsMWALE/qRKt8IMKNnMn2p90= -git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261028084903-1062b33d32c5/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261028090029-3028c7ec4ed2 h1:eSwObLdxs3jxPrlcwdaMo9hzIDTUz2ogWw8cjX8To7I= +git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261028090029-3028c7ec4ed2/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0= github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI= github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo= diff --git a/internal/ownresync/ownresync.go b/internal/ownresync/ownresync.go index c8edd6f..02599a3 100644 --- a/internal/ownresync/ownresync.go +++ b/internal/ownresync/ownresync.go @@ -223,13 +223,17 @@ func (r *Resync) running(ctx context.Context, o delivery.OwnValueDiffers) (strin return "", fmt.Sprintf("what runs (%s, %s) is not yet the composition its want names (%s)", have.Composed, have.Phase, want.Composed) } - id := catalogue.NeedID(o.Name) + // On a node the resource's id carries its module's name (`only-office.needs-jwt`); delivery.OwnNeedName reads it. + id := o.Module + "." + catalogue.NeedID(o.Name) for _, res := range comp.Resources { var body struct { ID string `json:"id"` Sealed any `json:"sealed"` } - if json.Unmarshal(res, &body) != nil || body.ID != id { + if json.Unmarshal(res, &body) != nil { + continue + } + if name, own := delivery.OwnNeedName(o.Module, body.ID); !own || name != o.Name { continue } if s, ok := body.Sealed.(string); ok && s != "" { diff --git a/internal/ownresync/ownresync_test.go b/internal/ownresync/ownresync_test.go index fe46aa0..2ec1235 100644 --- a/internal/ownresync/ownresync_test.go +++ b/internal/ownresync/ownresync_test.go @@ -21,9 +21,9 @@ func TestTheNodeHandsTheVaultWhatRunsOfADriftedOwnSecret(t *testing.T) { fp := "src2:" + strings.Repeat("b", 64) sum := sha256.Sum256([]byte(running)) answers := map[string]delivery.CandidateAnswer{"g": {Head: "h", Verdict: delivery.CandidateDiffers, - Differs: []delivery.ModuleDiffers{{Module: "onlyoffice", Why: "the resource differs", Bodies: []delivery.ResourceBodies{ - {ID: "needs-jwt", Composed: `{"sealed":"` + delivery.MaskedAnotherValue + `"}`, Running: `{"sealed":"` + delivery.MaskedAnotherValue + `"}`}, - {ID: "needs-salt", Composed: `{"sealed":""}`}}}}}} + Differs: []delivery.ModuleDiffers{{Module: "only-office", Why: "the resource differs", Bodies: []delivery.ResourceBodies{ + {ID: "only-office.needs-jwt", Composed: `{"sealed":"` + delivery.MaskedAnotherValue + `"}`, Running: `{"sealed":"` + delivery.MaskedAnotherValue + `"}`}, + {ID: "only-office.needs-salt", Composed: `{"sealed":""}`}}}}}} for name, row := range map[string]struct { composes string runs string // the have's composition digest @@ -43,14 +43,16 @@ func TestTheNodeHandsTheVaultWhatRunsOfADriftedOwnSecret(t *testing.T) { have, _ := delivery.EncodeHave(delivery.Have{FP: fp, Composed: row.runs, Phase: delivery.PhaseRunning, Health: delivery.HealthOK}) r := New(Env{Node: "novox", Composes: func() string { return row.composes }, Running: func() []delivery.Composed { - return []delivery.Composed{{Node: "novox", Module: "onlyoffice", FP: fp, Resources: []json.RawMessage{ - json.RawMessage(`{"id":"needs-jwt","type":"file","path":"/etc/jwt","sealed":"box-of-the-running-value"}`)}}} + return []delivery.Composed{{Node: "novox", Module: "only-office", FP: fp, Resources: []json.RawMessage{ + // As novox runs it (its shadow answer, 2026-10-28): the id carries the module's name. + json.RawMessage(`{"id":"only-office.needs-jwt","module":"only-office","type":"file",` + + `"path":"/var/lib/only-office/jwt.secret","sealed":"box-of-the-running-value"}`)}}} }, Get: func(_ context.Context, bucket, key string) ([]byte, error) { switch { - case bucket == delivery.AssignerWantsBucket && key == "want.novox.onlyoffice": + case bucket == delivery.AssignerWantsBucket && key == "want.novox.only-office": return want, nil - case bucket == delivery.HaveBucket && key == "novox.onlyoffice": + case bucket == delivery.HaveBucket && key == "novox.only-office": return have, nil } return nil, nil @@ -71,15 +73,15 @@ func TestTheNodeHandsTheVaultWhatRunsOfADriftedOwnSecret(t *testing.T) { return nil, errors.New(row.refuse) } if args["call"] == nil { - if args["module"] != "onlyoffice" || args["name"] != "jwt" || args["node"] != nil { + if args["module"] != "only-office" || args["name"] != "jwt" || args["node"] != nil { t.Errorf("%s: the first step names %v", name, args) } - return json.RawMessage(`{"call":"c1","seal_to":"key","secret":"own/novox/onlyoffice/jwt"}`), nil + return json.RawMessage(`{"call":"c1","seal_to":"key","secret":"own/novox/only-office/jwt"}`), nil } if args["sealed"] != "key("+running+")" { t.Errorf("%s: handed %v, not what runs sealed to the call's key", name, args["sealed"]) } - return json.RawMessage(`{"secret":"own/novox/onlyoffice/jwt","from_generation":1,"to_generation":2,` + + return json.RawMessage(`{"secret":"own/novox/only-office/jwt","from_generation":1,"to_generation":2,` + `"fingerprint":"sha256:` + hex.EncodeToString(sum[:]) + `"}`), nil }, Say: func(s string) { said = append(said, s) }})