Skip to content

feat(marketplace): typed allow-list gate with open-to-everyone toggle#8484

Closed
LWS49 wants to merge 11 commits into
lws49/feat-marketplace-pr5-previewfrom
lws49/feat-marketplace-pra-allowlist
Closed

feat(marketplace): typed allow-list gate with open-to-everyone toggle#8484
LWS49 wants to merge 11 commits into
lws49/feat-marketplace-pr5-previewfrom
lws49/feat-marketplace-pra-allowlist

Conversation

@LWS49

@LWS49 LWS49 commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator

Summary

Marketplace visibility is currently all-or-nothing, which blocks a staged rollout. This PR gates the marketplace behind a global typed allow-list: course managers/owners only see it if a rule matches them (specific user, whole instance, or email domain), while system administrators always retain access. It adds a self-serve System::Admin page to manage the rules, and a deliberate, reversible "open to everyone" mode that opens the marketplace to all course managers everywhere in one action without discarding the scoped rules built up during the staged rollout.

Design decisions

  • Rules live in one global (non tenant-scoped) table with a typed rule_type enum (user / instance / email_domain / everyone) - a single pool keeps administration in one place, and instance rules still scope per-instance naturally because the match goes through user.instance_users, which is tenant-scoped at query time
  • "Open to everyone" is a fourth rule type rather than a separate settings flag - enable inserts one everyone row, disable deletes it, so scoped rules survive a temporary opening untouched and the existing create/destroy endpoints are reused with no new routes
  • The admin page surfaces everyone-mode as a page-level banner + toggle instead of a fourth table row - while open, the scoped table renders dimmed with add/delete disabled, making both the active mode and its reversibility obvious at a glance
  • At most one everyone row, enforced by a model uniqueness validation paired with a partial unique DB index

Regression prevention

  • Model specs cover: per-type presence validations, the single-everyone-rule constraint, and grants_access? matching for user rules, instance rules (including per-instance scoping under the current tenant), case-insensitive email-domain rules, the everyone rule, and nil-user denial
  • Controller specs cover: the visibility gate (manager denied without a matching rule, allowed with one or under everyone, sysadmin bypass with zero rules, students still denied even under everyone), admin CRUD, everyone-mode JSON reporting (everyoneRuleId, everyone row excluded from the scoped list), and rejection of a second everyone rule with 400
  • Frontend tests cover: the rules table and add/delete flows, the open-to-everyone and restrict confirm flows (request payloads and banner copy transitions), and disabled add/delete controls while open
  • Manually tested end to end: gate hidden for non-allow-listed managers (sidebar and direct URL), each rule type granting access, per-instance scoping, sysadmin bypass, students never gaining access, admin page CRUD and empty state, open-to-everyone and restrict round trip with scoped rules preserved, and double-open rejection
  • Behaviour change for existing users is intentional: managers lose marketplace access until allow-listed (or the marketplace is opened to everyone); system administrators are unaffected

@LWS49
LWS49 marked this pull request as draft July 16, 2026 07:40
LWS49 added 6 commits July 16, 2026 15:49
InstanceUser is acts_as_tenant-scoped, so the instance_users subquery in
grants_access? only sees the current tenant: an instance rule grants that
instance's users access while browsing it, not membership-based access
everywhere. The model comment claimed the opposite; fix it and add a
characterization spec for the cross-instance case.
@LWS49 LWS49 changed the title feat(marketplace): gate access behind a typed allow-list feat(marketplace): typed allow-list gate with open-to-everyone toggle Jul 17, 2026
@LWS49

LWS49 commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator Author

Superseded by #8485 — same work, branch renamed to lws49/feat-marketplace-pr6-allowlist and rebased onto lws49/feat-marketplace-pr5b-misc.

@LWS49 LWS49 closed this Jul 17, 2026
@LWS49
LWS49 deleted the lws49/feat-marketplace-pra-allowlist branch July 17, 2026 03:30
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.

1 participant