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 +}