Skip to content

fix: emit confirm-publish events with permission-aware subscriber fanout - #735

Draft
xiaoyaner0201 wants to merge 1 commit into
iflytek:mainfrom
xiaoyaner0201:20260819-skillhub-731-confirm-publish-event-publication-r1
Draft

fix: emit confirm-publish events with permission-aware subscriber fanout#735
xiaoyaner0201 wants to merge 1 commit into
iflytek:mainfrom
xiaoyaner0201:20260819-skillhub-731-confirm-publish-event-publication-r1

Conversation

@xiaoyaner0201

Copy link
Copy Markdown

Summary

  • emit SkillPublishedEvent after confirmPublish persists the published version and latest skill version
  • apply purpose-aware, current metadata-read eligibility before publish/yank subscriber fanout
  • fail closed on stale membership, inactive accounts/namespaces, cross-namespace state, or authoritative lookup failures

Fixes #731.

Why

The confirm-publish path currently updates persistence without reaching the existing subscriber listener. For PRIVATE skills, fanout also needs to re-check current read eligibility so removed or stale subscribers do not receive recipient-visible metadata.

Validation

  • Backend tests passed
  • Frontend typecheck/build passed — not applicable; no frontend files changed
  • OpenAPI SDK regenerated or checked when API contracts changed — not applicable; no API contract changed
  • Smoke test run when relevant — not run; no operator-facing workflow changed

Commands and results:

exact listener → eligibility → dispatcher → Notification persistence/SSE sink probe: 8 passed
authorization and compatibility suite: domain 76, notification 4, app 49; 0 failures/errors/skips
full reactor: 1,400 tests, 0 failures/errors; 1 existing Redis-cluster environment skip
git diff --check: passed

Risk

  • User-facing impact: subscribers receive confirm-publish and yank notifications only while they retain current metadata-read eligibility
  • Deployment or migration impact: none; no schema or API migration
  • Rollback approach: revert this commit to restore the previous event and fanout behavior

Limits

Not exercised against production infrastructure, a real browser EventSource client, or a configured Redis cluster. The synchronous production listener/eligibility/dispatcher path and final persistence/SSE arguments are covered.

Notes

@CLAassistant

CLAassistant commented Aug 20, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

Signed-off-by: 千乘妍 (Xiaoyaner) <258399167+xiaoyaner0201@users.noreply.github.com>
@xiaoyaner-multica-leader
xiaoyaner-multica-leader Bot force-pushed the 20260819-skillhub-731-confirm-publish-event-publication-r1 branch from d72f461 to e071afb Compare August 20, 2026 03:00

@FenjuFu FenjuFu left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deep-reviewed against #731 and the repo's visibility model. The core fix is correct and the extra hardening is well thought through — a few actionable points below.

Core fix (resolves #731): confirmPublish now publishes SkillPublishedEvent after persisting the PUBLISHED version and latestVersionId, so NotificationEventListener#onSkillPublishedForSubscribers is finally reached — consistent with the autoPublish branch in SkillPublishService.

On the recipient filtering: I initially flagged that the issue's scenario (a regular namespace member subscribing to a PRIVATE skill and expecting a notification) is at odds with SubscriptionMetadataAccessPolicy returning owner || manager for PRIVATE. After checking docs/oss-02-core-semantic-rules.md, the canonical read model is PRIVATE -> owner only, not marketplace-visible, so the original "member gets notified" behavior was itself fail-open. Filtering non-eligible subscribers is the correct call, and allowing manager (ADMIN/OWNER) is a reasonable governance extension. The batch account/member loading (findByIdIn / findByNamespaceIdAndUserIdIn) avoids an N+1 in the async fan-out. Good.

Points worth addressing / a maintainer decision:

  1. Missing i18n key. subscribe() throws new DomainForbiddenException("error.skill.subscription.noPermission"), but I don't see that key added to messages.properties / messages_zh.properties (the diff is Java-only). ApiResponseFactory resolves via getMessage(code, args, code, locale), so this degrades to showing the raw code rather than a 500 — not fatal, but existing forbidden keys (e.g. error.namespace.membership.required) are registered, so please add EN/zh entries for consistency.

  2. subscribe() is now a behavior change on a public endpoint. Previously PUT /skills/{id}/subscription succeeded for any existing skill; it now returns 403 for users without current read access, and existing regular-member subscriptions to PRIVATE/NAMESPACE_ONLY skills will be silently filtered out of all future notifications. That's the right hardening, but it's a maintainer call whether a one-time prune/migration of now-ineligible skill_subscription rows is wanted so the DB state matches the new policy.

  3. Fail-closed on a null namespace. In the listener, namespaceRepository.findById(...).orElse(null) feeding an eligibility check that denies when namespace == null means a namespace-load hiccup silently drops the whole fan-out. Safe by default, but a debug/warn log there would make such a case diagnosable rather than invisible.

Only DCO has reported so far — worth waiting for the backend build/test job before merge so the new listener/policy tests are confirmed green in CI. Correctness and design look right to me; leaving the merge and the policy/migration decision to the maintainers.

@XiaoSeS

XiaoSeS commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator

Thanks for the PR. The narrow #731 regression has now been fixed by #738, which is merged into main.

The broader permission-aware subscriber fanout in this PR is still valuable, but it should be handled as a separate authorization hardening change rather than bundled with the confirmPublish event fix.

Please keep this PR open as draft/design work, rebase it on latest main, remove the already-merged confirmPublish change, and narrow the scope to:

  1. reject subscription creation when the current user cannot read the skill metadata;
  2. filter subscriber notifications using the current visibility/access rules at fanout time;
  3. reuse the existing VisibilityChecker or a shared access policy instead of introducing a parallel visibility model;
  4. add the missing i18n message and tests for private, namespace-only, hidden, removed-member, and disabled-user cases.

We should not close this PR, but it is not mergeable as-is.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] confirmPublish does not emit SkillPublishedEvent, so subscribers get no update notification

4 participants