From 3215e5eeb92083d2f0266b92b7d6f0f5ddcb83b4 Mon Sep 17 00:00:00 2001 From: jochen Date: Wed, 11 Nov 2026 22:08:33 +0100 Subject: [PATCH] G findings: distribution and gitea's package registry delete their old finding keys once at start Builds: design 47 G A-31, A-14, A-22 Claude-Session: https://claude.ai/code/session_01JG73KEq4zoDfM9WtYpcQgZ --- .../cmd/distribution-tools/main.go | 4 ++ modules/distribution/cmd/distribution/main.go | 4 ++ .../distribution/internal/holder/findings.go | 26 +++++++++++ .../internal/holder/findings_test.go | 44 +++++++++++++++++++ .../gitea/cmd/package-registry/findings.go | 26 +++++++++++ .../cmd/package-registry/findings_test.go | 44 +++++++++++++++++++ modules/gitea/cmd/package-registry/main.go | 4 ++ 7 files changed, 152 insertions(+) create mode 100644 modules/distribution/internal/holder/findings_test.go create mode 100644 modules/gitea/cmd/package-registry/findings_test.go diff --git a/modules/distribution/cmd/distribution-tools/main.go b/modules/distribution/cmd/distribution-tools/main.go index f99403064..e3964a8c4 100644 --- a/modules/distribution/cmd/distribution-tools/main.go +++ b/modules/distribution/cmd/distribution-tools/main.go @@ -517,6 +517,10 @@ func main() { // the runtime answers the writer's subscription only once Serve has its channel go func() { <-stdio.Served() + // the keys of the older form end in no kind the writer owns, so it does not clear them (A-31) + if err := holder.DeleteOldFindings(stdio.State("findings"), holder.Self, holder.TransferFindingKinds); err != nil { + logf("the old findings are not deleted: %v", err) + } if err := w.Start(context.Background()); err != nil { logf("%v", err) os.Exit(1) diff --git a/modules/distribution/cmd/distribution/main.go b/modules/distribution/cmd/distribution/main.go index 42e2aabc8..7fb838063 100644 --- a/modules/distribution/cmd/distribution/main.go +++ b/modules/distribution/cmd/distribution/main.go @@ -74,6 +74,10 @@ func run(ctx context.Context, getenv func(string) string) error { return err } findings.Writer = w + // the keys of the older form end in no kind the writer owns, so it does not clear them (A-31) + if err := holder.DeleteOldFindings(calls.State("findings"), holder.Self, holder.DriverFindingKinds); err != nil { + logger.Printf("the old findings are not deleted: %v", err) + } if err := w.Start(ctx); err != nil { return err } diff --git a/modules/distribution/internal/holder/findings.go b/modules/distribution/internal/holder/findings.go index b99472d9b..6a4e51684 100644 --- a/modules/distribution/internal/holder/findings.go +++ b/modules/distribution/internal/holder/findings.go @@ -2,6 +2,7 @@ package holder import ( "context" + "strings" "sync" "time" @@ -75,3 +76,28 @@ func (k *Findings) Observed(context.Context) (views.Observed[meshconditions.Find } return out, nil } + +// DeleteOldFindings deletes, once at a module's start, the findings the keys of an older form hold (design 47 G A-31): the form +// `seat.._`, whose kind is no kind the writer owns in its key, so the writer's own first statement does not +// clear it. Only a key of one of kinds is deleted; the keys of the writer's form (`seat...`) are left. +func DeleteOldFindings(state views.FindingState, seat string, kinds []string) error { + keys, err := state.Keys() + if err != nil { + return err + } + for _, k := range keys { + rest, ok := strings.CutPrefix(k, "seat."+seat+".") + if !ok { + continue + } + for _, kind := range kinds { + if strings.HasPrefix(rest, kind+"_") { + if err := state.Delete(k); err != nil { + return err + } + break + } + } + } + return nil +} diff --git a/modules/distribution/internal/holder/findings_test.go b/modules/distribution/internal/holder/findings_test.go new file mode 100644 index 000000000..677910d1b --- /dev/null +++ b/modules/distribution/internal/holder/findings_test.go @@ -0,0 +1,44 @@ +package holder + +import ( + "sort" + "strings" + "testing" + + stdio "git.novox.be/novox/mesh-sdk/go" +) + +// A-31: the keys of the older form (`seat.._`) are deleted once; a key of the writer's form, another seat's +// and another kind's stay. +func TestTheOldFindingKeysAreDeletedOnce(t *testing.T) { + state := &oldKeysState{keys: map[string]bool{}} + for _, k := range []string{ + "seat.distribution.publish-refused_write", "seat.distribution.publish-refused_a_b_c", + "seat.distribution.sub.publish-refused", "seat.other.publish-refused_write", "seat.distribution.unrelated_write"} { + state.keys[k] = true + } + if err := DeleteOldFindings(state, "distribution", []string{"publish-refused", "incoming-full"}); err != nil { + t.Fatal(err) + } + var left []string + for k := range state.keys { + left = append(left, k) + } + sort.Strings(left) + if got, want := strings.Join(left, " "), "seat.distribution.sub.publish-refused seat.distribution.unrelated_write seat.other.publish-refused_write"; got != want { + t.Errorf("left %s, want %s", got, want) + } +} + +type oldKeysState struct{ keys map[string]bool } + +func (s *oldKeysState) Get(string) (*stdio.StateEntry, error) { return nil, nil } +func (s *oldKeysState) Put(string, any) (uint64, error) { return 0, nil } +func (s *oldKeysState) Delete(k string) error { delete(s.keys, k); return nil } +func (s *oldKeysState) Keys() ([]string, error) { + var out []string + for k := range s.keys { + out = append(out, k) + } + return out, nil +} diff --git a/modules/gitea/cmd/package-registry/findings.go b/modules/gitea/cmd/package-registry/findings.go index 544e699f1..b9ae01044 100644 --- a/modules/gitea/cmd/package-registry/findings.go +++ b/modules/gitea/cmd/package-registry/findings.go @@ -2,6 +2,7 @@ package main import ( "context" + "strings" "sync" "time" @@ -74,3 +75,28 @@ func (k *Findings) Observed(context.Context) (views.Observed[meshconditions.Find } return out, nil } + +// DeleteOldFindings deletes, once at a module's start, the findings the keys of an older form hold (design 47 G A-31): the form +// `seat.._`, whose kind is no kind the writer owns in its key, so the writer's own first statement does not +// clear it. Only a key of one of kinds is deleted; the keys of the writer's form (`seat...`) are left. +func DeleteOldFindings(state views.FindingState, seat string, kinds []string) error { + keys, err := state.Keys() + if err != nil { + return err + } + for _, k := range keys { + rest, ok := strings.CutPrefix(k, "seat."+seat+".") + if !ok { + continue + } + for _, kind := range kinds { + if strings.HasPrefix(rest, kind+"_") { + if err := state.Delete(k); err != nil { + return err + } + break + } + } + } + return nil +} diff --git a/modules/gitea/cmd/package-registry/findings_test.go b/modules/gitea/cmd/package-registry/findings_test.go new file mode 100644 index 000000000..df05ad213 --- /dev/null +++ b/modules/gitea/cmd/package-registry/findings_test.go @@ -0,0 +1,44 @@ +package main + +import ( + "sort" + "strings" + "testing" + + stdio "git.novox.be/novox/mesh-sdk/go" +) + +// A-31: the keys of the older form (`seat.._`) are deleted once; a key of the writer's form, another seat's +// and another kind's stay. +func TestTheOldFindingKeysAreDeletedOnce(t *testing.T) { + state := &oldKeysState{keys: map[string]bool{}} + for _, k := range []string{ + "seat.gitea.packages-token-refused_write", "seat.gitea.packages-token-refused_a_b_c", + "seat.gitea.sub.packages-token-refused", "seat.other.packages-token-refused_write", "seat.gitea.unrelated_write"} { + state.keys[k] = true + } + if err := DeleteOldFindings(state, "gitea", []string{"packages-token-refused", "publish-refused", "incoming-full"}); err != nil { + t.Fatal(err) + } + var left []string + for k := range state.keys { + left = append(left, k) + } + sort.Strings(left) + if got, want := strings.Join(left, " "), "seat.gitea.sub.packages-token-refused seat.gitea.unrelated_write seat.other.packages-token-refused_write"; got != want { + t.Errorf("left %s, want %s", got, want) + } +} + +type oldKeysState struct{ keys map[string]bool } + +func (s *oldKeysState) Get(string) (*stdio.StateEntry, error) { return nil, nil } +func (s *oldKeysState) Put(string, any) (uint64, error) { return 0, nil } +func (s *oldKeysState) Delete(k string) error { delete(s.keys, k); return nil } +func (s *oldKeysState) Keys() ([]string, error) { + var out []string + for k := range s.keys { + out = append(out, k) + } + return out, nil +} diff --git a/modules/gitea/cmd/package-registry/main.go b/modules/gitea/cmd/package-registry/main.go index e07e52e3c..fc26d39c7 100644 --- a/modules/gitea/cmd/package-registry/main.go +++ b/modules/gitea/cmd/package-registry/main.go @@ -40,6 +40,10 @@ func main() { // the runtime answers the writer's subscription only once Serve has its channel go func() { <-stdio.Served() + // the keys of the older form end in no kind the writer owns, so it does not clear them (A-31) + if err := DeleteOldFindings(stdio.State("findings"), packageseats.Self, findingKinds); err != nil { + fmt.Fprintln(os.Stderr, "the old findings are not deleted:", err) + } if err := w.Start(context.Background()); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1)