// engine/rbac/permission-checker.ts — Permission enforcement logic for SPEC-166
import { roleHasPermission } from './roles.js';
// ---------------------------------------------------------------------------
// Permission check
// ---------------------------------------------------------------------------
/**
 * Check whether a user is allowed to perform an action on a resource.
 *
 * When RBAC is disabled (default single-user mode) this is always a no-op
 * that returns allowed=true — preserving backward compatibility.
 *
 * Resolution order:
 *   1. RBAC disabled → allow
 *   2. Find spec-scoped assignment (most specific)
 *   3. Find project-level assignment
 *   4. No assignment found → deny
 */
export function checkPermission(config, userId, action, resource, specId) {
    // No-op when RBAC is not enabled
    if (!config.enabled) {
        return { allowed: true, reason: 'RBAC disabled — single-user mode' };
    }
    const role = resolveRole(config, userId, specId);
    if (!role) {
        const result = {
            allowed: false,
            reason: `User "${userId}" has no role assignment for this project${specId ? ` or spec "${specId}"` : ''}.`,
        };
        return result;
    }
    const allowed = roleHasPermission(role, action);
    return {
        allowed,
        role,
        reason: allowed
            ? `Role "${role}" is permitted to perform "${action}" on "${resource}".`
            : `Role "${role}" is not permitted to perform "${action}" on "${resource}".`,
    };
}
// ---------------------------------------------------------------------------
// Role resolution
// ---------------------------------------------------------------------------
/**
 * Resolve the effective role for a user.
 * Spec-scoped assignments take precedence over project-level assignments.
 */
export function resolveRole(config, userId, specId) {
    const assignments = config.assignments.filter((a) => a.userId === userId);
    // 1. Spec-scoped (most specific)
    if (specId) {
        const specAssignment = assignments.find((a) => a.specId === specId);
        if (specAssignment) {
            return specAssignment.role;
        }
    }
    // 2. Project-level (no specId)
    const projectAssignment = assignments.find((a) => !a.specId);
    return projectAssignment?.role;
}
// ---------------------------------------------------------------------------
// Audit log entry builder
// ---------------------------------------------------------------------------
export function buildAuditEntry(userId, action, resource, result, specId) {
    return {
        timestamp: new Date().toISOString(),
        userId,
        action,
        resource,
        specId,
        result: result.allowed ? 'allowed' : 'denied',
        role: result.role,
    };
}
//# sourceMappingURL=permission-checker.js.map