Skip to content

Sharing rules created at runtime don't bind their hooks until restart (bindRuleHooks is boot-only) #2592

Description

@os-zhuang

Summary

A sharing rule created at runtime for an object that had no sharing rule at boot never binds its enforcement hook, so it silently does not take effect until the next restart. The rule definitions are read live (enforcement is correct once a hook fires) — the gap is that hook binding is boot-only, and the create trigger is a data write, so the #2576 metadata:reloaded path doesn't even apply here.

Found in the post-#2576 boot-cached-consumer audit. NOTE: not yet runtime-verified (code analysis; high confidence) — worth a quick repro before fixing.

Evidence

  • packages/plugins/plugin-sharing/src/sharing-plugin.ts:201bindRuleHooks(engine, ruleService, rules, ...) is called once at boot (kernel:ready) with the rules that existed then. It registers insert/update hooks only for the objects that had a rule at that moment.
  • Rule evaluation reads rules live from sys_sharing_rule on each hook fire (sharing-rule-service.tsgetRule/evaluateAllForRecord), so enforcement itself is not stale.
  • But sharing rules are data rows (sys_sharing_rule), authored via a data write (defineRule / POST /data/sys_sharing_rule), not a metadata publish. So metadata:reloaded never fires for a new rule — the flow-pattern rebind wouldn't trigger.
  • Result: create the first sharing rule for object X at runtime → no hook was ever bound for X → the rule never evaluates until restart. (Rules for objects that already had ≥1 rule at boot are fine.)

Impact

priority:p2, security — access-control correctness: an admin adds a record-sharing rule expecting it to restrict/grant visibility, and it silently no-ops until a reboot. Narrow (only the object-had-no-rule-at-boot edge) but security-relevant.

Proposed fix

Give the sharing plugin a data-change trigger on sys_sharing_rule (after insert/update/delete) that re-runs the bind: unbind all rule hooks + bindRuleHooks with the fresh listRules() (mirrors boot; enforcement already reads live so no teardown-of-definitions concern). This is a different mechanism from metadata:reloaded because the source is data, not metadata. Verify with a member-user E2E (create a rule at runtime for a fresh object → sharing takes effect without restart).

Companion to the hooks (#2588) and i18n runtime-authoring gaps.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingpriority:p2Medium: important, M3security

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions