Skip to content

feat(organizations): cross-product sites listing via sites:list:cross_product scope (SITES-46454)#2607

Draft
ravverma wants to merge 3 commits into
mainfrom
feat/sites-list-cross-product-scope
Draft

feat(organizations): cross-product sites listing via sites:list:cross_product scope (SITES-46454)#2607
ravverma wants to merge 3 commits into
mainfrom
feat/sites-list-cross-product-scope

Conversation

@ravverma

@ravverma ravverma commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Summary

Phase 1 of multi-product login support (SITES-46453). GET /organizations/{organizationId}/sites now consults authInfo.hasScope('sites:list:cross_product'). When the scope is present (minted by spacecat-auth-service at login for allow-listed IMS client_ids; surfaced as a first-class AuthInfo scope by spacecat-shared-http-utils JwtHandler), the own-sites filter is widened from a single x-product to a union across every product the org is entitled to, deduped by site id.

The entitlement, tier-visibility (CUSTOMER_VISIBLE_TIERS), and enrollment gates are preserved per-product — only the single-product restriction is dropped. Sites the org has no entitlement to under any product never appear; PRE_ONBOARD-tier sites stay hidden from non-admins.

The delegated-sites flow is unchanged — it stays product-pinned to x-product (which therefore remains required by the route signature). SiteDto.toJSON is unchanged.

Companion PRs (must release first):

  • spacecat-shared — JWT handler fan-out (PR)
  • spacecat-auth-service — login-time scope minting (PR)

Design ADR: adobe/mysticat-architecture#139
Jira: SITES-46454 (parent: SITES-46453)

What changed

  • src/controllers/organizations.jsgetSitesForOrganization: branch on the scope, call new helper, union with dedupe.
  • src/support/utils.js: new getEntitledProductCodes(context, organization) helper next to filterSitesForProductCode. Pure read; iterates EntitlementModel.PRODUCT_CODES via TierClient.

Containment

Only this controller consults sites:list:cross_product. The literal string appears in exactly two places in this repo (controller + test) plus the auth-service mint site and the jwt.js namespace constants. Enforced by code review on the allow-list; any new caller of the scope requires an ADR update.

Test plan

  • npx mocha test/controllers/organizations.test.js test/support/utils.test.js — 203 passing
  • Lint clean
  • OpenAPI valid
  • Merge order: this PR waits on the spacecat-shared-http-utils release (will bump the dep version in a follow-up commit before merge).
  • Disclosure sign-off captured before ship.

🤖 Generated with Claude Code

…_product scope (SITES-46454)

Phase 1 of multi-product login support. GET /organizations/{id}/sites
now consults authInfo.hasScope('sites:list:cross_product'). When the
scope is present (minted by spacecat-auth-service at login time for
allow-listed IMS client_ids; surfaced as a first-class AuthInfo scope
by spacecat-shared-http-utils JwtHandler), the own-sites filter is
widened from a single x-product to a union across every product the
org is entitled to, deduped by site id.

The entitlement, tier-visibility (CUSTOMER_VISIBLE_TIERS), and
enrollment gates are preserved per-product — we drop only the
single-product restriction. Sites the org has no entitlement to under
any product never appear; PRE_ONBOARD-tier sites stay hidden from
non-admins.

The delegated-sites flow is unchanged — it stays product-pinned to
x-product (which therefore remains required by the route signature).
SiteDto.toJSON is unchanged.

New getEntitledProductCodes(context, organization) helper in
src/support/utils.js next to filterSitesForProductCode. Pure read,
iterates EntitlementModel.PRODUCT_CODES via TierClient.

Design ADR: adobe/mysticat-architecture#139
Jira: SITES-46454

Tests:
- only sites enrolled under entitled products are returned
- union across multiple entitled products, deduped by site id
- empty list when org has no entitlements
- PRE_ONBOARD tier hidden from non-admin (tier-visibility gate preserved)
- single-product behaviour unchanged when scope is absent
- getEntitledProductCodes helper covers zero / single / multiple
  entitled-product cases

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@codecov

codecov Bot commented Jun 15, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@github-actions

Copy link
Copy Markdown

This PR will trigger a minor release when merged.

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