change the spec to support 0.5.0 and 0.6.0#1948
Conversation
|
Warning Rate limit exceeded
You’ve run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (7)
📝 WalkthroughWalkthroughThis pull request refactors WebSub API policy configuration across gateway-controller and platform-api services. The core change renames the all-channels policy field from Suggested reviewers
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (2)
gateway/gateway-controller/api/management-openapi.yaml (2)
3779-3790: ⚡ Quick winEvent property names use snake_case instead of camelCase.
The new
WebSubChannelpropertieson_subscription,on_unsubscription,on_message_received, andon_message_deliveryuse snake_case. The same naming style is propagated toWebSubAllChannelPolicies(lines 3808-3815) andWebSubEventPoliciesis referenced by them. Per the established convention for REST API entity property names in this spec file, these should be camelCase (e.g.,onSubscription,onUnsubscription,onMessageReceived,onMessageDelivery). Since this refactor is already restructuring the per-event policy shape and regenerating the Go types, it is a good moment to migrate the keys to camelCase before the new shape is consumed by clients. If the snake_case keys are an intentional, externally-visible contract, please disregard.♻️ Proposed property renames
WebSubChannel: type: object description: A single channel definition with optional per-channel policy overrides. properties: - on_subscription: + onSubscription: $ref: '#/components/schemas/WebSubEventPolicies' - on_unsubscription: + onUnsubscription: $ref: '#/components/schemas/WebSubEventPolicies' - on_message_received: + onMessageReceived: $ref: '#/components/schemas/WebSubEventPolicies' - on_message_delivery: + onMessageDelivery: $ref: '#/components/schemas/WebSubEventPolicies'WebSubAllChannelPolicies: type: object description: Policies applied to all channels, organized by event type. properties: - on_subscription: + onSubscription: $ref: '#/components/schemas/WebSubEventPolicies' - on_unsubscription: + onUnsubscription: $ref: '#/components/schemas/WebSubEventPolicies' - on_message_received: + onMessageReceived: $ref: '#/components/schemas/WebSubEventPolicies' - on_message_delivery: + onMessageDelivery: $ref: '#/components/schemas/WebSubEventPolicies'Based on learnings: "In wso2/api-platform's API Gateway Controller OpenAPI spec YAML files under
gateway/gateway-controller/api/, ensure all REST API entity property names follow camelCase (e.g.,createdAt,updatedAt) and never use snake_case (e.g.,created_at,updated_at). This applies to schema property names,requiredarray entries, and any inline example values included in the spec."🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@gateway/gateway-controller/api/management-openapi.yaml` around lines 3779 - 3790, The schema properties in WebSubChannel (and the related WebSubAllChannelPolicies and any references to WebSubEventPolicies) use snake_case; change each event property to camelCase—rename on_subscription → onSubscription, on_unsubscription → onUnsubscription, on_message_received → onMessageReceived, and on_message_delivery → onMessageDelivery—then update any corresponding entries in required arrays and inline examples to match the new camelCase keys so the OpenAPI spec and generated Go types remain consistent.
3817-3841: ⚡ Quick winRemove the orphaned
WebSubChannelPoliciesschema.Verification confirms that
WebSubChannelPoliciesis not referenced by any other schema in the management-openapi.yaml spec, and the corresponding Go struct has been removed from the generated code. Retaining this definition creates inconsistency between the spec and the generated types, and will confuse consumers of the API specification.♻️ Proposed removal
- # WebSubChannelPolicies defines per-channel policies organized by event type. - WebSubChannelPolicies: - type: object - description: Policies applied to a specific channel, organized by event type. - properties: - on_subscription: - type: array - description: Policies applied when a client subscribes to this channel (e.g., rbac) - items: - $ref: '#/components/schemas/Policy' - on_unsubscription: - type: array - description: Policies applied when a client unsubscribes from this channel - items: - $ref: '#/components/schemas/Policy' - on_message_received: - type: array - description: Policies applied when a message is received for this channel - items: - $ref: '#/components/schemas/Policy' - on_message_delivery: - type: array - description: Policies applied when delivering a message for this channel - items: - $ref: '#/components/schemas/Policy' -🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@gateway/gateway-controller/api/management-openapi.yaml` around lines 3817 - 3841, Remove the orphaned WebSubChannelPolicies schema definition from the management-openapi.yaml (the entire components schema named "WebSubChannelPolicies"), ensuring no lingering references to WebSubChannelPolicies remain elsewhere in the spec; after removal, regenerate any OpenAPI-derived code/artifacts to keep the spec and generated Go types in sync (search for the symbol WebSubChannelPolicies to verify no usages remain).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@gateway/gateway-controller/pkg/api/management/generated.go`:
- Around line 1587-1624: The generated types drop the 0.5.0 "policies"-based
shape (WebhookAPIData now only exposes AllChannels of type
WebSubAllChannelPolicies and channel structs use WebSubEventPolicies), making
old payloads unrepresentable; update the source OpenAPI schema to include
backward-compatible fields (e.g. keep the original "policies" arrays on
WebSubEventPolicies/WebSubChannel and/or add a oneOf/anyOf that accepts both the
legacy policies array and the new event-wrapper object), then regenerate the
client so WebhookAPIData, WebSubAllChannelPolicies, WebSubChannel, and
WebSubEventPolicies accept both the legacy policies-based payload and the new
event-wrapper form during the transition.
In `@platform-api/src/internal/model/deployment.go`:
- Line 128: The AllChannels field in the WebSubAPIDeploymentSpec struct is
missing a yaml tag which will break YAML marshaling; update the AllChannels
field declaration (type WebSubDeployAllChannelPolicies) to include a matching
yaml tag (e.g., yaml:"allChannels,omitempty") alongside the existing json tag so
YAML serialization uses the correct key and mirrors the other fields' tagging.
In `@platform-api/src/resources/openapi.yaml`:
- Around line 9047-9048: The OpenAPI change renamed the WebSub payload field
from policies to allChannels and changed its shape, breaking backward
compatibility; update the schema(s) (e.g., WebSubAllChannelPolicies and any
related schemas referenced as allChannels) to accept both old and new payload
shapes by using a oneOf (or anyOf) union that includes the previous array form
(the legacy "policies" array schema) and the new object form ({ allChannels:
[...] }), or reintroduce a backward-compatible property (keep "policies" as a
deprecated alias alongside "allChannels") so both clients are supported; apply
the same pattern to the other affected schema references mentioned (the
occurrences around the other WebSub channel policy refs).
---
Nitpick comments:
In `@gateway/gateway-controller/api/management-openapi.yaml`:
- Around line 3779-3790: The schema properties in WebSubChannel (and the related
WebSubAllChannelPolicies and any references to WebSubEventPolicies) use
snake_case; change each event property to camelCase—rename on_subscription →
onSubscription, on_unsubscription → onUnsubscription, on_message_received →
onMessageReceived, and on_message_delivery → onMessageDelivery—then update any
corresponding entries in required arrays and inline examples to match the new
camelCase keys so the OpenAPI spec and generated Go types remain consistent.
- Around line 3817-3841: Remove the orphaned WebSubChannelPolicies schema
definition from the management-openapi.yaml (the entire components schema named
"WebSubChannelPolicies"), ensuring no lingering references to
WebSubChannelPolicies remain elsewhere in the spec; after removal, regenerate
any OpenAPI-derived code/artifacts to keep the spec and generated Go types in
sync (search for the symbol WebSubChannelPolicies to verify no usages remain).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 338f63dd-79f3-4d02-a9ea-2733142bbfa2
📒 Files selected for processing (11)
distribution/all-in-one/docker-compose.yamlgateway/gateway-controller/api/management-openapi.yamlgateway/gateway-controller/pkg/api/management/generated.gogateway/gateway-controller/pkg/policy/builder.gogateway/gateway-controller/pkg/policyxds/event_channel_translator.goplatform-api/src/api/generated.goplatform-api/src/internal/model/deployment.goplatform-api/src/internal/model/websub_api.goplatform-api/src/internal/service/websub_api.goplatform-api/src/internal/service/websub_api_deployment.goplatform-api/src/resources/openapi.yaml
| allChannels: | ||
| $ref: '#/components/schemas/WebSubAllChannelPolicies' |
There was a problem hiding this comment.
Preserve backward compatibility for WebSub policy payloads.
This changes both the field name (policies → allChannels) and the event payload shape (array → { policies: [] }). That will break 0.5.0 clients (or silently ignore old fields), so the spec does not currently support both versions.
Suggested compatibility approach
WebSubAPI:
properties:
allChannels:
$ref: '#/components/schemas/WebSubAllChannelPolicies'
+ policies:
+ $ref: '#/components/schemas/WebSubAllChannelPolicies'
+ deprecated: true
+ description: Deprecated alias for backward compatibility with 0.5.0 clients.
WebSubEventPolicies:
- type: object
- description: Policies for a single event type.
- properties:
- policies:
- type: array
- description: List of policies applied for this event type.
- items:
- $ref: '#/components/schemas/Policy'
+ description: Supports both legacy array form and wrapped form.
+ oneOf:
+ - type: array
+ items:
+ $ref: '#/components/schemas/Policy'
+ - type: object
+ properties:
+ policies:
+ type: array
+ items:
+ $ref: '#/components/schemas/Policy'Also applies to: 9153-9160, 9162-9169, 9201-9208
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@platform-api/src/resources/openapi.yaml` around lines 9047 - 9048, The
OpenAPI change renamed the WebSub payload field from policies to allChannels and
changed its shape, breaking backward compatibility; update the schema(s) (e.g.,
WebSubAllChannelPolicies and any related schemas referenced as allChannels) to
accept both old and new payload shapes by using a oneOf (or anyOf) union that
includes the previous array form (the legacy "policies" array schema) and the
new object form ({ allChannels: [...] }), or reintroduce a backward-compatible
property (keep "policies" as a deprecated alias alongside "allChannels") so both
clients are supported; apply the same pattern to the other affected schema
references mentioned (the occurrences around the other WebSub channel policy
refs).
There was a problem hiding this comment.
from platform api we are not allow to create 0.5 APIS but for any created APIS can deploy on 0.5 gateway.
There was a problem hiding this comment.
@tharindu1st Thanks for clarifying. Understood: the Platform API should be 0.6-only for WebSub payloads, while deployments must remain compatible with 0.5 gateways.
Given that, I’ll drop the earlier suggestion to accept 0.5 payloads in the OpenAPI (no deprecated alias and no oneOf needed). A couple of follow-ups to ensure we meet your stated model:
-
Platform API schema
- Keep WebSubAPI.allChannels as the sole field (no legacy policies alias).
- Optional hardening: if you want to actively reject 0.5 payloads rather than ignore unknown fields, we can set additionalProperties: false on the relevant WebSub objects. Let me know if you want this in this PR.
-
Deployment compatibility to 0.5 gateways
- The deploy path should down-convert the 0.6 event-policy shape to the 0.5 contract when the target gateway advertises version 0.5.x (e.g., flatten wrapped event objects to arrays and emit the legacy keys expected by 0.5).
- Please confirm whether the current websub_api_deployment.go already performs this version-aware transform. If not, I can open a follow-up issue to track it, or draft a small plan here.
-
Documentation note (optional)
- I recommend adding a short note to WebSubAPI.allChannels description indicating this replaces policies as of 0.6.0 so client integrators understand the breaking change.
How would you like to proceed on the two optional items (strict schema and brief doc note)? If you prefer, I can open a follow-up GitHub issue to track the version-aware deployment transform.
✏️ Learnings added
Learnt from: tharindu1st
Repo: wso2/api-platform PR: 1948
File: platform-api/src/resources/openapi.yaml:0-0
Timestamp: 2026-05-13T18:50:36.592Z
Learning: Compatibility model for WebSub in wso2/api-platform: Platform API schema is 0.6-only (do not accept legacy 0.5 “policies” payloads). Backward compatibility is required only on the deployment path—APIs created via Platform API must be deployable to 0.5 gateways via a version-aware manifest transformation in platform-api (e.g., in websub_api_deployment.go).
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
🧠 Learnings used
Learnt from: IsuruGunarathne
Repo: wso2/api-platform PR: 1326
File: platform-api/src/resources/openapi.yaml:3159-3176
Timestamp: 2026-03-11T11:08:19.820Z
Learning: In platform-api/src/resources/openapi.yaml, the APIVhost schema intentionally marks main and sandbox optional (no required: [main]). Reviewers should not treat missing main as a schema gap. Ensure server deployment logic preserves existing/default value when Main is nil (deployment.go lines ~213-227). The generated Go type uses Main *string to model optional fields. When reviewing OpenAPI schemas, treat absence of required as an intentional partial override design.
Learnt from: ShalkiWenushika
Repo: wso2/api-platform PR: 1342
File: platform-api/src/resources/openapi.yaml:5055-5062
Timestamp: 2026-03-15T16:50:28.306Z
Learning: Ensure API key expiry logic is explicit in platform-api/src/resources/openapi.yaml and the related platform-api/src/internal/service/apikey.go: 1) expiresAt, if present, takes precedence for expiry. 2) If expiresAt is absent, derive expiry from expiresIn. 3) Enforce mutual exclusivity in the OpenAPI spec for CreateAPIKeyRequest and UpdateAPIKeyRequest using allOf with a not schema, e.g.: allOf: - not: { required: [expiresAt, expiresIn] }. This prevents requests that specify both fields and avoids ambiguity. Add or update CI validation to ensure this pattern is enforced for any future OpenAPI changes.
There was a problem hiding this comment.
create a github issue.
There was a problem hiding this comment.
🧩 Analysis chain
@tharindu1st Creating the GitHub issue now with context, acceptance criteria, and backlinks to PR #1948 and your comment. I’ll share the issue URL once it’s created.
🏁 Script executed:
#!/bin/bash
set -euo pipefail
REPO="wso2/api-platform"
TITLE="WebSub: Version-aware deployment transform for 0.5 gateways (Platform API remains 0.6-only)"
PR_URL="https://github.com/wso2/api-platform/pull/1948"
COMMENT_URL="https://github.com/wso2/api-platform/pull/1948#discussion_r3234750942"
REQUESTER="tharindu1st"
BODY_FILE="$(mktemp)"
cat > "$BODY_FILE" << 'EOF'
Summary
- Platform API will accept only WebSub 0.6 payloads (allChannels + per-event wrapper). Deployments must remain compatible with 0.5 gateways.
Context
- See PR `#1948` for the schema refactor to 0.6-only. As noted in the referenced comment, we should not accept 0.5 payloads at the Platform API layer; backward compatibility must be handled only in the deployment path.
Problem
- The current WebSub deployment YAML builder emits the 0.6 structure. 0.5 gateways expect the legacy 0.5 shape, so deployments targeting 0.5 gateways must receive a compatible manifest.
Goal
- Add a version-aware transformation in the deployment path so that:
- When the target gateway is 0.5.x, the emitted manifest uses the legacy top-level and per-event array shapes expected by 0.5 (and omits 0.6-only sections where unsupported).
- When the target gateway is 0.6.0+, emit the 0.6 event-policy structure.
Acceptance criteria
- Detect target gateway version during deployment and select the appropriate manifest shape.
- Unit tests assert both shapes (0.5 vs 0.6) for representative cases (global/all-channels and per-channel event policies).
- No changes to the Platform API OpenAPI are required; it remains 0.6-only.
- Add a brief note in code/docs describing the version-aware behavior.
Backlinks
- PR: https://github.com/wso2/api-platform/pull/1948
- Comment: https://github.com/wso2/api-platform/pull/1948#discussion_r3234750942
Requested by `@tharindu1st` on 2026-05-13.
EOF
# Create the issue first (without assignee to avoid failure if permissions prevent assignment)
ISSUE_URL="$(gh issue create --repo "$REPO" --title "$TITLE" --body-file "$BODY_FILE")"
echo "Created issue: $ISSUE_URL"
# Try to assign to requester; do not fail the script if assignment is not permitted
ISSUE_NUMBER="$(basename "$ISSUE_URL")"
set +e
gh issue edit --repo "$REPO" "$ISSUE_NUMBER" --add-assignee "$REQUESTER"
ASSIGN_RC=$?
set -e
if [ $ASSIGN_RC -eq 0 ]; then
echo "Assigned to: $REQUESTER"
else
echo "Note: Could not assign to $REQUESTER (insufficient permissions or user not assignable)."
fi
# Cleanup
rm -f "$BODY_FILE"
Length of output: 76
@tharindu1st The first attempt failed because GH_TOKEN/GITHUB_TOKEN isn’t available in the automation environment. I’ll retry with a script that, if no token is present, outputs a prefilled new-issue URL, the full body, and a ready-to-run gh command you can execute locally. If you can provide a token, I can create and assign it automatically.
🏁 Script executed:
#!/bin/bash
set -euo pipefail
REPO="wso2/api-platform"
TITLE="WebSub: Version-aware deployment transform for 0.5 gateways (Platform API remains 0.6-only)"
REQUESTER="tharindu1st"
PR_URL="https://github.com/wso2/api-platform/pull/1948"
COMMENT_URL="https://github.com/wso2/api-platform/pull/1948#discussion_r3234750942"
read -r -d '' BODY <<'EOF'
Summary
- Platform API will accept only WebSub 0.6 payloads (allChannels + per-event wrapper). Deployments must remain compatible with 0.5 gateways.
Context
- See PR `#1948` for the schema refactor to 0.6-only. As noted in the referenced comment, we should not accept 0.5 payloads at the Platform API layer; backward compatibility must be handled only in the deployment path.
Problem
- The current WebSub deployment YAML builder emits the 0.6 structure. 0.5 gateways expect the legacy 0.5 shape, so deployments targeting 0.5 gateways must receive a compatible manifest.
Goal
- Add a version-aware transformation in the deployment path so that:
- When the target gateway is 0.5.x, the emitted manifest uses the legacy top-level and per-event array shapes expected by 0.5 (and omits 0.6-only sections where unsupported).
- When the target gateway is 0.6.0+, emit the 0.6 event-policy structure.
Acceptance criteria
- Detect target gateway version during deployment and select the appropriate manifest shape.
- Unit tests assert both shapes (0.5 vs 0.6) for representative cases (global/all-channels and per-channel event policies).
- No changes to the Platform API OpenAPI are required; it remains 0.6-only.
- Add a brief note in code/docs describing the version-aware behavior.
Backlinks
- PR: https://github.com/wso2/api-platform/pull/1948
- Comment: https://github.com/wso2/api-platform/pull/1948#discussion_r3234750942
Requested by `@tharindu1st` on 2026-05-13.
EOF
if [[ -n "${GH_TOKEN:-}" || -n "${GITHUB_TOKEN:-}" ]]; then
TMP_BODY="$(mktemp)"
printf "%s" "$BODY" > "$TMP_BODY"
ISSUE_URL="$(gh issue create --repo "$REPO" --title "$TITLE" --body-file "$TMP_BODY")" || {
echo "Failed to create issue via gh." >&2
exit 1
}
echo "Created issue: $ISSUE_URL"
ISSUE_NUMBER="$(basename "$ISSUE_URL")"
if gh issue edit --repo "$REPO" "$ISSUE_NUMBER" --add-assignee "$REQUESTER" >/dev/null 2>&1; then
echo "Assigned to: $REQUESTER"
else
echo "Note: Could not assign to $REQUESTER (permissions or settings)."
fi
rm -f "$TMP_BODY"
else
echo "GH_TOKEN/GITHUB_TOKEN is not set. Cannot create the issue automatically."
# Print a prefilled URL for manual creation
python - <<PY
import urllib.parse
repo = "${REPO}"
title = "${TITLE}"
body = """${BODY}"""
def enc(s): return urllib.parse.quote(s, safe='')
url = f"https://github.com/{repo}/issues/new?title={enc(title)}&body={enc(body)}"
print("Prefilled new-issue URL:")
print(url)
PY
echo
echo "To create locally with GitHub CLI:"
echo "1) Save the following content into body.md"
echo "2) Run: gh issue create --repo \"$REPO\" --title \"$TITLE\" --body-file body.md --assignee \"$REQUESTER\""
echo "-----BEGIN body.md-----"
printf "%s\n" "$BODY"
echo "-----END body.md-----"
fi
Length of output: 0
@tharindu1st The automation environment lacks GH_TOKEN/GITHUB_TOKEN, so I couldn’t create the issue directly. Here’s a ready-to-use command and the full body so you can open it immediately. If you prefer, provide a token in the workflow/runner and I’ll retry and assign it to you automatically.
Title
WebSub: Version-aware deployment transform for 0.5 gateways (Platform API remains 0.6-only)
Body
Summary
- Platform API will accept only WebSub 0.6 payloads (allChannels + per-event wrapper). Deployments must remain compatible with 0.5 gateways.
Context
- See PR `#1948` for the schema refactor to 0.6-only. As noted in the referenced comment, we should not accept 0.5 payloads at the Platform API layer; backward compatibility must be handled only in the deployment path.
Problem
- The current WebSub deployment YAML builder emits the 0.6 structure. 0.5 gateways expect the legacy 0.5 shape, so deployments targeting 0.5 gateways must receive a compatible manifest.
Goal
- Add a version-aware transformation in the deployment path so that:
- When the target gateway is 0.5.x, the emitted manifest uses the legacy top-level and per-event array shapes expected by 0.5 (and omits 0.6-only sections where unsupported).
- When the target gateway is 0.6.0+, emit the 0.6 event-policy structure.
Acceptance criteria
- Detect target gateway version during deployment and select the appropriate manifest shape.
- Unit tests assert both shapes (0.5 vs 0.6) for representative cases (global/all-channels and per-channel event policies).
- No changes to the Platform API OpenAPI are required; it remains 0.6-only.
- Add a brief note in code/docs describing the version-aware behavior.
Backlinks
- PR: https://github.com/wso2/api-platform/pull/1948
- Comment: https://github.com/wso2/api-platform/pull/1948#discussion_r3234750942
Requested by `@tharindu1st` on 2026-05-13.One-liner using GitHub CLI (local)
# Save the body to a file, then create and assign
cat > body.md <<'EOF'
Summary
- Platform API will accept only WebSub 0.6 payloads (allChannels + per-event wrapper). Deployments must remain compatible with 0.5 gateways.
Context
- See PR `#1948` for the schema refactor to 0.6-only. As noted in the referenced comment, we should not accept 0.5 payloads at the Platform API layer; backward compatibility must be handled only in the deployment path.
Problem
- The current WebSub deployment YAML builder emits the 0.6 structure. 0.5 gateways expect the legacy 0.5 shape, so deployments targeting 0.5 gateways must receive a compatible manifest.
Goal
- Add a version-aware transformation in the deployment path so that:
- When the target gateway is 0.5.x, the emitted manifest uses the legacy top-level and per-event array shapes expected by 0.5 (and omits 0.6-only sections where unsupported).
- When the target gateway is 0.6.0+, emit the 0.6 event-policy structure.
Acceptance criteria
- Detect target gateway version during deployment and select the appropriate manifest shape.
- Unit tests assert both shapes (0.5 vs 0.6) for representative cases (global/all-channels and per-channel event policies).
- No changes to the Platform API OpenAPI are required; it remains 0.6-only.
- Add a brief note in code/docs describing the version-aware behavior.
Backlinks
- PR: https://github.com/wso2/api-platform/pull/1948
- Comment: https://github.com/wso2/api-platform/pull/1948#discussion_r3234750942
Requested by `@tharindu1st` on 2026-05-13.
EOF
gh issue create \
--repo wso2/api-platform \
--title "WebSub: Version-aware deployment transform for 0.5 gateways (Platform API remains 0.6-only)" \
--body-file body.md \
--assignee "tharindu1st"Would you like me to retry automated creation if you set GH_TOKEN (repo scope) for the runner? If you create it manually, share the issue URL and I’ll track it from this PR.
🧠 Learnings used
Learnt from: IsuruGunarathne
Repo: wso2/api-platform PR: 1326
File: platform-api/src/resources/openapi.yaml:3159-3176
Timestamp: 2026-03-11T11:08:19.820Z
Learning: In platform-api/src/resources/openapi.yaml, the APIVhost schema intentionally marks main and sandbox optional (no required: [main]). Reviewers should not treat missing main as a schema gap. Ensure server deployment logic preserves existing/default value when Main is nil (deployment.go lines ~213-227). The generated Go type uses Main *string to model optional fields. When reviewing OpenAPI schemas, treat absence of required as an intentional partial override design.
Learnt from: ShalkiWenushika
Repo: wso2/api-platform PR: 1342
File: platform-api/src/resources/openapi.yaml:5055-5062
Timestamp: 2026-03-15T16:50:28.306Z
Learning: Ensure API key expiry logic is explicit in platform-api/src/resources/openapi.yaml and the related platform-api/src/internal/service/apikey.go: 1) expiresAt, if present, takes precedence for expiry. 2) If expiresAt is absent, derive expiry from expiresIn. 3) Enforce mutual exclusivity in the OpenAPI spec for CreateAPIKeyRequest and UpdateAPIKeyRequest using allOf with a not schema, e.g.: allOf: - not: { required: [expiresAt, expiresIn] }. This prevents requests that specify both fields and avoids ambiguity. Add or update CI validation to ensure this pattern is enforced for any future OpenAPI changes.
Learnt from: tharindu1st
Repo: wso2/api-platform PR: 1948
File: platform-api/src/resources/openapi.yaml:0-0
Timestamp: 2026-05-13T18:50:36.592Z
Learning: For WebSub in wso2/api-platform, treat the Platform API schema as 0.6-only: the Platform API layer should not accept legacy 0.5 “policies” payloads. Any backward compatibility with 0.5 gateways must be handled only on the deployment path by using a version-aware manifest/transformation step (e.g., in platform-api deployment code such as websub_api_deployment.go) that converts the 0.6 Platform API definition into a 0.5-compatible gateway manifest. During review, verify the OpenAPI/Platform API contract enforces/targets 0.6 payloads and that compatibility logic exists only in the deployment/version transformation path—not in the Platform API request schema/payload acceptance.
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
platform-api/src/internal/service/websub_api.go (1)
559-575:⚠️ Potential issue | 🟡 Minor | ⚡ Quick win
Policieswrapper is always emitted even when all event fields are nil.
mapWebSubChannelsModelToAPIunconditionally constructs&api.WebSubChannelPolicies{...}for every channel, so a channel with no event policies will still serialize a non-nilpoliciesobject in the API response. Previously such a channel likely omitted the wrapper. If the consumer differentiates between an absent wrapper and an empty one (or relies on optional/omitempty semantics), this is a subtle contract change.Proposed fix
for name, ch := range in { - out[name] = api.WebSubChannel{ - Policies: &api.WebSubChannelPolicies{ - OnSubscription: eventPoliciesToPolicySlicePtr(ch.OnSubscription), - OnUnsubscription: eventPoliciesToPolicySlicePtr(ch.OnUnsubscription), - OnMessageReceived: eventPoliciesToPolicySlicePtr(ch.OnMessageReceived), - OnMessageDelivery: eventPoliciesToPolicySlicePtr(ch.OnMessageDelivery), - }, - } + policies := &api.WebSubChannelPolicies{ + OnSubscription: eventPoliciesToPolicySlicePtr(ch.OnSubscription), + OnUnsubscription: eventPoliciesToPolicySlicePtr(ch.OnUnsubscription), + OnMessageReceived: eventPoliciesToPolicySlicePtr(ch.OnMessageReceived), + OnMessageDelivery: eventPoliciesToPolicySlicePtr(ch.OnMessageDelivery), + } + entry := api.WebSubChannel{} + if policies.OnSubscription != nil || policies.OnUnsubscription != nil || + policies.OnMessageReceived != nil || policies.OnMessageDelivery != nil { + entry.Policies = policies + } + out[name] = entry }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@platform-api/src/internal/service/websub_api.go` around lines 559 - 575, The mapWebSubChannelsModelToAPI function always sets Policies to a non-nil &api.WebSubChannelPolicies, causing an emitted wrapper even when all event policy fields are empty; change it to only assign Policies when at least one of the event policy pointers returned by eventPoliciesToPolicySlicePtr (OnSubscription, OnUnsubscription, OnMessageReceived, OnMessageDelivery) is non-nil/non-empty: call eventPoliciesToPolicySlicePtr for each field into local vars, construct an api.WebSubChannelPolicies value only if any of those vars is non-nil, and set out[name].Policies to its address in that case otherwise leave Policies nil.
🧹 Nitpick comments (5)
platform-api/src/internal/service/websub_api_test.go (1)
34-40: ⚖️ Poor tradeoffEmbedding the repository interface hides missing mock methods at compile time.
mockWebSubAPIRepositoryembedsrepository.WebSubAPIRepository, so any method not explicitly overridden falls through to a nil interface and panics at runtime instead of being caught by the compiler. If a future change toWebSubAPIServicecalls an additional repository method, these tests will compile but fail with a confusing nil-pointer panic. Consider implementing the interface explicitly (one struct method per interface method, even if returning zero values) so the compiler enforces the contract.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@platform-api/src/internal/service/websub_api_test.go` around lines 34 - 40, The mock currently embeds repository.WebSubAPIRepository which hides missing methods and can cause nil-pointer panics; replace the embedding in mockWebSubAPIRepository by removing the embedded interface and explicitly implement every method declared on repository.WebSubAPIRepository on mockWebSubAPIRepository (even if they return zero values or simple store-based behavior), so the compiler enforces the contract; update mockWebSubAPIRepository methods used by WebSubAPIService (and add stubs for any other interface methods) to avoid runtime panics.platform-api/src/internal/service/websub_api_deployment_yaml_test.go (2)
200-211: ⚡ Quick winMove the doc comment for
TestBuildWebSubAPIDeploymentYAML_ChannelDeliveryPolicyParamsonto its own line.The closing brace of
keysOfon line 207 is followed on the same line by the doc comment for the next test, which hurts readability and confuses some IDE/godoc rendering. Insert a blank line between the helper and the next test's comment block.Proposed fix
return keys -} // TestBuildWebSubAPIDeploymentYAML_ChannelDeliveryPolicyParams verifies the +} + +// TestBuildWebSubAPIDeploymentYAML_ChannelDeliveryPolicyParams verifies the // per-channel on_message_delivery set-headers policy and its params are in the YAML.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@platform-api/src/internal/service/websub_api_deployment_yaml_test.go` around lines 200 - 211, The doc comment for TestBuildWebSubAPIDeploymentYAML_ChannelDeliveryPolicyParams is on the same line as the closing brace of keysOf; split them by inserting a blank line so the closing brace of keysOf stands alone and the comment block preceding TestBuildWebSubAPIDeploymentYAML_ChannelDeliveryPolicyParams is on its own line, improving readability and proper godoc/IDE rendering.
145-163: 💤 Low valueSubstring checks for
"channels"and"issues"are too lax.
strings.Contains(yamlStr, "channels")will also match"allChannels", and"issues"could appear in policy names or unrelated string fields. To make the regression intent (per-channel section is actually emitted) more durable, prefer asserting on the unmarshalled structure (as done inTestBuildWebSubAPIDeploymentYAML_ChannelPoliciesNotWrapped) or use a key-anchored substring such as"\nchannels:"/" issues:".🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@platform-api/src/internal/service/websub_api_deployment_yaml_test.go` around lines 145 - 163, The test TestBuildWebSubAPIDeploymentYAML_ChannelPoliciesPresentInYAML uses lax substring checks on yamlStr; update it to assert more robustly that per-channel entries are emitted by either unmarshalling raw into the same struct used in TestBuildWebSubAPIDeploymentYAML_ChannelPoliciesNotWrapped and checking the Channels map contains the "issues" key, or by checking anchored substrings such as "\nchannels:" and a properly indented " issues:" in yamlStr; locate this logic around the yaml.Marshal of d (from buildWebSubAPIDeploymentYAML(buildTestWebSubAPI())) and replace the strings.Contains checks with the stronger unmarshalling or anchored substring assertions.platform-api/src/internal/service/websub_api.go (2)
428-446: ⚡ Quick winUse direct field access instead of stringly-typed event lookup.
policySlicePtrFromChannelPoliciesuses a string switch over event names, which loses compile-time guarantees: a typo (e.g.,"on_msg_received") silently returnsnilwith no diagnostic. Sinceapi.WebSubChannelPoliciesexposes each event as a direct field, the mapping can be expressed without the intermediate helper.Also, lines 434–437 are equivalent to
p := ch.Policies.Proposed refactor
for name, ch := range *in { - var p *api.WebSubChannelPolicies - if ch.Policies != nil { - p = ch.Policies + var on_sub, on_unsub, on_recv, on_deliv *[]api.Policy + if ch.Policies != nil { + on_sub = ch.Policies.OnSubscription + on_unsub = ch.Policies.OnUnsubscription + on_recv = ch.Policies.OnMessageReceived + on_deliv = ch.Policies.OnMessageDelivery } out[name] = model.WebSubChannel{ - OnSubscription: policySlicePtrToEventPolicies(policySlicePtrFromChannelPolicies(p, "on_subscription")), - OnUnsubscription: policySlicePtrToEventPolicies(policySlicePtrFromChannelPolicies(p, "on_unsubscription")), - OnMessageReceived: policySlicePtrToEventPolicies(policySlicePtrFromChannelPolicies(p, "on_message_received")), - OnMessageDelivery: policySlicePtrToEventPolicies(policySlicePtrFromChannelPolicies(p, "on_message_delivery")), + OnSubscription: policySlicePtrToEventPolicies(on_sub), + OnUnsubscription: policySlicePtrToEventPolicies(on_unsub), + OnMessageReceived: policySlicePtrToEventPolicies(on_recv), + OnMessageDelivery: policySlicePtrToEventPolicies(on_deliv), } }The
policySlicePtrFromChannelPolicieshelper at lines 541–556 then becomes dead and can be removed.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@platform-api/src/internal/service/websub_api.go` around lines 428 - 446, mapWebSubChannelsAPIToModel currently uses policySlicePtrFromChannelPolicies with string keys, which is brittle; instead directly read fields from api.WebSubChannelPolicies (e.g., p := ch.Policies) and pass those pointers into policySlicePtrToEventPolicies for each event (OnSubscription, OnUnsubscription, OnMessageReceived, OnMessageDelivery) rather than using string names; simplify the p assignment to p := ch.Policies and remove the now-unused policySlicePtrFromChannelPolicies helper (and any tests/uses) once refactored.
472-495: 💤 Low valueConsolidate the two near-identical
*api.WebSubChannelPolicies→*model.WebSubAllChannelPoliciespaths.
mapWebSubAllChannelPoliciesAPIToModel(input:*api.WebSubAllChannelPolicies) andmapWebSubPoliciesAPIToAllChannels(input:*api.WebSubChannelPolicies) both produce a*model.WebSubAllChannelPoliciesfrom per-event slice pointers and differ only in input type. If the API ever exposes both shapes (or one is removable), consider unifying via a small adapter to reduce future drift. Defer if the dual entry points are intentional.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@platform-api/src/internal/service/websub_api.go` around lines 472 - 495, Both functions mapWebSubAllChannelPoliciesAPIToModel and mapWebSubPoliciesAPIToAllChannels duplicate the construction of a model.WebSubAllChannelPolicies; extract the shared construction into a single helper and have both callers delegate to it. Create a small unexported builder like buildWebSubAllChannelPolicies(onSubscriptionFn, onUnsubscriptionFn, onMessageReceivedFn, onMessageDeliveryFn func() *model.EventPolicies) *model.WebSubAllChannelPolicies and then rewrite mapWebSubAllChannelPoliciesAPIToModel to call the builder with closures that invoke mapEventPoliciesAPIToModel on each input field, and rewrite mapWebSubPoliciesAPIToAllChannels to call the builder with closures that invoke policySlicePtrToEventPolicies on each input field; this removes duplication while keeping the two input-entrypoints.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@platform-api/src/internal/service/websub_api_test.go`:
- Around line 208-218: The test currently fetches ch from
stored.Configuration.Channels but never asserts its contents; either remove the
unused lookup (drop ch and the assignment) or add explicit assertions that the
channel's four event-policy fields are nil to verify the comment ("empty slices
map to nil"). Locate the repo.store["repo-watcher-v1-0"] lookup and the channels
map check, then either (A) delete the ch, _ = ch line and rely on the ok check,
or (B) replace the discard with assertions against ch (e.g., check
ch.EventXPolicy == nil for each policy field used by
policySlicePtrToEventPolicies) so the test verifies the intended mapping
behavior.
In `@platform-api/src/resources/openapi.yaml`:
- Around line 9153-9168: The OpenAPI schema mixes old and new shapes:
WebSubAllChannelPolicies uses WebSubEventPolicies but WebSubChannelPolicies
still exposes raw Policy[] fields, allowing legacy per-channel payloads; update
WebSubChannelPolicies to replace any direct Policy[] event fields with the
WebSubEventPolicies wrapper (the same structure used by WebSubAllChannelPolicies
and defined as WebSubEventPolicies) so the Platform API schema only exposes the
0.6 shape and remove or deprecate the legacy Policy[] fields from
WebSubChannelPolicies; ensure all event refs (e.g., on_subscription,
on_unsubscription, on_message_received, on_message_delivery) in
WebSubChannelPolicies point to $ref: '#/components/schemas/WebSubEventPolicies'
instead of Policy[].
- Around line 9047-9048: The WebSub root schema currently exposes the legacy
top-level field "policies" and points it at WebSubChannelPolicies; replace that
legacy field with the 0.6 canonical top-level field used for all-channel
policies (remove "policies" and add the 0.6 field name) and point it to the
correct 0.6 payload schema instead of WebSubChannelPolicies so the Platform API
emits 0.6-only WebSub payloads; leave any 0.5 compatibility handling to the
deployment/version transformation path.
---
Outside diff comments:
In `@platform-api/src/internal/service/websub_api.go`:
- Around line 559-575: The mapWebSubChannelsModelToAPI function always sets
Policies to a non-nil &api.WebSubChannelPolicies, causing an emitted wrapper
even when all event policy fields are empty; change it to only assign Policies
when at least one of the event policy pointers returned by
eventPoliciesToPolicySlicePtr (OnSubscription, OnUnsubscription,
OnMessageReceived, OnMessageDelivery) is non-nil/non-empty: call
eventPoliciesToPolicySlicePtr for each field into local vars, construct an
api.WebSubChannelPolicies value only if any of those vars is non-nil, and set
out[name].Policies to its address in that case otherwise leave Policies nil.
---
Nitpick comments:
In `@platform-api/src/internal/service/websub_api_deployment_yaml_test.go`:
- Around line 200-211: The doc comment for
TestBuildWebSubAPIDeploymentYAML_ChannelDeliveryPolicyParams is on the same line
as the closing brace of keysOf; split them by inserting a blank line so the
closing brace of keysOf stands alone and the comment block preceding
TestBuildWebSubAPIDeploymentYAML_ChannelDeliveryPolicyParams is on its own line,
improving readability and proper godoc/IDE rendering.
- Around line 145-163: The test
TestBuildWebSubAPIDeploymentYAML_ChannelPoliciesPresentInYAML uses lax substring
checks on yamlStr; update it to assert more robustly that per-channel entries
are emitted by either unmarshalling raw into the same struct used in
TestBuildWebSubAPIDeploymentYAML_ChannelPoliciesNotWrapped and checking the
Channels map contains the "issues" key, or by checking anchored substrings such
as "\nchannels:" and a properly indented " issues:" in yamlStr; locate this
logic around the yaml.Marshal of d (from
buildWebSubAPIDeploymentYAML(buildTestWebSubAPI())) and replace the
strings.Contains checks with the stronger unmarshalling or anchored substring
assertions.
In `@platform-api/src/internal/service/websub_api_test.go`:
- Around line 34-40: The mock currently embeds repository.WebSubAPIRepository
which hides missing methods and can cause nil-pointer panics; replace the
embedding in mockWebSubAPIRepository by removing the embedded interface and
explicitly implement every method declared on repository.WebSubAPIRepository on
mockWebSubAPIRepository (even if they return zero values or simple store-based
behavior), so the compiler enforces the contract; update mockWebSubAPIRepository
methods used by WebSubAPIService (and add stubs for any other interface methods)
to avoid runtime panics.
In `@platform-api/src/internal/service/websub_api.go`:
- Around line 428-446: mapWebSubChannelsAPIToModel currently uses
policySlicePtrFromChannelPolicies with string keys, which is brittle; instead
directly read fields from api.WebSubChannelPolicies (e.g., p := ch.Policies) and
pass those pointers into policySlicePtrToEventPolicies for each event
(OnSubscription, OnUnsubscription, OnMessageReceived, OnMessageDelivery) rather
than using string names; simplify the p assignment to p := ch.Policies and
remove the now-unused policySlicePtrFromChannelPolicies helper (and any
tests/uses) once refactored.
- Around line 472-495: Both functions mapWebSubAllChannelPoliciesAPIToModel and
mapWebSubPoliciesAPIToAllChannels duplicate the construction of a
model.WebSubAllChannelPolicies; extract the shared construction into a single
helper and have both callers delegate to it. Create a small unexported builder
like buildWebSubAllChannelPolicies(onSubscriptionFn, onUnsubscriptionFn,
onMessageReceivedFn, onMessageDeliveryFn func() *model.EventPolicies)
*model.WebSubAllChannelPolicies and then rewrite
mapWebSubAllChannelPoliciesAPIToModel to call the builder with closures that
invoke mapEventPoliciesAPIToModel on each input field, and rewrite
mapWebSubPoliciesAPIToAllChannels to call the builder with closures that invoke
policySlicePtrToEventPolicies on each input field; this removes duplication
while keeping the two input-entrypoints.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 3d07c6e6-6906-485c-bb0d-c01581abcd24
📒 Files selected for processing (7)
platform-api/src/api/generated.goplatform-api/src/internal/model/deployment.goplatform-api/src/internal/service/websub_api.goplatform-api/src/internal/service/websub_api_deployment.goplatform-api/src/internal/service/websub_api_deployment_yaml_test.goplatform-api/src/internal/service/websub_api_test.goplatform-api/src/resources/openapi.yaml
✅ Files skipped from review due to trivial changes (1)
- platform-api/src/api/generated.go
🚧 Files skipped from review as they are similar to previous changes (1)
- platform-api/src/internal/service/websub_api_deployment.go
| policies: | ||
| $ref: '#/components/schemas/WebSubAllChannelPolicies' | ||
| $ref: '#/components/schemas/WebSubChannelPolicies' |
There was a problem hiding this comment.
Use the 0.6 top-level field here.
The root WebSub schema still exposes policies and points it at WebSubChannelPolicies. That leaves the Platform API contract on the legacy field name and the wrong payload shape for all-channel policies.
Suggested fix
- policies:
- $ref: '#/components/schemas/WebSubChannelPolicies'
+ allChannels:
+ $ref: '#/components/schemas/WebSubAllChannelPolicies'Based on learnings, Platform API WebSub payloads must be 0.6-only, and any 0.5 compatibility belongs only in the deployment/version transformation path.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| policies: | |
| $ref: '#/components/schemas/WebSubAllChannelPolicies' | |
| $ref: '#/components/schemas/WebSubChannelPolicies' | |
| allChannels: | |
| $ref: '#/components/schemas/WebSubAllChannelPolicies' |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@platform-api/src/resources/openapi.yaml` around lines 9047 - 9048, The WebSub
root schema currently exposes the legacy top-level field "policies" and points
it at WebSubChannelPolicies; replace that legacy field with the 0.6 canonical
top-level field used for all-channel policies (remove "policies" and add the 0.6
field name) and point it to the correct 0.6 payload schema instead of
WebSubChannelPolicies so the Platform API emits 0.6-only WebSub payloads; leave
any 0.5 compatibility handling to the deployment/version transformation path.
There was a problem hiding this comment.
@tharindu1st Acknowledged—tracking this via #1951. I won’t mark this comment as resolved here.
For #1951, suggested acceptance criteria to close the gap:
- OpenAPI: In platform-api/src/resources/openapi.yaml, replace WebSubAPI.properties.policies with allChannels and point it to
#/components/schemas/WebSubAllChannelPolicies. - Codegen: Regenerate platform-api/src/api/generated.go so WebSubAPI exposes AllChannels with json/yaml tags set to allChannels.
- Service/tests: Adjust WebSub API mapping and unit tests to expect the 0.6 field name on the external contract (update any tests currently asserting “policies” at the root).
- Optional scope check: If
#1951aims for 0.6-only payloads end-to-end, consider aligning WebSubChannel to use the event wrapper object (WebSubEventPolicies) rather than flat arrays.
Would you like me to add this checklist as a comment on #1951 and cross-link this discussion?
🧠 Learnings used
Learnt from: IsuruGunarathne
Repo: wso2/api-platform PR: 1326
File: platform-api/src/resources/openapi.yaml:3159-3176
Timestamp: 2026-03-11T11:08:19.820Z
Learning: In platform-api/src/resources/openapi.yaml, the APIVhost schema intentionally marks main and sandbox optional (no required: [main]). Reviewers should not treat missing main as a schema gap. Ensure server deployment logic preserves existing/default value when Main is nil (deployment.go lines ~213-227). The generated Go type uses Main *string to model optional fields. When reviewing OpenAPI schemas, treat absence of required as an intentional partial override design.
Learnt from: ShalkiWenushika
Repo: wso2/api-platform PR: 1342
File: platform-api/src/resources/openapi.yaml:5055-5062
Timestamp: 2026-03-15T16:50:28.306Z
Learning: Ensure API key expiry logic is explicit in platform-api/src/resources/openapi.yaml and the related platform-api/src/internal/service/apikey.go: 1) expiresAt, if present, takes precedence for expiry. 2) If expiresAt is absent, derive expiry from expiresIn. 3) Enforce mutual exclusivity in the OpenAPI spec for CreateAPIKeyRequest and UpdateAPIKeyRequest using allOf with a not schema, e.g.: allOf: - not: { required: [expiresAt, expiresIn] }. This prevents requests that specify both fields and avoids ambiguity. Add or update CI validation to ensure this pattern is enforced for any future OpenAPI changes.
Learnt from: tharindu1st
Repo: wso2/api-platform PR: 1948
File: platform-api/src/resources/openapi.yaml:0-0
Timestamp: 2026-05-13T18:50:36.592Z
Learning: For WebSub in wso2/api-platform, treat the Platform API schema as 0.6-only: the Platform API layer should not accept legacy 0.5 “policies” payloads. Any backward compatibility with 0.5 gateways must be handled only on the deployment path by using a version-aware manifest/transformation step (e.g., in platform-api deployment code such as websub_api_deployment.go) that converts the 0.6 Platform API definition into a 0.5-compatible gateway manifest. During review, verify the OpenAPI/Platform API contract enforces/targets 0.6 payloads and that compatibility logic exists only in the deployment/version transformation path—not in the Platform API request schema/payload acceptance.
| 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 | ||
| 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: | ||
| $ref: '#/components/schemas/WebSubEventPolicies' | ||
|
|
||
| WebSubEventPolicies: | ||
| type: object | ||
| description: Policies for a single event type. | ||
| properties: | ||
| policies: | ||
| type: array | ||
| description: Policies applied when delivering a message to a subscriber callback URL (e.g., hmac-sign-messages) | ||
| description: List of policies applied for this event type. |
There was a problem hiding this comment.
Finish the wrapper migration for channel event policies.
This adds WebSubEventPolicies for WebSubAllChannelPolicies, but WebSubChannelPolicies still exposes raw Policy[] fields. That leaves API-level and per-channel payloads inconsistent and still accepts the legacy per-channel shape on the Platform API contract.
Suggested fix
WebSubChannelPolicies:
type: object
description: Policies applied to a specific channel, organized by event type.
properties:
on_subscription:
- type: array
- description: Policies applied when a client subscribes to this channel (e.g., rbac)
- items:
- $ref: '#/components/schemas/Policy'
+ $ref: '#/components/schemas/WebSubEventPolicies'
on_unsubscription:
- type: array
- description: Policies applied when a client unsubscribes from this channel
- items:
- $ref: '#/components/schemas/Policy'
+ $ref: '#/components/schemas/WebSubEventPolicies'
on_message_received:
- type: array
- description: Policies applied when a message is received for this channel
- items:
- $ref: '#/components/schemas/Policy'
+ $ref: '#/components/schemas/WebSubEventPolicies'
on_message_delivery:
- type: array
- description: Policies applied when delivering a message for this channel
- items:
- $ref: '#/components/schemas/Policy'
+ $ref: '#/components/schemas/WebSubEventPolicies'Based on learnings, Platform API WebSub payloads must be 0.6-only, and any 0.5 compatibility belongs only in the deployment/version transformation path.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@platform-api/src/resources/openapi.yaml` around lines 9153 - 9168, The
OpenAPI schema mixes old and new shapes: WebSubAllChannelPolicies uses
WebSubEventPolicies but WebSubChannelPolicies still exposes raw Policy[] fields,
allowing legacy per-channel payloads; update WebSubChannelPolicies to replace
any direct Policy[] event fields with the WebSubEventPolicies wrapper (the same
structure used by WebSubAllChannelPolicies and defined as WebSubEventPolicies)
so the Platform API schema only exposes the 0.6 shape and remove or deprecate
the legacy Policy[] fields from WebSubChannelPolicies; ensure all event refs
(e.g., on_subscription, on_unsubscription, on_message_received,
on_message_delivery) in WebSubChannelPolicies point to $ref:
'#/components/schemas/WebSubEventPolicies' instead of Policy[].
There was a problem hiding this comment.
0.6.0 have two spec versions . due to deployment complexity we kept 0.6.0 old spec support.
There was a problem hiding this comment.
@tharindu1st Understood. If we’re keeping the legacy 0.6.0 per-channel arrays for now, let’s make the contract explicit and consistent so clients aren’t surprised:
- Use a oneOf that prefers the new wrapper (WebSubEventPolicies) but still accepts the legacy array, with the array branch marked deprecated.
- Apply that oneOf to both API-level and per-channel event fields to avoid mixing shapes.
- Also, WebSubAPI.policies should point to WebSubAllChannelPolicies (not WebSubChannelPolicies).
Proposed minimal changes:
diff --git a/platform-api/src/resources/openapi.yaml b/platform-api/src/resources/openapi.yaml
@@
components:
schemas:
@@
WebSubAPI:
type: object
properties:
@@
- policies:
- $ref: '#/components/schemas/WebSubChannelPolicies'
+ policies:
+ $ref: '#/components/schemas/WebSubAllChannelPolicies'
@@
WebSubAllChannelPolicies:
type: object
description: Policies applied to all channels, organized by event type.
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'
+ on_subscription:
+ $ref: '#/components/schemas/WebSubEventPolicyList'
+ on_unsubscription:
+ $ref: '#/components/schemas/WebSubEventPolicyList'
+ on_message_received:
+ $ref: '#/components/schemas/WebSubEventPolicyList'
+ on_message_delivery:
+ $ref: '#/components/schemas/WebSubEventPolicyList'
@@
WebSubEventPolicies:
type: object
description: Policies for a single event type.
properties:
policies:
type: array
description: List of policies applied for this event type.
items:
$ref: '#/components/schemas/Policy'
+
+ # Back-compat helper: prefer wrapper, accept legacy array (deprecated)
+ WebSubPolicyArray:
+ type: array
+ description: Legacy array form accepted for backward compatibility (0.6.0-legacy).
+ deprecated: true
+ items:
+ $ref: '#/components/schemas/Policy'
+
+ WebSubEventPolicyList:
+ oneOf:
+ - $ref: '#/components/schemas/WebSubEventPolicies' # preferred (0.6.0-new)
+ - $ref: '#/components/schemas/WebSubPolicyArray' # legacy (deprecated)
+ description: Accepts wrapper or legacy array; wrapper is preferred.
@@
WebSubChannelPolicies:
type: object
description: Policies applied to a specific channel, organized by event type.
properties:
- on_subscription:
- type: array
- description: Policies applied when a client subscribes to this channel (e.g., rbac)
- items:
- $ref: '#/components/schemas/Policy'
- on_unsubscription:
- type: array
- description: Policies applied when a client unsubscribes from this channel
- items:
- $ref: '#/components/schemas/Policy'
- on_message_received:
- type: array
- description: Policies applied when a message is received for this channel
- items:
- $ref: '#/components/schemas/Policy'
- on_message_delivery:
- type: array
- description: Policies applied when delivering a message for this channel
- items:
- $ref: '#/components/schemas/Policy'
+ on_subscription:
+ $ref: '#/components/schemas/WebSubEventPolicyList'
+ on_unsubscription:
+ $ref: '#/components/schemas/WebSubEventPolicyList'
+ on_message_received:
+ $ref: '#/components/schemas/WebSubEventPolicyList'
+ on_message_delivery:
+ $ref: '#/components/schemas/WebSubEventPolicyList'Notes
- Lines 9154–9168 currently wrap only the API-level events; the change above makes both API-level and per-channel events uniform while retaining legacy acceptance.
- If you prefer to keep API-level strict (wrapper-only) but accept legacy only at the per-channel level, I can scope the oneOf to WebSubChannelPolicies only—just confirm.
- If helpful, I can open a follow-up issue to remove the legacy array branch after deployment complexity is reduced. Want me to file it and tag you?
I’ll also update our reviewer knowledge to reflect that for PR #1948 we intentionally accept both shapes at the Platform API level during this transition.
✏️ Learnings added
Learnt from: tharindu1st
Repo: wso2/api-platform PR: 1948
File: platform-api/src/resources/openapi.yaml:9153-9168
Timestamp: 2026-05-13T19:06:58.554Z
Learning: Repo: wso2/api-platform PR: 1948
Learning: For WebSub in Platform API (PR `#1948`), the team intentionally supports both 0.6.0 “wrapper” (WebSubEventPolicies) and legacy per-channel Policy[] shapes temporarily due to deployment complexity. The OpenAPI should express this via oneOf for event fields (preferred wrapper, deprecated array), and WebSubAPI.policies should reference WebSubAllChannelPolicies. A follow-up issue can track removal of the legacy branch.
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
🧠 Learnings used
Learnt from: IsuruGunarathne
Repo: wso2/api-platform PR: 1326
File: platform-api/src/resources/openapi.yaml:3159-3176
Timestamp: 2026-03-11T11:08:19.820Z
Learning: In platform-api/src/resources/openapi.yaml, the APIVhost schema intentionally marks main and sandbox optional (no required: [main]). Reviewers should not treat missing main as a schema gap. Ensure server deployment logic preserves existing/default value when Main is nil (deployment.go lines ~213-227). The generated Go type uses Main *string to model optional fields. When reviewing OpenAPI schemas, treat absence of required as an intentional partial override design.
Learnt from: ShalkiWenushika
Repo: wso2/api-platform PR: 1342
File: platform-api/src/resources/openapi.yaml:5055-5062
Timestamp: 2026-03-15T16:50:28.306Z
Learning: Ensure API key expiry logic is explicit in platform-api/src/resources/openapi.yaml and the related platform-api/src/internal/service/apikey.go: 1) expiresAt, if present, takes precedence for expiry. 2) If expiresAt is absent, derive expiry from expiresIn. 3) Enforce mutual exclusivity in the OpenAPI spec for CreateAPIKeyRequest and UpdateAPIKeyRequest using allOf with a not schema, e.g.: allOf: - not: { required: [expiresAt, expiresIn] }. This prevents requests that specify both fields and avoids ambiguity. Add or update CI validation to ensure this pattern is enforced for any future OpenAPI changes.
Learnt from: tharindu1st
Repo: wso2/api-platform PR: 1948
File: platform-api/src/resources/openapi.yaml:0-0
Timestamp: 2026-05-13T18:50:36.592Z
Learning: For WebSub in wso2/api-platform, treat the Platform API schema as 0.6-only: the Platform API layer should not accept legacy 0.5 “policies” payloads. Any backward compatibility with 0.5 gateways must be handled only on the deployment path by using a version-aware manifest/transformation step (e.g., in platform-api deployment code such as websub_api_deployment.go) that converts the 0.6 Platform API definition into a 0.5-compatible gateway manifest. During review, verify the OpenAPI/Platform API contract enforces/targets 0.6 payloads and that compatibility logic exists only in the deployment/version transformation path—not in the Platform API request schema/payload acceptance.
There was a problem hiding this comment.
@tharindu1st Acknowledged — we’ll consider removal of the legacy per-channel Policy[] shape tracked via #1951.
Do you want me to:
- keep this PR as-is and defer schema cleanup to
#1951, or - update this PR to make the contract explicit now by:
- using oneOf for each event to accept the wrapper (preferred) or the deprecated array (legacy), and
- pointing WebSubAPI.policies to WebSubAllChannelPolicies?
Either option keeps current clients working; the second clarifies the API surface until #1951 is closed. Let me know your preference.
✏️ Learnings added
Learnt from: tharindu1st
Repo: wso2/api-platform PR: 1948
File: platform-api/src/resources/openapi.yaml:9153-9168
Timestamp: 2026-05-13T19:19:58.330Z
Learning: Repo: wso2/api-platform (PR `#1948`). For WebSub Platform API, temporary support for the legacy 0.6 per‑channel Policy[] shape will remain; its removal is tracked in GitHub issue `#1951`. Prefer the wrapper (WebSubEventPolicies). When proposing changes, ensure backward compatibility until `#1951` is resolved.
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
🧠 Learnings used
Learnt from: IsuruGunarathne
Repo: wso2/api-platform PR: 1326
File: platform-api/src/resources/openapi.yaml:3159-3176
Timestamp: 2026-03-11T11:08:19.820Z
Learning: In platform-api/src/resources/openapi.yaml, the APIVhost schema intentionally marks main and sandbox optional (no required: [main]). Reviewers should not treat missing main as a schema gap. Ensure server deployment logic preserves existing/default value when Main is nil (deployment.go lines ~213-227). The generated Go type uses Main *string to model optional fields. When reviewing OpenAPI schemas, treat absence of required as an intentional partial override design.
Learnt from: ShalkiWenushika
Repo: wso2/api-platform PR: 1342
File: platform-api/src/resources/openapi.yaml:5055-5062
Timestamp: 2026-03-15T16:50:28.306Z
Learning: Ensure API key expiry logic is explicit in platform-api/src/resources/openapi.yaml and the related platform-api/src/internal/service/apikey.go: 1) expiresAt, if present, takes precedence for expiry. 2) If expiresAt is absent, derive expiry from expiresIn. 3) Enforce mutual exclusivity in the OpenAPI spec for CreateAPIKeyRequest and UpdateAPIKeyRequest using allOf with a not schema, e.g.: allOf: - not: { required: [expiresAt, expiresIn] }. This prevents requests that specify both fields and avoids ambiguity. Add or update CI validation to ensure this pattern is enforced for any future OpenAPI changes.
Learnt from: tharindu1st
Repo: wso2/api-platform PR: 1948
File: platform-api/src/resources/openapi.yaml:0-0
Timestamp: 2026-05-13T18:50:36.592Z
Learning: For WebSub in wso2/api-platform, treat the Platform API schema as 0.6-only: the Platform API layer should not accept legacy 0.5 “policies” payloads. Any backward compatibility with 0.5 gateways must be handled only on the deployment path by using a version-aware manifest/transformation step (e.g., in platform-api deployment code such as websub_api_deployment.go) that converts the 0.6 Platform API definition into a 0.5-compatible gateway manifest. During review, verify the OpenAPI/Platform API contract enforces/targets 0.6 payloads and that compatibility logic exists only in the deployment/version transformation path—not in the Platform API request schema/payload acceptance.
change the spec to support 0.5.0 and 0.6.0