Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions distribution/all-in-one/docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ services:
condition: service_healthy

platform-api:
image: ghcr.io/wso2/api-platform/platform-api:latest
build:
context: ../../platform-api
dockerfile: Dockerfile
Expand Down
41 changes: 23 additions & 18 deletions gateway/gateway-controller/api/management-openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3761,7 +3761,7 @@ components:
description: Custom virtual host/domain for sandbox traffic
pattern: '^[a-zA-Z0-9\.\-]+$'
example: sandbox-api.example.com
policies:
allChannels:
$ref: '#/components/schemas/WebSubAllChannelPolicies'
channels:
type: object
Expand All @@ -3779,35 +3779,40 @@ components:
WebSubChannel:
type: object
description: A single channel definition with optional per-channel policy overrides.
properties:
on_subscription:
$ref: '#/components/schemas/WebSubEventPolicies'
on_unsubscription:
$ref: '#/components/schemas/WebSubEventPolicies'
on_message_received:
$ref: '#/components/schemas/WebSubEventPolicies'
on_message_delivery:
$ref: '#/components/schemas/WebSubEventPolicies'

# WebSubEventPolicies defines policies for a single event type.
WebSubEventPolicies:
type: object
description: Policies for a single event type.
properties:
policies:
$ref: '#/components/schemas/WebSubChannelPolicies'
type: array
description: List of policies applied for this event type.
items:
$ref: '#/components/schemas/Policy'

# WebSubAllChannelPolicies defines policies applied to all channels for each event type.
WebSubAllChannelPolicies:
type: object
description: Policies applied to all channels, organized by event type.
properties:
on_subscription:
type: array
description: Policies applied when a client subscribes to a channel (e.g., api-key-auth)
items:
$ref: '#/components/schemas/Policy'
$ref: '#/components/schemas/WebSubEventPolicies'
on_unsubscription:
type: array
description: Policies applied when a client unsubscribes from a channel (e.g., api-key-auth)
items:
$ref: '#/components/schemas/Policy'
$ref: '#/components/schemas/WebSubEventPolicies'
on_message_received:
type: array
description: Policies applied when a message is received from the publisher via webhook (e.g., hmac-signature-validation)
items:
$ref: '#/components/schemas/Policy'
$ref: '#/components/schemas/WebSubEventPolicies'
on_message_delivery:
type: array
description: Policies applied when delivering a message to a subscriber callback URL (e.g., hmac-sign-messages)
items:
$ref: '#/components/schemas/Policy'
$ref: '#/components/schemas/WebSubEventPolicies'

# WebSubChannelPolicies defines per-channel policies organized by event type.
WebSubChannelPolicies:
Expand Down
246 changes: 122 additions & 124 deletions gateway/gateway-controller/pkg/api/management/generated.go

Large diffs are not rendered by default.

26 changes: 11 additions & 15 deletions gateway/gateway-controller/pkg/policy/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,17 +68,13 @@ func DerivePolicyFromAPIConfig(cfg *models.StoredConfig, routerConfig *config.Ro
channels = *apiData.Channels
}
for chName, ch := range channels {
var chPolicies api.WebSubChannelPolicies
if ch.Policies != nil {
chPolicies = *ch.Policies
}
var finalPolicies []policyenginev1.PolicyInstance

// Policy execution order: policies (on_subscription) -> per-channel policies
// Policy execution order: allChannels (on_subscription) -> per-channel policies
// Start with API-level subscription policies
if apiData.Policies != nil && apiData.Policies.OnSubscription != nil {
finalPolicies = make([]policyenginev1.PolicyInstance, 0, len(*apiData.Policies.OnSubscription))
for _, p := range *apiData.Policies.OnSubscription {
if apiData.AllChannels != nil && apiData.AllChannels.OnSubscription != nil && apiData.AllChannels.OnSubscription.Policies != nil {
finalPolicies = make([]policyenginev1.PolicyInstance, 0, len(*apiData.AllChannels.OnSubscription.Policies))
for _, p := range *apiData.AllChannels.OnSubscription.Policies {
resolved, err := config.ResolvePolicyVersion(policyDefinitions, latestVersions, p.Name, p.Version)
if err != nil {
slog.Error("Failed to resolve policy version for all-channel subscription policy", "policy_name", p.Name, "error", err)
Expand All @@ -89,8 +85,8 @@ func DerivePolicyFromAPIConfig(cfg *models.StoredConfig, routerConfig *config.Ro
}

// Append channel-level on_subscription policies
if chPolicies.OnSubscription != nil && len(*chPolicies.OnSubscription) > 0 {
for _, opPolicy := range *chPolicies.OnSubscription {
if ch.OnSubscription != nil && ch.OnSubscription.Policies != nil && len(*ch.OnSubscription.Policies) > 0 {
for _, opPolicy := range *ch.OnSubscription.Policies {
resolved, err := config.ResolvePolicyVersion(policyDefinitions, latestVersions, opPolicy.Name, opPolicy.Version)
if err != nil {
slog.Error("Failed to resolve policy version for channel-level policy", "policy_name", opPolicy.Name, "channel_name", chName, "error", err)
Expand All @@ -111,9 +107,9 @@ func DerivePolicyFromAPIConfig(cfg *models.StoredConfig, routerConfig *config.Ro

// Build UNSUB (unsubscription) policy chain for this channel
var unsubPolicies []policyenginev1.PolicyInstance
if apiData.Policies != nil && apiData.Policies.OnUnsubscription != nil {
unsubPolicies = make([]policyenginev1.PolicyInstance, 0, len(*apiData.Policies.OnUnsubscription))
for _, p := range *apiData.Policies.OnUnsubscription {
if apiData.AllChannels != nil && apiData.AllChannels.OnUnsubscription != nil && apiData.AllChannels.OnUnsubscription.Policies != nil {
unsubPolicies = make([]policyenginev1.PolicyInstance, 0, len(*apiData.AllChannels.OnUnsubscription.Policies))
for _, p := range *apiData.AllChannels.OnUnsubscription.Policies {
resolved, err := config.ResolvePolicyVersion(policyDefinitions, latestVersions, p.Name, p.Version)
if err != nil {
slog.Error("Failed to resolve policy version for all-channel unsubscription policy", "policy_name", p.Name, "error", err)
Expand All @@ -122,8 +118,8 @@ func DerivePolicyFromAPIConfig(cfg *models.StoredConfig, routerConfig *config.Ro
unsubPolicies = append(unsubPolicies, ConvertAPIPolicyToModel(p, policyv1alpha.LevelAPI, versionutil.MajorVersion(resolved)))
}
}
if chPolicies.OnUnsubscription != nil && len(*chPolicies.OnUnsubscription) > 0 {
for _, opPolicy := range *chPolicies.OnUnsubscription {
if ch.OnUnsubscription != nil && ch.OnUnsubscription.Policies != nil && len(*ch.OnUnsubscription.Policies) > 0 {
for _, opPolicy := range *ch.OnUnsubscription.Policies {
resolved, err := config.ResolvePolicyVersion(policyDefinitions, latestVersions, opPolicy.Name, opPolicy.Version)
if err != nil {
slog.Error("Failed to resolve policy version for channel-level unsubscription policy", "policy_name", opPolicy.Name, "channel_name", chName, "error", err)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,17 +81,26 @@ func (t *Translator) buildEventChannelResource(uuid string, webSubCfg *api.WebSu
sort.Strings(sortedKeys)
for _, chName := range sortedKeys {
ch := channels[chName]
var chPolicies api.WebSubChannelPolicies
if ch.Policies != nil {
chPolicies = *ch.Policies
var subPolicies, unsubPolicies, inboundPolicies, outboundPolicies []interface{}
if ch.OnSubscription != nil {
subPolicies = buildPolicyList(ch.OnSubscription.Policies)
}
if ch.OnUnsubscription != nil {
unsubPolicies = buildPolicyList(ch.OnUnsubscription.Policies)
}
if ch.OnMessageReceived != nil {
inboundPolicies = buildPolicyList(ch.OnMessageReceived.Policies)
}
if ch.OnMessageDelivery != nil {
outboundPolicies = buildPolicyList(ch.OnMessageDelivery.Policies)
}
chEntry := map[string]interface{}{
"name": chName,
"policies": map[string]interface{}{
"subscribe": buildPolicyList(chPolicies.OnSubscription),
"unsubscribe": buildPolicyList(chPolicies.OnUnsubscription),
"inbound": buildPolicyList(chPolicies.OnMessageReceived),
"outbound": buildPolicyList(chPolicies.OnMessageDelivery),
"subscribe": subPolicies,
"unsubscribe": unsubPolicies,
"inbound": inboundPolicies,
"outbound": outboundPolicies,
},
}
channelEntries = append(channelEntries, chEntry)
Expand All @@ -102,11 +111,19 @@ func (t *Translator) buildEventChannelResource(uuid string, webSubCfg *api.WebSu
unsubscribePolicies := []interface{}{}
inboundPolicies := []interface{}{}
outboundPolicies := []interface{}{}
if spec.Policies != nil {
subscribePolicies = buildPolicyList(spec.Policies.OnSubscription)
unsubscribePolicies = buildPolicyList(spec.Policies.OnUnsubscription)
inboundPolicies = buildPolicyList(spec.Policies.OnMessageReceived)
outboundPolicies = buildPolicyList(spec.Policies.OnMessageDelivery)
if spec.AllChannels != nil {
if spec.AllChannels.OnSubscription != nil {
subscribePolicies = buildPolicyList(spec.AllChannels.OnSubscription.Policies)
}
if spec.AllChannels.OnUnsubscription != nil {
unsubscribePolicies = buildPolicyList(spec.AllChannels.OnUnsubscription.Policies)
}
if spec.AllChannels.OnMessageReceived != nil {
inboundPolicies = buildPolicyList(spec.AllChannels.OnMessageReceived.Policies)
}
if spec.AllChannels.OnMessageDelivery != nil {
outboundPolicies = buildPolicyList(spec.AllChannels.OnMessageDelivery.Policies)
}
}

data := map[string]interface{}{
Expand Down
26 changes: 16 additions & 10 deletions platform-api/src/api/generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

66 changes: 47 additions & 19 deletions platform-api/src/internal/model/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,12 +121,16 @@ type WebSubAPIDeploymentYAML struct {

// WebSubAPIDeploymentSpec represents the spec section of the WebSub API deployment YAML
type WebSubAPIDeploymentSpec struct {
DisplayName string `yaml:"displayName"`
Version string `yaml:"version"`
Context string `yaml:"context"`
Vhosts *WebSubAPIDeploymentVhosts `yaml:"vhosts,omitempty"`
Policies *WebSubDeployAllChannelPolicies `yaml:"policies,omitempty"`
Channels map[string]WebSubDeployChannel `yaml:"channels,omitempty"`
DisplayName string `yaml:"displayName"`
Version string `yaml:"version"`
Context string `yaml:"context"`
Vhosts *WebSubAPIDeploymentVhosts `yaml:"vhosts,omitempty"`
AllChannels *WebSubDeployAllChannelPolicies `yaml:"allChannels,omitempty"`
Receiver *WebSubDeployReceiver `yaml:"receiver,omitempty"`
Hub *WebSubDeployHub `yaml:"hub,omitempty"`
Delivery *WebSubDeployDelivery `yaml:"delivery,omitempty"`
Channels map[string]WebSubDeployChannel `yaml:"channels,omitempty"`
DeploymentState string `yaml:"deploymentState,omitempty"`
}

// WebSubAPIDeploymentVhosts represents vhost configuration in the WebSub API deployment YAML
Expand All @@ -135,23 +139,47 @@ type WebSubAPIDeploymentVhosts struct {
Sandbox *string `yaml:"sandbox,omitempty"`
}

// WebSubDeployAllChannelPolicies represents policies for all channels in the deployment YAML, organized by event type.
type WebSubDeployAllChannelPolicies struct {
OnSubscription *[]Policy `yaml:"on_subscription,omitempty"`
OnUnsubscription *[]Policy `yaml:"on_unsubscription,omitempty"`
OnMessageReceived *[]Policy `yaml:"on_message_received,omitempty"`
OnMessageDelivery *[]Policy `yaml:"on_message_delivery,omitempty"`
// WebSubDeployEventPolicies wraps a list of policies for a single event type,
// matching the gateway controller's WebSubEventPolicies schema.
type WebSubDeployEventPolicies struct {
Policies *[]Policy `yaml:"policies,omitempty"`
}

// WebSubDeployChannelPolicies represents per-channel policies in the deployment YAML, organized by event type.
type WebSubDeployChannelPolicies struct {
OnSubscription *[]Policy `yaml:"on_subscription,omitempty"`
OnUnsubscription *[]Policy `yaml:"on_unsubscription,omitempty"`
OnMessageReceived *[]Policy `yaml:"on_message_received,omitempty"`
OnMessageDelivery *[]Policy `yaml:"on_message_delivery,omitempty"`
// WebSubDeployAllChannelPolicies represents policies for all channels in the deployment YAML, organized by event type.
type WebSubDeployAllChannelPolicies struct {
OnSubscription *WebSubDeployEventPolicies `yaml:"on_subscription,omitempty"`
OnUnsubscription *WebSubDeployEventPolicies `yaml:"on_unsubscription,omitempty"`
OnMessageReceived *WebSubDeployEventPolicies `yaml:"on_message_received,omitempty"`
OnMessageDelivery *WebSubDeployEventPolicies `yaml:"on_message_delivery,omitempty"`
}

// WebSubDeployChannel represents a single channel entry in the deployment YAML.
// Event policies are at the top level to match the gateway-controller's WebSubChannel schema.
type WebSubDeployChannel struct {
Policies *WebSubDeployChannelPolicies `yaml:"policies,omitempty"`
OnSubscription *WebSubDeployEventPolicies `yaml:"on_subscription,omitempty"`
OnUnsubscription *WebSubDeployEventPolicies `yaml:"on_unsubscription,omitempty"`
OnMessageReceived *WebSubDeployEventPolicies `yaml:"on_message_received,omitempty"`
OnMessageDelivery *WebSubDeployEventPolicies `yaml:"on_message_delivery,omitempty"`
}

// WebSubDeployReceiver represents the receiver section in the deployment YAML.
type WebSubDeployReceiver struct {
Policies []Policy `yaml:"policies"`
}

// WebSubDeployHub represents the hub section in the deployment YAML.
type WebSubDeployHub struct {
Policies []Policy `yaml:"policies"`
Channels []WebSubDeployHubChannel `yaml:"channels,omitempty"`
}

// WebSubDeployHubChannel represents a channel entry under the hub section in the deployment YAML.
type WebSubDeployHubChannel struct {
Name string `yaml:"name"`
Policies []Policy `yaml:"policies"`
}

// WebSubDeployDelivery represents the delivery section in the deployment YAML.
type WebSubDeployDelivery struct {
Policies []Policy `yaml:"policies"`
}
Loading
Loading