From 074032e9d43c93d274cce7cbb77e271e1d5cee15 Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 5 Nov 2026 14:49:56 +0100 Subject: [PATCH] =?UTF-8?q?mesh-module-assigner=20client:=20CheckProposalI?= =?UTF-8?q?D,=20the=20id=20a=20proposal=20and=20the=20ask=20about=20it=20c?= =?UTF-8?q?arry=20(ADR=200634=20=C2=A74;=20issue=201966)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i --- .../meshmoduleassignerclient/client_test.go | 7 +++++++ .../meshmoduleassignerclient/proposal.go | 17 +++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 placement/go/clients/meshmoduleassignerclient/proposal.go diff --git a/placement/go/clients/meshmoduleassignerclient/client_test.go b/placement/go/clients/meshmoduleassignerclient/client_test.go index 09ec425..06453e0 100644 --- a/placement/go/clients/meshmoduleassignerclient/client_test.go +++ b/placement/go/clients/meshmoduleassignerclient/client_test.go @@ -12,6 +12,13 @@ import ( ) func TestPlacementClient(t *testing.T) { + t.Run("proposal id", func(t *testing.T) { + for id, ok := range map[string]bool{"p-20261028t183000-1a2b3c": true, "abc": true, "ab": false, "A-bc": false, "-abc": false, "a.bc": false, "": false} { + if (CheckProposalID(id) == nil) != ok { + t.Errorf("CheckProposalID(%q) = %v", id, CheckProposalID(id)) + } + } + }) t.Run("key and file", func(t *testing.T) { // Research 072 row 37: one node key and one key per module, a legacy key read beside them, any other refused. for key, want := range map[string]struct { diff --git a/placement/go/clients/meshmoduleassignerclient/proposal.go b/placement/go/clients/meshmoduleassignerclient/proposal.go new file mode 100644 index 0000000..284a358 --- /dev/null +++ b/placement/go/clients/meshmoduleassignerclient/proposal.go @@ -0,0 +1,17 @@ +package meshmoduleassignerclient + +import ( + "fmt" + "regexp" +) + +var proposalIDOK = regexp.MustCompile(`^[a-z0-9][a-z0-9-]{2,62}$`) + +// CheckProposalID refuses an id that is no proposal's: lower-case letters, digits and dashes, 3 to 63 of them, so it is one +// key token. The holder writes proposals under it, and the keys of the asks about a proposal (`placement.`) carry it. +func CheckProposalID(id string) error { + if !proposalIDOK.MatchString(id) { + return fmt.Errorf("mesh-module-assigner: %q is no proposal id (lower-case letters, digits and dashes, one key token)", id) + } + return nil +}