/** * Organization-scoped workspace-policy gate — the parallel of * `enforceEnvironmentPolicy` for `brand`, `brief`, and `campaign`. * * Background: the workspace policy was originally environment-scoped * because every guarded path acted on an XM Cloud environment. The org- * scoped product surface (brand kits, briefs, campaigns, documents, * pipeline, review) is keyed by Sitecore organization, not environment, * so `enforceEnvironmentPolicy` doesn't bind it — `resolveOrganization` * historically returned the orgId with no allowlist check. That meant a * caller with an enrolled `brand[orgId]` credential could retarget any * orgId at will. Closed 2026-05-21. * * Two modes: * * - Strict (`workspacePolicy.strictOrgs: true`) — the orgId MUST be * in `workspacePolicy.organizations`. Mirrors env-scoped enrollment. * - Lenient (default) — the orgId is considered enrolled if either * (a) it's in `workspacePolicy.organizations`, or (b) any enrolled * env profile carries the same `organizationId`. Lets existing * policy files keep working without a manual migration: env * enrollment transitively enrolls its org. * * The repo policy (`scai.policy.json`) may narrow but not widen — same * shape as the env layer: `allowOrganizations` is an intersect, and * `organizations[orgId].ceiling` may only lower the user-global ceiling. */ import type { OrgIdentity, RiskTier } from "./types.js"; /** The resolved org-policy verdict. Mirrors `EffectivePolicy` for envs. */ export interface EffectiveOrganizationPolicy { /** False when no user-global policy file exists — "unmanaged mode". */ managed: boolean; /** Whether the org is on the effective (layered) allowlist. */ enrolled: boolean; /** Effective ceiling — the intersection of user-global and repo layers. */ ceiling: RiskTier; /** Pinned identity, or `null` when the org is not enrolled. */ identity: OrgIdentity | null; /** Phase 2 — whether `setup client register-brand` may mint here. */ mintCredentials: boolean; /** Phase 2 — whether a CI caller may write/destructive here. */ ciWrites: boolean; /** Phase 3 — freshness window (minutes) for destructive/mint ops. */ stepUpMinutes: number | undefined; /** * How enrollment was satisfied: an explicit `organizations[orgId]` * entry (`"explicit"`), or the lenient fall-through where an enrolled * env profile carrying this orgId implies enrollment (`"transitive"`). * `null` when not enrolled. Surfaced by `scai access check` so the * operator can see whether to add an explicit entry before flipping * `strictOrgs: true`. */ enrolledVia: "explicit" | "transitive" | null; } /** Compute the effective org-policy verdict. Sync, mirrors `resolveEffectivePolicy`. */ export declare const resolveEffectiveOrganizationPolicy: (orgId: string, configRootDir?: string) => EffectiveOrganizationPolicy; export interface EnforceOrganizationPolicyParams { orgId: string; /** Directory holding `sitecoreai.cli.json`; enables repo-policy narrowing. */ configRootDir?: string; } /** * Throws `POLICY_DENIED` when the organization is not on the workspace- * policy allowlist. A no-op in unmanaged mode. * * Called from `resolveOrganization` so every CLI / SDK / MCP surface * routes through it. */ export declare const enforceOrganizationPolicy: (params: EnforceOrganizationPolicyParams) => void;