From 32014ac6de1a2ed73b937fd1c6751c627fb74d98 Mon Sep 17 00:00:00 2001 From: fix-ctl-pas Date: Fri, 16 Oct 2026 19:31:58 +0200 Subject: [PATCH] Keep a provision's contributes, at, from, as and names in the sent plans (issue 923) --- internal/inventory/provisioning.go | 16 ++++------------ internal/inventory/provisioning_test.go | 22 ++++++++++++++++++++++ 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/internal/inventory/provisioning.go b/internal/inventory/provisioning.go index 4f1bad66..f3340e58 100644 --- a/internal/inventory/provisioning.go +++ b/internal/inventory/provisioning.go @@ -81,18 +81,10 @@ type ProvisionedCollection struct { } // ProvisionedCredential is one provision the module requires, under one local name, and its provider (issue 760); -// with a name, a credential issued for this holder alone (issue 757). -type ProvisionedCredential struct { - Name string `json:"name,omitempty"` - Provision string `json:"provision"` - Local string `json:"local,omitempty"` - Provider string `json:"provider"` - ProviderModule string `json:"provider-module"` - // CredentialForm is the form the provider's offer declares for its credential (issue 768): shared, pair, - // issued or given; empty when the provider's manifest was not in hand. - CredentialForm string `json:"credential-form,omitempty"` - Path string `json:"path,omitempty"` -} +// with a name, a credential issued for this holder alone (issue 757). It is the composition's own type, not a copy: +// the plan is kept and read back as the one it was sent as, so no field of it (contributes, at, from, as, names) can +// be lost between the two (issue 923). +type ProvisionedCredential = catalogue.PlanProvision // ProvisionedSecret is one of the module's own secrets, by its name in the manifest. Path, when set, is the file // holding the secret alone (the manifest's `own-secrets`), which the client fills with its value and nothing else. diff --git a/internal/inventory/provisioning_test.go b/internal/inventory/provisioning_test.go index 5fccf095..21e88169 100644 --- a/internal/inventory/provisioning_test.go +++ b/internal/inventory/provisioning_test.go @@ -352,3 +352,25 @@ func TestAPlanMayHoldSeveralNamedItemsOfOneCollectionAndRefusesABadOne(t *testin } } } + +// **A kept plan's provisions keep every field the composition sets** (issue 923): the names, the place, the machine +// and the identity the provider's helper writes into the consumer's entry, and what the manifest contributes, are +// read back as they were sent, so the assignments mirror carries them to the provider. +func TestAKeptPlansProvisionsKeepContributesAtFromAsAndNames(t *testing.T) { + sent := catalogue.PlanProvision{Provision: "route", Provider: "novox", ProviderModule: "route-proxy", + Contributes: map[string]any{"database": "gitea"}, At: "10.0.0.1", From: "novox", As: "gitea@novox", + Names: map[string]string{"name-web": "git.example.org", "internal-name": "gitea.mesh"}} + raw, err := json.Marshal(map[string]any{"gitea": map[string]any{ + "provisions": []catalogue.PlanProvision{sent}, "required-by": "forge"}}) + if err != nil { + t.Fatal(err) + } + var kept map[string]keptPlan + if err := json.Unmarshal(raw, &kept); err != nil { + t.Fatal(err) + } + got := kept["gitea"].Provisions + if len(got) != 1 || !reflect.DeepEqual(got[0], sent) { + t.Fatalf("the kept plan's provisions are %+v, want %+v", got, sent) + } +}