From 8520a4c09960a03b6f8b3dd16b7d4138d4be5ae4 Mon Sep 17 00:00:00 2001 From: jochen Date: Wed, 28 Oct 2026 12:22:37 +0100 Subject: [PATCH] Only a file's secrets are split entry by entry when masked and named: a vault box under vault-sealed is one masked word and one path, judged whole by what it opens to (issue 1126, C1; review of seed-same-3, round 1) --- go/delivery/answer_paths.go | 5 +++-- go/delivery/composed_compare.go | 16 ++++++++-------- go/delivery/placement_test.go | 17 +++++++++++++++++ 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/go/delivery/answer_paths.go b/go/delivery/answer_paths.go index bee6368..da4cb42 100644 --- a/go/delivery/answer_paths.go +++ b/go/delivery/answer_paths.go @@ -86,10 +86,11 @@ func walkDiffering(a, b any, at string, out *[]string) { case !inA || !inB: *out = append(*out, join(at, k)) case secretKey(k): - // A map of secrets (a file's, by name) is named entry by entry, each entry never entered. + // A file's secrets (SecretsField) are named entry by entry, each entry never entered; any other + // object under a secret key, a vault box included, is one path. sx, isSX := x.(map[string]any) sy, isSY := y.(map[string]any) - if !isSX || !isSY { + if k != SecretsField || !isSX || !isSY { if !sameAny(x, y) { *out = append(*out, join(at, k)) } diff --git a/go/delivery/composed_compare.go b/go/delivery/composed_compare.go index 47c7279..3ce208d 100644 --- a/go/delivery/composed_compare.go +++ b/go/delivery/composed_compare.go @@ -265,7 +265,7 @@ func maskBoth(a, b any, sameValue func(a, b string) (bool, bool)) (any, any) { va, inA := ma[k] vb, inB := mb[k] if secretKey(k) { - x, y := maskAll(va, vb, inA && inB, sameValue) + x, y := maskAll(k, va, vb, inA && inB, sameValue) if inA { outA[k] = x } @@ -328,24 +328,24 @@ func maskBoth(a, b any, sameValue func(a, b string) (bool, bool)) (any, any) { return a, b } -// maskAll is a value under a key a secret could be under, masked: a map entry by entry (a file's secrets, each its own -// sealed value: "another seal of the same value" or "another value" per secret, issue 1126, C1), its names shown and -// every value under it masked; anything else as one word (maskWord). -func maskAll(a, b any, both bool, sameValue func(a, b string) (bool, bool)) (any, any) { +// maskAll is a value under a key a secret could be under, masked as one word (maskWord); a file's secrets +// (SecretsField) alone entry by entry, each its own sealed value: "another seal of the same value" or "another value" +// per secret, its name shown (issue 1126, C1). Any other object, a vault box included, is one word, judged whole. +func maskAll(key string, a, b any, both bool, sameValue func(a, b string) (bool, bool)) (any, any) { ma, isA := a.(map[string]any) mb, isB := b.(map[string]any) - if !isA && !isB { + if key != SecretsField || (!isA && !isB) { w := maskWord(a, b, both, sameValue) return w, w } outA, outB := map[string]any{}, map[string]any{} for k, va := range ma { vb, inB := mb[k] - outA[k], _ = maskAll(va, vb, isB && inB, sameValue) + outA[k] = maskWord(va, vb, isB && inB, sameValue) } for k, vb := range mb { va, inA := ma[k] - _, outB[k] = maskAll(va, vb, isA && inA, sameValue) + outB[k] = maskWord(va, vb, isA && inA, sameValue) } // A map on one side and another value on the other: the other is one word. var ra, rb any = outA, outB diff --git a/go/delivery/placement_test.go b/go/delivery/placement_test.go index 5ffda73..c672877 100644 --- a/go/delivery/placement_test.go +++ b/go/delivery/placement_test.go @@ -365,6 +365,23 @@ func TestPlacement(t *testing.T) { }); !strings.Contains(c, `"postgres-database":""`) || !strings.Contains(c, `"secret-key":""`) { t.Errorf("each secret is not masked by what it opens to: %s", c) } + // Only a file's secrets are split by entry: a vault box (an object under `vault-sealed`) is one masked word and one + // path, judged whole by what it opens to (rev-seed-same-3, round 1). + box := func(ct string) json.RawMessage { + return json.RawMessage(`{"id":"core-box","type":"file","module":"nats","path":"/etc/core","mode":"0600","vault-sealed":{"v":1,"eph":"e-` + + ct + `","ct":"` + ct + `"}}`) + } + vault := CompareComposedWith(map[string]Composed{"k": comp(box("c1"))}, []Composed{comp(box("c2"))}, + func(a, b string) (bool, bool) { + return false, strings.Contains(a, `"ct":"c1"`) && strings.Contains(b, `"ct":"c2"`) + }) + if len(vault.Differs) != 1 || len(vault.Differs[0].Bodies) != 1 { + t.Fatalf("a box of another value is not shown: %+v", vault) + } + if body := vault.Differs[0].Bodies[0]; !slices.Equal(body.Paths, []string{"vault-sealed"}) || + !strings.Contains(body.Composed, `"vault-sealed":""`) || strings.Contains(body.Composed+body.Running, "c1") { + t.Errorf("a vault box shown as %+v", body) + } // Issue 1126, T1: the paths are found on the whole bodies, before they are cut; JSON in a string is walked into, a // key a secret could be under is named and never shown. long := strings.Repeat("x", MaxBody)