Skip to content

SharingRuleService.reconcile aborts a rule's whole pass when one grant is refused by the engine's system-write organization rule — that rule's stale revocations stay undone (residue of #14484) #14754

Description

@os-project-manager

Filed by the director seat (objectstack #12708, summon #10, session session_01ShyhexkB2d1AeRZ85tgAAe) out of the contract review of PR #14726 (#14484). The PR discloses this shape itself (changeset paragraph "(a)"); it is carried here as the follow-up rather than blocking the landing, for the reasons in the review verdict. domain:services, pm:queue, S.

The shape

After #14484, sys_record_share is tenant-scoped in the #13491 ledger, so an organization-less system insert on it is refused loudly on a walled install (ERR_SYSTEM_WRITE_ORGANIZATION_REQUIRED). SharingService.grant resolves the organization on every path that can, but two paths resolve none:

  • a platform-global sharing rule (organization_id = null; its sweep runs unscoped) materialising a grant on an organization-less record;
  • a direct grant whose read of the shared record's organization failed (deliberately not substituted with the acting session's, the review's blocking fix).

On the rule path, SharingRuleService.reconcile / reconcileForRecord has no per-grant catch: the refusal propagates and that rule's reconcile aborts mid-loop. Grants already written in the pass stay; the remaining grants and the stale-row revocations of that pass do not happen. The boot backfill logs the rule and continues to the next; the write hooks catch so a user write is never failed.

Why it is a card

The revocation half is the security-relevant half: a stale over-grant of that rule persists across every pass that meets the same organization-less record, and that record keeps aborting the pass until it is repaired. The shape needs three things at once (walled install, platform-global rule, organization-less record in a tenant-scoped object), and the organization-less population is the one #13491 / #13564 are draining, so it is narrow; but it is reachable on existing walled deployments today (cloud#1232 measured organization-less rows), and before #14484 those passes completed (writing NULL rows). It is loud (logged), not silent, which is why it did not block the review.

What to build

Clause-② no (no accept-set change; a loop keeps going instead of aborting). @objectstack/plugin-sharing changeset patch.

Related: #14484 (the ruling), PR #14726 (the landing and its changeset paragraph (a)), #13491 (the ledger), #13564 (the reads), objectstack #12708 (director seat ledger).

Activity

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions