import { Injectable } from '@nestjs/common'; import { AbilityBuilder, createMongoAbility, subject, type ForcedSubject, type MongoAbility } from '@casl/ability'; /** * Nivel de risc pentru unelte AI/agenti (Hermes MCP), portat din modelul de * capabilitati risk-stratified al Open.Jarvis (github.com/dmrr35/Open.Jarvis, * open_jarvis/plugins/permissions.py) -- roluri non-admin primesc implicit * doar unelte low/medium, high/critical raman rezervate owner/admin. */ export type AgentToolRiskLevel = 'low' | 'medium' | 'high' | 'critical'; export interface AgentToolDefinition { name: string; riskLevel: AgentToolRiskLevel; description: string; } /** Forma exacta produsa de `subject('AgentTool', toolDefinition)` -- vezi canInvokeAgentTool. */ type AgentToolInstance = AgentToolDefinition & ForcedSubject<'AgentTool'>; export type Action = 'manage' | 'create' | 'read' | 'update' | 'delete' | 'invoke'; export type Subject = | 'Organization' | 'Transaction' | 'Document' | 'Membership' | 'AgentTool' | AgentToolInstance | 'all'; export type AppAbility = MongoAbility<[Action, Subject]>; export type MembershipRole = 'owner' | 'admin' | 'member'; export interface MembershipContext { tenantId: string; role: MembershipRole; } /** * Registrul uneltelor AI expuse prin Hermes (namespace MetaMCP 'ceo-os-endpoint'). * `name` trebuie sa corespunda exact numelui serverului MCP raportat de * `hermes mcp test` -- vezi project_supersrv_new_server.md pentru lista live. */ export const AGENT_TOOL_REGISTRY: readonly AgentToolDefinition[] = [ { name: 'economic-data', riskLevel: 'low', description: 'World Bank/ECB/Eurostat/FRED/OECD, stiri, IP/domeniu lookups', }, { name: 'capability-reasoning', riskLevel: 'low', description: 'Potrivire ocupatii/skill-uri ESCO pentru "ce poate/nu poate face agentul"', }, { name: 'legislation-search', riskLevel: 'medium', description: 'Cautare semantica in legislatia UK/DE/RO -- informativ, nu consultanta juridica', }, ]; const DEFAULT_ROLE_INVOKABLE_RISK_LEVELS: readonly AgentToolRiskLevel[] = ['low', 'medium']; /** * Traduce rolul de membership (blueprint 8.3: memberships.role) intr-un set de * permisiuni CASL. Regulile sunt intentionat minimale -- se extind per bounded * context pe masura ce apar entitati noi (11.1 "roles si ABAC policies"). */ @Injectable() export class AbilityFactory { createForMembership(membership: MembershipContext): AppAbility { const { can, build } = new AbilityBuilder(createMongoAbility); if (membership.role === 'owner' || membership.role === 'admin') { can('manage', 'all'); } else { can('read', 'all'); can(['create', 'update'], ['Transaction', 'Document']); can('invoke', 'AgentTool', { riskLevel: { $in: [...DEFAULT_ROLE_INVOKABLE_RISK_LEVELS] } }); } return build(); } } /** * Verifica daca o abilitate poate invoca o unealta AI dupa nume. Nume necunoscute * (absente din AGENT_TOOL_REGISTRY) sunt respinse implicit -- acelasi deny-by-default * ca `require_plugin_permission()` din Open.Jarvis. */ export function canInvokeAgentTool(ability: AppAbility, toolName: string): boolean { const toolDefinition = AGENT_TOOL_REGISTRY.find((tool) => tool.name === toolName); if (!toolDefinition) { return false; } return ability.can('invoke', subject('AgentTool', toolDefinition)); }