From ffc5dc333e82ccc4a58956372ead625e067361ef Mon Sep 17 00:00:00 2001 From: Gael Date: Fri, 30 Oct 2026 12:38:29 -0400 Subject: [PATCH] feat: carry resolved installation setup in signed delivery --- pkg/gitops/authority.go | 2 + pkg/gitops/composition_delivery.go | 12 +++++- .../paired_installation_agreement_test.go | 37 +++++++++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/pkg/gitops/authority.go b/pkg/gitops/authority.go index 10153791..9035bc31 100644 --- a/pkg/gitops/authority.go +++ b/pkg/gitops/authority.go @@ -166,6 +166,8 @@ func moduleAuthority( // order, and EdgeDependency.Module stays the signed principal the host // resolves through its catalogue — never a name, binding id or release. authority.InstallationRole = resolved.InstallationRole + authority.Setup = append([]modulecontract.ResolvedSetup(nil), resolved.Setup...) + authority.OwnerAwareResourceKinds = append([]string(nil), resolved.OwnerAwareResourceKinds...) authority.EdgeDependencies = append([]modulecontract.EdgeDependency(nil), resolved.EdgeDependencies...) authority.Queues = append([]string(nil), resolved.Queues...) authority.Namespaces = append([]string(nil), resolved.Namespaces...) diff --git a/pkg/gitops/composition_delivery.go b/pkg/gitops/composition_delivery.go index 6bb0efa9..9264b589 100644 --- a/pkg/gitops/composition_delivery.go +++ b/pkg/gitops/composition_delivery.go @@ -216,7 +216,8 @@ func (c *CompositionDelivery) authority(manifest *solutionhost.ModuleManifest, c // generation or another module. A nil declaration carries nothing, which is // how a withdrawal keeps its Core-only identity. func SignedAuthorityDocument(manifest *solutionhost.ModuleManifest, core, declaration []byte, signer solutionhost.Signer) (*compositionv1.SignedManifestV1, error) { - if declaration == nil { + hasResolved := !manifest.Removed && manifest.Authority != nil && (len(manifest.Authority.Setup) > 0 || len(manifest.Authority.OwnerAwareResourceKinds) > 0) + if declaration == nil && !hasResolved { return nil, nil } if signer == nil { @@ -226,6 +227,15 @@ func SignedAuthorityDocument(manifest *solutionhost.ModuleManifest, core, declar if err := proto.Unmarshal(declaration, &policy); err != nil { return nil, err } + // Setup requirements need resolved callees. Use the Core-resolved carrier + // already captured by native run or publish, never reparse or re-resolve here. + policy.Setup, policy.OwnerAwareResourceKinds = nil, nil + if hasResolved { + policy.OwnerAwareResourceKinds = append([]string(nil), manifest.Authority.OwnerAwareResourceKinds...) + for _, entry := range manifest.Authority.Setup { + policy.Setup = append(policy.Setup, &compositionv1.SetupGrantV1{Binding: entry.Binding, Methods: append([]string(nil), entry.Methods...), Scopes: append([]string(nil), entry.Scopes...)}) + } + } policy.Module, policy.Generation, policy.CoreManifestDigest = manifest.Alias, manifest.Generation, delivery.Digest(core) document, err := proto.MarshalOptions{Deterministic: true}.Marshal(&policy) if err != nil { diff --git a/pkg/gitops/paired_installation_agreement_test.go b/pkg/gitops/paired_installation_agreement_test.go index 360b1faa..ad83b877 100644 --- a/pkg/gitops/paired_installation_agreement_test.go +++ b/pkg/gitops/paired_installation_agreement_test.go @@ -338,3 +338,40 @@ func TestNilAndEmptyEdgesAgree(t *testing.T) { _ = context.Background() } + +func TestResolvedSetupAndOwnerKindsSurviveSignedDelivery(t *testing.T) { + conn, peer := pairedConnection(t) + signer := nativeSigner(t) + composition := NewCompositionDelivery(conn, signer, + func(context.Context, string) ([]*compositionv1.MethodPolicyV1, bool, error) { return nil, false, nil }, + func(context.Context, string) ([]*authorityv1.WorkScopeV1, error) { return nil, nil }, + func(context.Context, string) ([]*compositionv1.RoleV1, error) { return nil, nil }, + func(context.Context, string) (bool, error) { return false, nil }, nil) + d := &NativeDeliverer{Signer: signer, StateDir: t.TempDir(), Prepare: composition.Prepare, Token: func(string) (string, error) { return "credential", nil }} + m := pairedManifest() + m.Authority = &solutionhost.Authority{Principal: m.Alias, Setup: []modulecontract.ResolvedSetup{{Binding: "schemas", Methods: []string{"/store.v1.Store/Define"}, Scopes: []string{"records.types:define"}}}, OwnerAwareResourceKinds: []string{"example.items"}} + _, err := d.Deliver(t.Context(), m) + require.NoError(t, err) + requests := peer.requests() + require.Len(t, requests, 1) + request := requests[0] + require.NotNil(t, request.Authority) + manifest, err := solutionhost.ManifestFromVerified(request.Carrier.Document) + require.NoError(t, err) + var policy compositionv1.AuthorityManifestV1 + require.NoError(t, proto.Unmarshal(request.Authority.Document, &policy)) + require.Equal(t, m.Authority.OwnerAwareResourceKinds, policy.OwnerAwareResourceKinds) + require.Len(t, policy.Setup, 1) + require.Equal(t, "schemas", policy.Setup[0].Binding) + require.Equal(t, m.Authority.Setup[0].Methods, policy.Setup[0].Methods) + require.Equal(t, m.Authority.Setup[0].Scopes, policy.Setup[0].Scopes) + doc := documentOf(t, request.Authority.Document, manifest) + doc.CoreManifestDigest = policy.CoreManifestDigest + doc.OwnerAwareResourceKinds = policy.OwnerAwareResourceKinds + for _, entry := range policy.Setup { + doc.Setup = append(doc.Setup, modulecontract.ResolvedSetup{Binding: entry.Binding, Methods: entry.Methods, Scopes: entry.Scopes}) + } + require.NoError(t, delivered.Pair(doc, request.Carrier.Document, manifest)) + doc.Setup[0].Methods = []string{"/store.v1.Store/Other"} + require.Error(t, delivered.Pair(doc, request.Carrier.Document, manifest), "equal permission cannot hide changed exact method") +}