/**
 * Workspace-scoped RBAC for multi-tenant team-tier substrate.
 *
 * Six canonical workspace roles map to discrete permission sets.
 * These roles are workspace-scoped and distinct from the org-level
 * Role enum in packages/auth/src/rbac.ts (ORG_ADMIN, ORG_VIEWER, etc.).
 *
 * New permissions added here that did not exist in packages/auth/src/rbac.ts:
 *   WORKSPACE_ADMIN, POLICY_WRITE, POLICY_READ, REVIEW_APPROVE,
 *   REVIEW_DECLINE, BILLING_READ, BILLING_WRITE, MEMBER_INVITE,
 *   MEMBER_SUSPEND.
 *
 * Design rule: Owner has every permission. All other roles are additive
 * subsets -- never full-inherit to avoid privilege creep.
 *
 * @connexum/ai-governance tenant substrate
 */
// ---------------------------------------------------------------------------
// WorkspacePermission enum
// ---------------------------------------------------------------------------
export var WorkspacePermission;
(function (WorkspacePermission) {
    // Workspace administration
    WorkspacePermission["WORKSPACE_ADMIN"] = "workspace:admin";
    // Policy management
    WorkspacePermission["POLICY_WRITE"] = "policy:write";
    WorkspacePermission["POLICY_READ"] = "policy:read";
    // Review actions
    WorkspacePermission["REVIEW_APPROVE"] = "review:approve";
    WorkspacePermission["REVIEW_DECLINE"] = "review:decline";
    // Billing
    WorkspacePermission["BILLING_READ"] = "billing:read";
    WorkspacePermission["BILLING_WRITE"] = "billing:write";
    // Member management
    WorkspacePermission["MEMBER_INVITE"] = "member:invite";
    WorkspacePermission["MEMBER_SUSPEND"] = "member:suspend";
    // Agent registry + scanning (developer surface)
    WorkspacePermission["AGENT_READ"] = "agent:read";
    WorkspacePermission["SCAN_RUN"] = "scan:run";
    // Audit reads
    WorkspacePermission["AUDIT_READ"] = "audit:read";
    // Pack reads (compliance-officer surface)
    WorkspacePermission["PACK_READ"] = "pack:read";
})(WorkspacePermission || (WorkspacePermission = {}));
// ---------------------------------------------------------------------------
// ROLE_PERMISSIONS: the canonical permission map
// ---------------------------------------------------------------------------
/**
 * Strictest-wins policy still applies here: a workspace-scoped role
 * CANNOT grant permissions the org-level role forbids. Enforcement
 * of org-level caps is done at the route layer (decodeClaims + this map).
 */
export const WORKSPACE_ROLE_PERMISSIONS = {
    /**
     * owner: full control over the workspace they created.
     */
    owner: [
        WorkspacePermission.WORKSPACE_ADMIN,
        WorkspacePermission.POLICY_WRITE,
        WorkspacePermission.POLICY_READ,
        WorkspacePermission.REVIEW_APPROVE,
        WorkspacePermission.REVIEW_DECLINE,
        WorkspacePermission.BILLING_READ,
        WorkspacePermission.BILLING_WRITE,
        WorkspacePermission.MEMBER_INVITE,
        WorkspacePermission.MEMBER_SUSPEND,
        WorkspacePermission.AGENT_READ,
        WorkspacePermission.SCAN_RUN,
        WorkspacePermission.AUDIT_READ,
        WorkspacePermission.PACK_READ,
    ],
    /**
     * compliance-officer: reads packs, reads policy, approves reviews,
     * reads audit trail. No billing, no member management, no policy writes.
     */
    'compliance-officer': [
        WorkspacePermission.PACK_READ,
        WorkspacePermission.POLICY_READ,
        WorkspacePermission.REVIEW_APPROVE,
        WorkspacePermission.AUDIT_READ,
        WorkspacePermission.AGENT_READ,
    ],
    /**
     * security-admin: manages members, writes policy, reads audit.
     * No billing, no review-approve (conflict-of-interest), no billing writes.
     */
    'security-admin': [
        WorkspacePermission.MEMBER_INVITE,
        WorkspacePermission.MEMBER_SUSPEND,
        WorkspacePermission.POLICY_WRITE,
        WorkspacePermission.POLICY_READ,
        WorkspacePermission.AUDIT_READ,
        WorkspacePermission.PACK_READ,
        WorkspacePermission.AGENT_READ,
        WorkspacePermission.SCAN_RUN,
    ],
    /**
     * reviewer: approve and decline reviews only.
     * Cannot touch members, policy, or billing.
     */
    reviewer: [
        WorkspacePermission.REVIEW_APPROVE,
        WorkspacePermission.REVIEW_DECLINE,
    ],
    /**
     * developer: reads agent registry and can run scans.
     * No policy writes, no member management, no billing.
     */
    developer: [
        WorkspacePermission.AGENT_READ,
        WorkspacePermission.SCAN_RUN,
        WorkspacePermission.PACK_READ,
    ],
    /**
     * billing-admin: billing reads and writes only.
     * No access to audit, agents, policies, or member management.
     */
    'billing-admin': [
        WorkspacePermission.BILLING_READ,
        WorkspacePermission.BILLING_WRITE,
    ],
};
// ---------------------------------------------------------------------------
// Helper: check permission for a workspace role
// ---------------------------------------------------------------------------
export function hasWorkspacePermission(role, permission) {
    const perms = WORKSPACE_ROLE_PERMISSIONS[role];
    if (!perms)
        return false;
    return perms.includes(permission);
}
/**
 * Look up the caller's membership in the workspace and verify they hold
 * at least the required role. Returns the claims or throws with a 403 message.
 *
 * Usage at route layer:
 *   const claims = requireRole(memberStore, workspaceId, userId, 'owner');
 *
 * Throws WorkspaceAuthError on access denied.
 */
export function requireRole(member, requiredRole) {
    if (!member || member.status !== 'active') {
        throw new WorkspaceAuthError('Workspace membership required', 403);
    }
    // owner always passes
    if (member.role === 'owner') {
        return { userId: member.userId, workspaceId: member.workspaceId, role: member.role };
    }
    if (member.role !== requiredRole) {
        throw new WorkspaceAuthError(`Requires role '${requiredRole}', caller has '${member.role}'`, 403);
    }
    return { userId: member.userId, workspaceId: member.workspaceId, role: member.role };
}
/**
 * Check that the caller's workspace role includes the specified permission.
 * Throws WorkspaceAuthError (403) if not.
 */
export function requirePermission(member, permission) {
    if (!member || member.status !== 'active') {
        throw new WorkspaceAuthError('Workspace membership required', 403);
    }
    if (!hasWorkspacePermission(member.role, permission)) {
        throw new WorkspaceAuthError(`Permission '${permission}' required, role '${member.role}' does not have it`, 403);
    }
    return { userId: member.userId, workspaceId: member.workspaceId, role: member.role };
}
// ---------------------------------------------------------------------------
// Error class
// ---------------------------------------------------------------------------
export class WorkspaceAuthError extends Error {
    statusCode;
    constructor(message, statusCode = 403) {
        super(message);
        this.name = 'WorkspaceAuthError';
        this.statusCode = statusCode;
    }
}
//# sourceMappingURL=rbac.js.map