| 1 | package sidecar |
| 2 | |
| 3 | import ( |
| 4 | "fmt" |
| 5 | "strings" |
| 6 | |
| 7 | "reasonix/internal/extension/protocol" |
| 8 | "reasonix/internal/pluginpkg" |
| 9 | ) |
| 10 | |
| 11 | func (c *Client) initializeParams() protocol.InitializeParams { |
| 12 | return protocol.InitializeParams{ |
| 13 | ProtocolVersion: protocol.ProtocolVersion, |
| 14 | ProtocolID: protocol.ProtocolID, |
| 15 | Manifest: c.manifestExpectation(), |
| 16 | Session: c.session, |
| 17 | DependencySchemaVersion: protocol.DependencySchemaVersion, |
| 18 | Capabilities: protocol.HostCapabilities{ |
| 19 | ContentRefs: true, |
| 20 | UIHost: c.uiHost, |
| 21 | ProtocolVersion: protocol.ProtocolVersion, |
| 22 | DependencySchemaVersion: protocol.DependencySchemaVersion, |
| 23 | }, |
| 24 | } |
| 25 | } |
| 26 | |
| 27 | func (c *Client) manifestExpectation() protocol.ManifestExpectation { |
| 28 | rt := c.rt |
| 29 | expectation := protocol.ManifestExpectation{ |
| 30 | Intercepts: append([]string(nil), rt.Intercepts...), |
| 31 | Replaces: append([]string(nil), rt.Replaces...), |
| 32 | Capabilities: append([]string(nil), rt.Capabilities...), |
| 33 | Requires: requirementWires(c.requires), |
| 34 | Provides: capabilityWires(c.provides), |
| 35 | } |
| 36 | for _, provided := range c.provides { |
| 37 | switch strings.ToLower(strings.TrimSpace(provided.Kind)) { |
| 38 | case "provider": |
| 39 | expectation.Providers = append(expectation.Providers, capabilityAddress(provided)) |
| 40 | case "uiaction": |
| 41 | expectation.UIActions = append(expectation.UIActions, strings.TrimSpace(provided.ID)) |
| 42 | } |
| 43 | } |
| 44 | return expectation |
| 45 | } |
| 46 | |
| 47 | func capabilityAddress(ref pluginpkg.CapabilityRef) string { |
| 48 | return strings.TrimSuffix(strings.TrimSpace(ref.Namespace), "/") + "/" + strings.TrimPrefix(strings.TrimSpace(ref.ID), "/") |
| 49 | } |
| 50 | |
| 51 | func capabilityWires(refs []pluginpkg.CapabilityRef) []protocol.CapabilityWire { |
| 52 | out := make([]protocol.CapabilityWire, 0, len(refs)) |
| 53 | for _, ref := range refs { |
| 54 | out = append(out, protocol.CapabilityWire{ |
| 55 | Namespace: strings.TrimSpace(ref.Namespace), |
| 56 | Kind: strings.TrimSpace(ref.Kind), |
| 57 | ID: strings.TrimSpace(ref.ID), |
| 58 | Version: strings.TrimSpace(ref.Version), |
| 59 | SchemaHash: strings.TrimSpace(ref.SchemaHash), |
| 60 | }) |
| 61 | } |
| 62 | return out |
| 63 | } |
| 64 | |
| 65 | func requirementWires(refs []pluginpkg.CapabilityRef) []protocol.RequirementWire { |
| 66 | out := make([]protocol.RequirementWire, 0, len(refs)) |
| 67 | for _, ref := range refs { |
| 68 | out = append(out, protocol.RequirementWire{ |
| 69 | Namespace: strings.TrimSpace(ref.Namespace), |
| 70 | Kind: strings.TrimSpace(ref.Kind), |
| 71 | ID: strings.TrimSpace(ref.ID), |
| 72 | Version: strings.TrimSpace(ref.Version), |
| 73 | SchemaHash: strings.TrimSpace(ref.SchemaHash), |
| 74 | VersionRange: strings.TrimSpace(ref.VersionRange), |
| 75 | Optional: ref.Optional, |
| 76 | }) |
| 77 | } |
| 78 | return out |
| 79 | } |
| 80 | |
| 81 | // validateProvidesCeiling rejects handshake Provides entries that are not a |
| 82 | // subset of the manifest capability ceiling (by namespace/kind/id). |
| 83 | func validateProvidesCeiling(manifest []pluginpkg.CapabilityRef, wire []protocol.CapabilityWire) error { |
| 84 | if len(wire) == 0 { |
| 85 | return nil |
| 86 | } |
| 87 | if len(manifest) == 0 { |
| 88 | // No v2 provides list: fall back to runtime.capabilities string checks above. |
| 89 | return nil |
| 90 | } |
| 91 | allowed := map[string]bool{} |
| 92 | for _, p := range manifest { |
| 93 | key := strings.TrimSpace(p.Namespace) + "/" + strings.TrimSpace(p.Kind) + "/" + strings.TrimSpace(p.ID) |
| 94 | allowed[key] = true |
| 95 | } |
| 96 | for _, w := range wire { |
| 97 | key := strings.TrimSpace(w.Namespace) + "/" + strings.TrimSpace(w.Kind) + "/" + strings.TrimSpace(w.ID) |
| 98 | if !allowed[key] { |
| 99 | return fmt.Errorf("handshake provides %q is outside the manifest provides ceiling", key) |
| 100 | } |
| 101 | } |
| 102 | return nil |
| 103 | } |
| 104 |