From 9379e9a96ad425e84e7e77643881861b274653b6 Mon Sep 17 00:00:00 2001 From: jochen Date: Fri, 30 Oct 2026 16:03:14 +0100 Subject: [PATCH] Keep one list of credential forms in the catalogue, so no reader of a plan refuses a form another writes (issue 774) Second meeting of the credential-form list kind: the provisioner client's own copy lacked "none" and refused every plan naming it, as the controller's had before. Thorough: one list in mesh-sdk, catalogue.CredentialForms and IsCredentialForm; provisions' forms are now the catalogue's constants. --- go/catalogue/handed_providers_test.go | 7 +++++++ go/catalogue/manifest.go | 12 ++++++++++++ go/provisions/provisions.go | 13 +++++++------ 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/go/catalogue/handed_providers_test.go b/go/catalogue/handed_providers_test.go index 6541c74..3851372 100644 --- a/go/catalogue/handed_providers_test.go +++ b/go/catalogue/handed_providers_test.go @@ -153,6 +153,13 @@ func TestAHandedModulesPlanNamesTheCredentialFormOfItsProvidersOffer(t *testing. if len(got) != 1 || got[0].CredentialForm != want { t.Errorf("an offer with %q: the plan names %+v, want the form %q", credential, got, want) } + // Every form a plan names is in the one list each reader checks (issue 774); an undeclared one is not. + if IsCredentialForm(want) != (want != "") { + t.Errorf("the form %q of an offer with %q: in CredentialForms %v", want, credential, IsCredentialForm(want)) + } + } + if forms := strings.Join(CredentialForms(), ","); forms != "shared,pair,issued,given,none" || IsCredentialForm("maybe") { + t.Errorf("the credential forms are %s, and maybe is one: %v", forms, IsCredentialForm("maybe")) } if got := (Manifest{Module: "x"}).CredentialFormOf("postgres-database"); got != "" { t.Errorf("a module offering nothing has the credential form %q", got) diff --git a/go/catalogue/manifest.go b/go/catalogue/manifest.go index 1d5242f..04e86b8 100644 --- a/go/catalogue/manifest.go +++ b/go/catalogue/manifest.go @@ -11,6 +11,7 @@ import ( "errors" "fmt" "regexp" + "slices" "sort" "strconv" "strings" @@ -371,6 +372,17 @@ const ( CredentialFormNone = "none" ) +// CredentialForms is the one list of the credential forms a plan's entry may name (issue 774): every part that reads +// a plan checks a form here, so a form added above reaches each of them at once. Each part kept its own copy before, +// and a copy left without "none" refused every plan naming it. +func CredentialForms() []string { + return []string{CredentialFormShared, CredentialFormPair, CredentialFormIssued, CredentialFormGiven, + CredentialFormNone} +} + +// IsCredentialForm is whether form is one of CredentialForms. +func IsCredentialForm(form string) bool { return slices.Contains(CredentialForms(), form) } + // CredentialFormOf is the credential form this module's offer of a provision declares, read from the offer's // `credential` alone (issue 768): no new manifest field, since that field already says whether the provider shares // one of its own secrets, its software issues it, or a person gives it, and saying none is a login per consumer. diff --git a/go/provisions/provisions.go b/go/provisions/provisions.go index 1e7a4fb..376b9bc 100644 --- a/go/provisions/provisions.go +++ b/go/provisions/provisions.go @@ -93,15 +93,16 @@ func PlanKey(node, module string) (string, error) { return node + "." + module, nil } -// The forms of a provision's credential, as a plan's entry names them (catalogue.PlanProvision.CredentialForm). +// The forms of a provision's credential, as a plan's entry names them (catalogue.PlanProvision.CredentialForm): the +// catalogue's one list (catalogue.CredentialForms, issue 774), under the names this package has used. const ( - FormPair = "pair" - FormShared = "shared" - FormIssued = "issued" - FormGiven = "given" + FormPair = catalogue.CredentialFormPair + FormShared = catalogue.CredentialFormShared + FormIssued = catalogue.CredentialFormIssued + FormGiven = catalogue.CredentialFormGiven // FormNone is an offer whose consumers present no credential (catalogue.CredentialFormNone): the vault mints nothing, // and the provision depends on no credential. - FormNone = "none" + FormNone = catalogue.CredentialFormNone ) // VaultName is the vault's name of a provision's credential in form, as its verb `own` names it and the provider asks