/**
 * OperatorRoles -- User-level RBAC for governance operations.
 *
 * Three roles: ADMIN, OPERATOR, VIEWER
 *   - ADMIN: Full access (configure, approve, modify governance)
 *   - OPERATOR: Run agents, view logs, submit approvals
 *   - VIEWER: Read-only access to logs and reports
 *
 * Required by:
 *   - HIPAA 164.312(a)(1): Access control
 *   - SOC 2 CC6.1: Logical access
 *   - ISO 27001 A.9.2: User access management
 *   - PCI DSS Req 7: Restrict access by business need
 *
 * @connexum/ai-governance
 */
import { ensureDir, loadJson, saveJson } from '../util/fs.js';
import { createLogger } from '../util/log.js';
import * as path from 'path';
import * as crypto from 'crypto';
const log = createLogger('operator-roles');
/** Actions each role can perform */
const ROLE_PERMISSIONS = {
    ADMIN: new Set([
        'governance.configure',
        'governance.rotate-secret',
        'governance.update-hash',
        'governance.export-manifest',
        'governance.import-manifest',
        'operators.create',
        'operators.delete',
        'operators.modify',
        'operators.list',
        'approval.resolve',
        'approval.submit',
        'approval.view',
        'agents.start',
        'agents.stop',
        'agents.configure',
        'audit.view',
        'audit.export',
        'audit.verify',
        'incidents.create',
        'incidents.update',
        'incidents.view',
        'retention.enforce',
        'retention.configure',
        'packs.activate',
        'packs.deactivate',
        'packs.configure',
        'reports.generate',
        'reports.view',
        'memory.deanonymize',
        'memory.early-delete',
    ]),
    OPERATOR: new Set([
        'operators.list',
        'approval.submit',
        'approval.view',
        'agents.start',
        'agents.stop',
        'audit.view',
        'audit.verify',
        'incidents.create',
        'incidents.update',
        'incidents.view',
        'reports.generate',
        'reports.view',
    ]),
    VIEWER: new Set([
        'operators.list',
        'approval.view',
        'audit.view',
        'incidents.view',
        'reports.view',
    ]),
};
export class OperatorRoles {
    config;
    operators = new Map();
    sessions = new Map();
    operatorsFile;
    constructor(config) {
        this.config = {
            sessionTimeoutMs: 600000, // 10 min (DEV MODE -- production: 900000 / 15min HIPAA)
            ...config,
        };
        ensureDir(config.operatorsDir);
        this.operatorsFile = path.join(config.operatorsDir, 'operators.json');
        this.loadOperators();
    }
    /**
     * Create a new operator.
     */
    createOperator(name, role, metadata) {
        const operator = {
            id: `op_${crypto.randomBytes(6).toString('hex')}`,
            name,
            role,
            createdAt: new Date().toISOString(),
            active: true,
            metadata,
        };
        this.operators.set(operator.id, operator);
        this.saveOperators();
        log.info(`Operator created: ${operator.id} (${name}, ${role})`);
        return operator;
    }
    /**
     * Get an operator by ID.
     */
    getOperator(operatorId) {
        return this.operators.get(operatorId) || null;
    }
    /**
     * List all operators.
     */
    listOperators() {
        return Array.from(this.operators.values());
    }
    /**
     * Update an operator's role.
     */
    updateRole(operatorId, newRole) {
        const operator = this.operators.get(operatorId);
        if (!operator)
            throw new Error(`Operator ${operatorId} not found`);
        const oldRole = operator.role;
        operator.role = newRole;
        this.saveOperators();
        log.info(`Role changed: ${operatorId} ${oldRole} -> ${newRole}`);
        return operator;
    }
    /**
     * Deactivate an operator.
     */
    deactivate(operatorId) {
        const operator = this.operators.get(operatorId);
        if (!operator)
            throw new Error(`Operator ${operatorId} not found`);
        operator.active = false;
        this.saveOperators();
        log.info(`Operator deactivated: ${operatorId}`);
    }
    /**
     * Start a session for an operator. Returns session token.
     */
    startSession(operatorId) {
        const operator = this.operators.get(operatorId);
        if (!operator)
            throw new Error(`Operator ${operatorId} not found`);
        if (!operator.active)
            throw new Error(`Operator ${operatorId} is deactivated`);
        const token = crypto.randomBytes(32).toString('hex');
        this.sessions.set(token, {
            operatorId,
            startedAt: Date.now(),
        });
        operator.lastActiveAt = new Date().toISOString();
        this.saveOperators();
        return token;
    }
    /**
     * Validate a session token. Returns operator ID if valid.
     */
    validateSession(token) {
        const session = this.sessions.get(token);
        if (!session)
            return null;
        // Check timeout
        if (Date.now() - session.startedAt > this.config.sessionTimeoutMs) {
            this.sessions.delete(token);
            return null;
        }
        return session.operatorId;
    }
    /**
     * End a session.
     */
    endSession(token) {
        this.sessions.delete(token);
    }
    /**
     * Check if an operator has permission to perform an action.
     */
    checkPermission(operatorId, action) {
        const operator = this.operators.get(operatorId);
        if (!operator) {
            return { allowed: false, operator: operatorId, role: 'VIEWER', action, reason: 'Operator not found' };
        }
        if (!operator.active) {
            return { allowed: false, operator: operatorId, role: operator.role, action, reason: 'Operator is deactivated' };
        }
        const permissions = ROLE_PERMISSIONS[operator.role];
        const allowed = permissions.has(action);
        return {
            allowed,
            operator: operatorId,
            role: operator.role,
            action,
            reason: allowed ? 'Permitted' : `Role '${operator.role}' does not have '${action}' permission`,
        };
    }
    /**
     * Get all permissions for a role.
     */
    getRolePermissions(role) {
        return Array.from(ROLE_PERMISSIONS[role]);
    }
    /**
     * Get active session count.
     */
    getActiveSessionCount() {
        // Prune expired
        const now = Date.now();
        for (const [token, session] of this.sessions) {
            if (now - session.startedAt > this.config.sessionTimeoutMs) {
                this.sessions.delete(token);
            }
        }
        return this.sessions.size;
    }
    // --- Private ---
    saveOperators() {
        try {
            saveJson(this.operatorsFile, Array.from(this.operators.values()));
        }
        catch (err) {
            log.error(`Failed to save operators: ${err.message}`);
        }
    }
    loadOperators() {
        const data = loadJson(this.operatorsFile);
        if (data && Array.isArray(data)) {
            for (const op of data) {
                this.operators.set(op.id, op);
            }
        }
    }
}
//# sourceMappingURL=operator-roles.js.map