@mastra/core
Version:
1,503 lines • 57.7 kB
JavaScript
const require_rolldown_runtime = require("./rolldown-runtime-uwYp4b74.cjs");
let crypto = require("crypto");
let os = require("os");
os = require_rolldown_runtime.__toESM(os, 1);
//#region ../_internals/auth/dist/capabilities-ZXD8uYsD.js
function hashTelemetryValue(value) {
return (0, crypto.createHash)("sha256").update(value).digest("hex");
}
function getHashedHostname() {
return hashTelemetryValue(os.default.hostname() || "unknown-host").slice(0, 16);
}
function getEETelemetryFallbackDistinctId() {
return `mastra-${getHashedHostname()}`;
}
const EE_TELEMETRY_BRIDGE = Symbol.for("mastra.eeTelemetryBridge");
function getTelemetryBridge() {
return globalThis[EE_TELEMETRY_BRIDGE];
}
function captureEEEvent(event, distinctId, properties) {
getTelemetryBridge()?.captureEEEvent?.(event, distinctId, properties);
}
/**
* License validation for EE features.
*
* Validation is delegated to the Mastra license server via `LicenseClient`
* (POST {MASTRA_LICENSE_URL}/validate). The client validates in the
* background and caches the result; the synchronous helpers in this module
* read the cached state:
*
* - No license key configured → EE features disabled.
* - Key configured, validation pending → fail open (features enabled) until
* the first server response settles the state.
* - Server says invalid/revoked/expired → EE features disabled.
* - Server unreachable → fail open with a 72h grace period for previously
* validated licenses.
*
* `MASTRA_LICENSE_KEY` is the primary env var; `MASTRA_EE_LICENSE` is a
* supported legacy alias.
*/
var LicenseClient = class LicenseClient {
static instance;
logger;
licenseKey;
licenseUrl;
mode = "open-source";
status = "pending";
cachedResult = null;
cacheExpiry = 0;
gracePeriodEnd = 0;
revalidationTimeout = null;
GRACE_PERIOD_MS = 4320 * 60 * 1e3;
DEFAULT_TTL_MS = 1440 * 60 * 1e3;
constructor(logger) {
this.logger = logger;
this.licenseKey = process.env.MASTRA_LICENSE_KEY || process.env.MASTRA_EE_LICENSE;
this.licenseUrl = process.env.MASTRA_LICENSE_URL || "https://license.mastra.ai";
if (this.licenseKey) this.mode = "enterprise";
else this.mode = "open-source";
}
static getInstance(logger) {
if (!LicenseClient.instance) LicenseClient.instance = new LicenseClient(logger);
else if (logger) LicenseClient.instance.logger = logger;
return LicenseClient.instance;
}
/**
* Reset the singleton so the next getInstance() re-reads env vars.
* Intended for tests.
*/
static resetInstance() {
if (LicenseClient.instance?.revalidationTimeout) clearTimeout(LicenseClient.instance.revalidationTimeout);
LicenseClient.instance = void 0;
}
REQUEST_TIMEOUT_MS = 1e4;
async fetchWithRetry(url, options, retries = 3) {
for (let i = 0; i < retries; i++) {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), this.REQUEST_TIMEOUT_MS);
timer.unref?.();
try {
const signal = options.signal ? AbortSignal.any([options.signal, controller.signal]) : controller.signal;
const response = await fetch(url, {
...options,
signal
});
if (response.status === 429 || response.status >= 500) {
if (i === retries - 1) return response;
} else return response;
} catch (error) {
if (i === retries - 1) throw error;
} finally {
clearTimeout(timer);
}
const delay = Math.pow(2, i) * 1e3;
await new Promise((resolve) => setTimeout(resolve, delay));
}
throw new Error("Unreachable");
}
validationPromise = null;
async validate() {
if (this.mode === "open-source") return true;
if (this.cachedResult && Date.now() < this.cacheExpiry) return true;
return this.revalidate();
}
/**
* Contact the server regardless of cache freshness, coalescing concurrent
* callers (e.g. the Mastra constructor and the auth/ee helpers both kicking
* off validation at startup) into a single in-flight request so the server
* is contacted — and the outcome logged — only once. Used directly by the
* background revalidation timer, which must bypass the cache check.
*/
revalidate() {
if (!this.validationPromise) this.validationPromise = this.performValidation().finally(() => {
this.validationPromise = null;
});
return this.validationPromise;
}
async performValidation() {
const now = Date.now();
try {
if (!this.licenseUrl?.startsWith("https://") && !this.licenseUrl?.includes("localhost")) this.logger?.warn("License URL is not HTTPS. Proceeding, but this is insecure.");
const response = await this.fetchWithRetry(`${this.licenseUrl}/validate`, {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ licenseKey: this.licenseKey })
});
if (response.status === 429 || response.status >= 500) throw new Error(`License server responded with ${response.status}`);
const data = await response.json();
if (data.valid) {
this.status = "valid";
this.logger?.info(`License validated: ${data.planTier} tier${data.expiresAt ? `, expires ${data.expiresAt.slice(0, 10)}` : ""}`);
this.cachedResult = data;
const ttlSeconds = data.leaseTtlSeconds || this.DEFAULT_TTL_MS / 1e3;
this.cacheExpiry = now + ttlSeconds * 1e3;
this.gracePeriodEnd = now + this.GRACE_PERIOD_MS;
this.scheduleRevalidation(ttlSeconds);
return true;
} else if (data.code === "RATE_LIMITED") throw new Error(`License server rate limited: ${data.reason}`);
else {
this.status = "invalid";
this.logger?.error(`License validation failed: ${data.code} - ${data.reason}`);
this.clearCache();
return false;
}
} catch {
if (this.cachedResult && now < this.gracePeriodEnd) {
this.logger?.warn("License server unreachable. Using cached license (within grace period).");
this.status = "valid";
this.scheduleRevalidation(this.DEFAULT_TTL_MS / 1e3);
return true;
} else if (this.cachedResult) {
this.logger?.error("License server unreachable and grace period expired. Disabling enterprise features.");
this.status = "invalid";
this.clearCache();
return false;
} else {
this.logger?.warn("License server unreachable on startup. Failing open (allowing features) and will retry.");
this.status = "valid";
this.cachedResult = {
valid: true,
entitlements: [],
planTier: "unknown",
expiresAt: null,
leaseTtlSeconds: 300
};
this.cacheExpiry = now + 300 * 1e3;
this.gracePeriodEnd = now + this.GRACE_PERIOD_MS;
this.scheduleRevalidation(300);
return true;
}
}
}
scheduleRevalidation(ttlSeconds) {
if (this.revalidationTimeout) clearTimeout(this.revalidationTimeout);
const revalidateMs = ttlSeconds * 1e3 * .75;
this.revalidationTimeout = setTimeout(() => {
this.logger?.info("Performing background license revalidation...");
this.revalidate().catch((err) => {
this.logger?.error(`Background license revalidation failed: ${err instanceof Error ? err.message : String(err)}`);
});
}, revalidateMs);
this.revalidationTimeout.unref();
}
clearCache() {
this.cachedResult = null;
this.cacheExpiry = 0;
this.gracePeriodEnd = 0;
this.status = "invalid";
if (this.revalidationTimeout) {
clearTimeout(this.revalidationTimeout);
this.revalidationTimeout = null;
}
}
hasFeature(featureName) {
if (this.mode === "open-source") return true;
if (this.status === "pending") return true;
if (this.status === "invalid") return false;
if (!this.cachedResult) return false;
if (this.cachedResult.planTier === "unknown") return true;
return this.cachedResult.entitlements.includes(featureName);
}
getEntitlements() {
if (this.mode === "open-source") return null;
return this.cachedResult?.entitlements || null;
}
getSnapshot() {
return {
mode: this.mode,
status: this.status,
entitlements: this.cachedResult?.entitlements ?? null,
planTier: this.cachedResult?.planTier ?? null,
expiresAt: this.cachedResult?.expiresAt ?? null
};
}
};
/**
* Resolve the configured license key.
* `MASTRA_LICENSE_KEY` is primary; `MASTRA_EE_LICENSE` is a supported legacy alias.
*/
function getLicenseKey() {
return process.env["MASTRA_LICENSE_KEY"] || process.env["MASTRA_EE_LICENSE"];
}
let validationStarted = false;
let hasWarnedAboutDevLicense = false;
/**
* Get the shared LicenseClient and kick off background validation on first use.
*/
function getClient() {
const client = LicenseClient.getInstance();
if (!validationStarted) {
validationStarted = true;
client.validate().catch(() => {});
}
return client;
}
/**
* Start license validation against the license server.
*
* Safe to call multiple times — the underlying client caches results and
* schedules its own background revalidation. Resolves to whether the license
* is currently considered valid.
*/
function startLicenseValidation() {
const client = LicenseClient.getInstance();
validationStarted = true;
return client.validate();
}
/**
* Validate the configured license and return license information.
*
* Reflects the current server-backed validation state. The actual network
* validation happens in the background via `LicenseClient`, and only the
* configured key (env var) is ever validated — passing any other key
* returns invalid.
*
* @param licenseKey - Optional key to check; must match the configured key.
* @returns License information
*/
function validateLicense(licenseKey) {
const configuredKey = getLicenseKey();
if (!(licenseKey ?? configuredKey)) return { valid: false };
if (licenseKey !== void 0 && licenseKey !== configuredKey) return { valid: false };
const snap = getClient().getSnapshot();
return {
valid: snap.status !== "invalid",
features: snap.entitlements ?? void 0,
tier: snap.planTier ?? void 0,
expiresAt: snap.expiresAt ? new Date(snap.expiresAt) : void 0
};
}
/**
* Check if EE features are enabled (valid or pending server validation).
*
* @returns True if EE features should be enabled
*/
function isLicenseValid() {
if (!getLicenseKey()) return false;
return getClient().getSnapshot().status !== "invalid";
}
/**
* @deprecated Use `isLicenseValid()` instead. This alias is provided for backward compatibility.
*/
const isEELicenseValid = isLicenseValid;
/**
* Check if a specific EE feature is enabled by the license entitlements.
*
* @param feature - Feature name to check (e.g. 'rbac', 'fga', 'sso')
* @returns True if the feature is enabled
*/
function isFeatureEnabled(feature) {
if (!getLicenseKey()) return false;
return getClient().hasFeature(feature);
}
function getSafeLicenseSummary() {
const key = getLicenseKey();
const info = validateLicense(key);
const licenseHash = key ? hashTelemetryValue(key) : void 0;
return {
valid: info.valid,
isDevEnvironment: isDevEnvironment(),
licenseHash: licenseHash ? licenseHash.slice(0, 16) : void 0,
anonymousId: licenseHash ? `${licenseHash.slice(0, 16)}-anonymous` : void 0,
features: info.features,
tier: info.tier
};
}
function warnIfDevEENeedsLicense() {
if (hasWarnedAboutDevLicense || !isDevEnvironment() || isLicenseValid()) return;
hasWarnedAboutDevLicense = true;
console.warn("[mastra/auth-ee] Mastra Enterprise features are enabled for local development, but no valid MASTRA_LICENSE_KEY is configured. These features will be disabled in production without a valid license. Contact us to get a production license: https://mastra.ai/contact");
}
/**
* Clear the license cache (useful for testing).
* Resets the shared client so the next check re-reads env vars.
*/
function clearLicenseCache() {
validationStarted = false;
hasWarnedAboutDevLicense = false;
LicenseClient.resetInstance();
}
/**
* Check if running in a development/testing environment.
* In dev, EE features work without a license per the ee/LICENSE terms.
*/
function isDevEnvironment() {
return process.env["MASTRA_DEV"] === "true" || process.env["MASTRA_DEV"] === "1" || process.env["NODE_ENV"] !== "production" && process.env["NODE_ENV"] !== "prod";
}
/**
* Check if EE features should be active.
* Returns true if running in dev/test environment (always allowed) or if a valid license is present.
*/
function isEEEnabled() {
if (isDevEnvironment()) {
warnIfDevEENeedsLicense();
return true;
}
return isLicenseValid();
}
/**
* Type guard to check if response is authenticated.
*/
function isAuthenticated(caps) {
return "user" in caps && caps.user !== null;
}
/**
* Check if an auth provider implements a specific interface.
*/
function implementsInterface(auth, method) {
return auth !== null && typeof auth === "object" && typeof auth[method] === "function";
}
/**
* Check if auth provider is MastraCloudAuth (exempt from license requirement).
*/
function isMastraCloudAuth(auth) {
if (!auth || typeof auth !== "object") return false;
return "isMastraCloudAuth" in auth && auth.isMastraCloudAuth === true;
}
/**
* Check if auth provider is SimpleAuth (exempt from license requirement).
* SimpleAuth is for development/testing and should work without a license.
*/
function isSimpleAuth(auth) {
if (!auth || typeof auth !== "object") return false;
return "isSimpleAuth" in auth && auth.isSimpleAuth === true;
}
/**
* Check if a set of permissions includes admin bypass (`*` or `*:*`).
*/
function hasAdminBypassPermissions(permissions) {
return permissions.some((p) => p === "*" || p === "*:*");
}
function getRequestIp(request) {
const forwardedFor = request.headers.get("x-forwarded-for");
if (forwardedFor) return forwardedFor.split(",")[0]?.trim();
return request.headers.get("x-real-ip") ?? void 0;
}
function captureLicenseCheck({ request, user, hasLicense, isDev, isCloud, isSimple, capabilities }) {
const license = getSafeLicenseSummary();
try {
const ip = getRequestIp(request);
captureEEEvent("ee_license_check", user?.id || license.anonymousId || getEETelemetryFallbackDistinctId(), {
license_valid: hasLicense,
license_hash: license.licenseHash,
is_dev_environment: isDev,
is_cloud: isCloud,
is_simple_auth: isSimple,
capabilities,
user_id: user?.id,
$ip: ip,
license_features: license.features,
license_tier: license.tier
});
} catch {}
}
/**
* Build capabilities response based on auth configuration and request state.
*
* This function determines what capabilities are available and, if the user
* is authenticated, includes their user info and access permissions.
*
* @param auth - Auth provider (or null if no auth configured)
* @param request - Incoming HTTP request
* @param options - Optional configuration (roleMapping, etc.)
* @returns Capabilities response (public or authenticated)
*/
async function buildCapabilities(auth, request, options) {
if (!auth) return {
enabled: false,
login: null
};
const hasLicense = isLicenseValid();
const isCloud = isMastraCloudAuth(auth);
const isSimple = isSimpleAuth(auth);
const isDev = isDevEnvironment();
if (isDev && !hasLicense) warnIfDevEENeedsLicense();
const isLicensedOrCloud = hasLicense || isCloud || isSimple || isDev;
const isFeatureLicensed = (feature) => isCloud || isSimple || isDev || hasLicense && isFeatureEnabled(feature);
let login = null;
const hasSSO = implementsInterface(auth, "getLoginUrl") && isLicensedOrCloud;
const hasCredentials = implementsInterface(auth, "signIn") && isLicensedOrCloud;
const raw = (options?.apiPrefix || "/api").trim();
const withSlash = raw.startsWith("/") ? raw : `/${raw}`;
const ssoLoginUrl = `${withSlash.endsWith("/") ? withSlash.slice(0, -1) : withSlash}/auth/sso/login`;
let signUpEnabled = true;
if (implementsInterface(auth, "signIn")) {
const credentialsProvider = auth;
if (typeof credentialsProvider.isSignUpEnabled === "function") signUpEnabled = credentialsProvider.isSignUpEnabled();
}
if (hasSSO && hasCredentials) {
const ssoConfig = auth.getLoginButtonConfig();
login = {
type: "both",
signUpEnabled,
description: ssoConfig.description,
sso: {
...ssoConfig,
url: ssoLoginUrl
}
};
} else if (hasSSO) {
const ssoConfig = auth.getLoginButtonConfig();
login = {
type: "sso",
description: ssoConfig.description,
sso: {
...ssoConfig,
url: ssoLoginUrl
}
};
} else if (hasCredentials) login = {
type: "credentials",
signUpEnabled
};
let user = null;
if (implementsInterface(auth, "getCurrentUser") && isLicensedOrCloud) try {
user = await auth.getCurrentUser(request);
} catch {
user = null;
}
if (!user) {
captureLicenseCheck({
request,
user,
hasLicense,
isDev,
isCloud,
isSimple
});
return {
enabled: true,
login
};
}
const rbacProvider = options?.rbac;
const hasRBAC = !!rbacProvider && isFeatureLicensed("rbac");
const hasFGA = !!options?.fga && isFeatureLicensed("fga");
const capabilities = {
user: implementsInterface(auth, "getCurrentUser") && isLicensedOrCloud,
session: implementsInterface(auth, "createSession") && isLicensedOrCloud,
sso: implementsInterface(auth, "getLoginUrl") && isLicensedOrCloud,
rbac: hasRBAC,
acl: implementsInterface(auth, "canAccess") && isFeatureLicensed("acl"),
fga: hasFGA
};
let access = null;
if (hasRBAC && rbacProvider) try {
const roles = await rbacProvider.getRoles(user);
const permissions = await rbacProvider.getPermissions(user);
access = {
roles,
permissions
};
const license = getSafeLicenseSummary();
try {
const ip = getRequestIp(request);
captureEEEvent("ee_feature_used", user.id || license.anonymousId || getEETelemetryFallbackDistinctId(), {
feature: "rbac",
user_id: user.id,
organization_membership_id: user.metadata?.["organizationMembershipId"],
role_count: roles.length,
permission_count: permissions.length,
$ip: ip,
license_valid: license.valid,
license_hash: license.licenseHash,
is_dev_environment: license.isDevEnvironment
});
} catch {}
} catch {
access = null;
}
let availableRoles;
if (access && rbacProvider?.getAvailableRoles) {
if (hasAdminBypassPermissions(access.permissions)) try {
const allRoles = await rbacProvider.getAvailableRoles();
const getPermissionsForRole = rbacProvider.getPermissionsForRole?.bind(rbacProvider);
if (getPermissionsForRole) availableRoles = (await Promise.allSettled(allRoles.map(async (role) => ({
role,
perms: await getPermissionsForRole(role.id)
})))).flatMap((result) => {
if (result.status !== "fulfilled") {
console.warn("[auth/ee] failed to list permissions for role:", result.reason);
return [];
}
return hasAdminBypassPermissions(result.value.perms) ? [] : [result.value.role];
});
else availableRoles = allRoles;
} catch (error) {
console.warn("[auth/ee] failed to list available roles for admin user:", error);
}
}
captureLicenseCheck({
request,
user,
hasLicense,
isDev,
isCloud,
isSimple,
capabilities
});
return {
enabled: true,
login,
user: {
id: user.id,
email: user.email,
name: user.name,
avatarUrl: user.avatarUrl
},
capabilities,
access,
availableRoles
};
}
//#endregion
//#region ../_internals/auth/dist/ee-DXvSoTl7.js
/**
* AUTO-GENERATED FILE - DO NOT EDIT DIRECTLY
*
* This file is generated by packages/server/scripts/generate-permissions.ts
* Run `pnpm generate:permissions` from packages/server to regenerate.
*
* Source of truth: SERVER_ROUTES in @mastra/server
*/
/**
* All known API resources.
* Derived from SERVER_ROUTES paths in @mastra/server.
*/
const RESOURCES = [
"a2a",
"agent-builder",
"agent-controller",
"agents",
"auth",
"background-tasks",
"channels",
"datasets",
"embedders",
"experiments",
"infrastructure",
"logs",
"mcp",
"memory",
"observability",
"processor-providers",
"processors",
"schedules",
"scores",
"stored-agents",
"stored-mcp-clients",
"stored-prompt-blocks",
"stored-scorers",
"stored-skills",
"stored-workflows",
"stored-workspaces",
"system",
"tool-providers",
"tools",
"vector",
"vectors",
"workflows",
"workspaces"
];
/**
* All permission actions.
* Derived from HTTP methods and route overrides:
* - GET → read
* - POST → write or execute (context-dependent)
* - PUT/PATCH → write
* - DELETE → delete
* - Additional actions from explicit requiresPermission overrides
*/
const ACTIONS = [
"create",
"delete",
"execute",
"publish",
"read",
"share",
"write"
];
/**
* All valid permission patterns.
* Use `keyof typeof PERMISSION_PATTERNS` or the `PermissionPattern` type.
*/
const PERMISSION_PATTERNS = {
/** Full access to all resources and actions */
"*": "*",
/** Create all resources */
"*:create": "*:create",
/** Delete all resources */
"*:delete": "*:delete",
/** Execute all resources */
"*:execute": "*:execute",
/** Publish, activate, or restore all resources */
"*:publish": "*:publish",
/** View all resources */
"*:read": "*:read",
/** Change visibility/audience all resources */
"*:share": "*:share",
/** Create and modify all resources */
"*:write": "*:write",
/** Full access to agent-to-agent communication */
"a2a:*": "a2a:*",
/** Full access to agent builder */
"agent-builder:*": "agent-builder:*",
/** Full access to agent controller sessions */
"agent-controller:*": "agent-controller:*",
/** Full access to agents */
"agents:*": "agents:*",
/** Full access to auth */
"auth:*": "auth:*",
/** Full access to background tasks */
"background-tasks:*": "background-tasks:*",
/** Full access to channels */
"channels:*": "channels:*",
/** Full access to datasets */
"datasets:*": "datasets:*",
/** Full access to embedders */
"embedders:*": "embedders:*",
/** Full access to experiments */
"experiments:*": "experiments:*",
/** Full access to infrastructure */
"infrastructure:*": "infrastructure:*",
/** Full access to logs */
"logs:*": "logs:*",
/** Full access to MCP servers */
"mcp:*": "mcp:*",
/** Full access to memory and threads */
"memory:*": "memory:*",
/** Full access to traces and spans */
"observability:*": "observability:*",
/** Full access to processor-providers */
"processor-providers:*": "processor-providers:*",
/** Full access to processors */
"processors:*": "processors:*",
/** Full access to schedules */
"schedules:*": "schedules:*",
/** Full access to evaluation scores */
"scores:*": "scores:*",
/** Full access to stored agents */
"stored-agents:*": "stored-agents:*",
/** Full access to stored MCP clients */
"stored-mcp-clients:*": "stored-mcp-clients:*",
/** Full access to stored prompt blocks */
"stored-prompt-blocks:*": "stored-prompt-blocks:*",
/** Full access to stored scorers */
"stored-scorers:*": "stored-scorers:*",
/** Full access to stored skills */
"stored-skills:*": "stored-skills:*",
/** Full access to stored workflows */
"stored-workflows:*": "stored-workflows:*",
/** Full access to stored workspaces */
"stored-workspaces:*": "stored-workspaces:*",
/** Full access to system info */
"system:*": "system:*",
/** Full access to tool-providers */
"tool-providers:*": "tool-providers:*",
/** Full access to tools */
"tools:*": "tools:*",
/** Full access to vector stores */
"vector:*": "vector:*",
/** Full access to vectors */
"vectors:*": "vectors:*",
/** Full access to workflows */
"workflows:*": "workflows:*",
/** Full access to workspaces */
"workspaces:*": "workspaces:*",
/** View agent-to-agent communication */
"a2a:read": "a2a:read",
/** Create and modify agent-to-agent communication */
"a2a:write": "a2a:write",
/** Execute agent builder */
"agent-builder:execute": "agent-builder:execute",
/** View agent builder */
"agent-builder:read": "agent-builder:read",
/** Create and modify agent builder */
"agent-builder:write": "agent-builder:write",
/** Execute agent controller sessions */
"agent-controller:execute": "agent-controller:execute",
/** View agent controller sessions */
"agent-controller:read": "agent-controller:read",
/** Create agents */
"agents:create": "agents:create",
/** Delete agents */
"agents:delete": "agents:delete",
/** Execute agents */
"agents:execute": "agents:execute",
/** View agents */
"agents:read": "agents:read",
/** Create and modify agents */
"agents:write": "agents:write",
/** View auth */
"auth:read": "auth:read",
/** View background tasks */
"background-tasks:read": "background-tasks:read",
/** View channels */
"channels:read": "channels:read",
/** Create and modify channels */
"channels:write": "channels:write",
/** Delete datasets */
"datasets:delete": "datasets:delete",
/** Execute datasets */
"datasets:execute": "datasets:execute",
/** View datasets */
"datasets:read": "datasets:read",
/** Create and modify datasets */
"datasets:write": "datasets:write",
/** View embedders */
"embedders:read": "embedders:read",
/** View experiments */
"experiments:read": "experiments:read",
/** View infrastructure */
"infrastructure:read": "infrastructure:read",
/** View logs */
"logs:read": "logs:read",
/** Execute MCP servers */
"mcp:execute": "mcp:execute",
/** View MCP servers */
"mcp:read": "mcp:read",
/** Create and modify MCP servers */
"mcp:write": "mcp:write",
/** Delete memory and threads */
"memory:delete": "memory:delete",
/** Execute memory and threads */
"memory:execute": "memory:execute",
/** View memory and threads */
"memory:read": "memory:read",
/** Create and modify memory and threads */
"memory:write": "memory:write",
/** View traces and spans */
"observability:read": "observability:read",
/** Create and modify traces and spans */
"observability:write": "observability:write",
/** View processor-providers */
"processor-providers:read": "processor-providers:read",
/** Execute processors */
"processors:execute": "processors:execute",
/** View processors */
"processors:read": "processors:read",
/** Delete schedules */
"schedules:delete": "schedules:delete",
/** Execute schedules */
"schedules:execute": "schedules:execute",
/** View schedules */
"schedules:read": "schedules:read",
/** Create and modify schedules */
"schedules:write": "schedules:write",
/** View evaluation scores */
"scores:read": "scores:read",
/** Create and modify evaluation scores */
"scores:write": "scores:write",
/** Delete stored agents */
"stored-agents:delete": "stored-agents:delete",
/** Publish, activate, or restore stored agents */
"stored-agents:publish": "stored-agents:publish",
/** View stored agents */
"stored-agents:read": "stored-agents:read",
/** Create and modify stored agents */
"stored-agents:write": "stored-agents:write",
/** Delete stored MCP clients */
"stored-mcp-clients:delete": "stored-mcp-clients:delete",
/** Publish, activate, or restore stored MCP clients */
"stored-mcp-clients:publish": "stored-mcp-clients:publish",
/** View stored MCP clients */
"stored-mcp-clients:read": "stored-mcp-clients:read",
/** Create and modify stored MCP clients */
"stored-mcp-clients:write": "stored-mcp-clients:write",
/** Delete stored prompt blocks */
"stored-prompt-blocks:delete": "stored-prompt-blocks:delete",
/** Publish, activate, or restore stored prompt blocks */
"stored-prompt-blocks:publish": "stored-prompt-blocks:publish",
/** View stored prompt blocks */
"stored-prompt-blocks:read": "stored-prompt-blocks:read",
/** Create and modify stored prompt blocks */
"stored-prompt-blocks:write": "stored-prompt-blocks:write",
/** Delete stored scorers */
"stored-scorers:delete": "stored-scorers:delete",
/** Publish, activate, or restore stored scorers */
"stored-scorers:publish": "stored-scorers:publish",
/** View stored scorers */
"stored-scorers:read": "stored-scorers:read",
/** Create and modify stored scorers */
"stored-scorers:write": "stored-scorers:write",
/** Delete stored skills */
"stored-skills:delete": "stored-skills:delete",
/** Publish, activate, or restore stored skills */
"stored-skills:publish": "stored-skills:publish",
/** View stored skills */
"stored-skills:read": "stored-skills:read",
/** Create and modify stored skills */
"stored-skills:write": "stored-skills:write",
/** View stored workflows */
"stored-workflows:read": "stored-workflows:read",
/** Create and modify stored workflows */
"stored-workflows:write": "stored-workflows:write",
/** Delete stored workspaces */
"stored-workspaces:delete": "stored-workspaces:delete",
/** View stored workspaces */
"stored-workspaces:read": "stored-workspaces:read",
/** Create and modify stored workspaces */
"stored-workspaces:write": "stored-workspaces:write",
/** View system info */
"system:read": "system:read",
/** Delete tool-providers */
"tool-providers:delete": "tool-providers:delete",
/** View tool-providers */
"tool-providers:read": "tool-providers:read",
/** Create and modify tool-providers */
"tool-providers:write": "tool-providers:write",
/** Execute tools */
"tools:execute": "tools:execute",
/** View tools */
"tools:read": "tools:read",
/** Delete vector stores */
"vector:delete": "vector:delete",
/** Execute vector stores */
"vector:execute": "vector:execute",
/** View vector stores */
"vector:read": "vector:read",
/** Create and modify vector stores */
"vector:write": "vector:write",
/** View vectors */
"vectors:read": "vectors:read",
/** Delete workflows */
"workflows:delete": "workflows:delete",
/** Execute workflows */
"workflows:execute": "workflows:execute",
/** View workflows */
"workflows:read": "workflows:read",
/** Create and modify workflows */
"workflows:write": "workflows:write",
/** Delete workspaces */
"workspaces:delete": "workspaces:delete",
/** View workspaces */
"workspaces:read": "workspaces:read",
/** Create and modify workspaces */
"workspaces:write": "workspaces:write",
/** Full access to all stored resource families */
"stored:*": "stored:*",
/** View all stored resource families */
"stored:read": "stored:read",
/** Create and modify all stored resource families */
"stored:write": "stored:write",
/** Delete all stored resource families */
"stored:delete": "stored:delete",
/** Change visibility/audience stored agents */
"stored-agents:share": "stored-agents:share",
/** Change visibility/audience stored skills */
"stored-skills:share": "stored-skills:share"
};
/**
* All valid resource:action permission combinations (excludes wildcards).
*/
const PERMISSIONS = [
"a2a:read",
"a2a:write",
"agent-builder:execute",
"agent-builder:read",
"agent-builder:write",
"agent-controller:execute",
"agent-controller:read",
"agents:create",
"agents:delete",
"agents:execute",
"agents:read",
"agents:write",
"auth:read",
"background-tasks:read",
"channels:read",
"channels:write",
"datasets:delete",
"datasets:execute",
"datasets:read",
"datasets:write",
"embedders:read",
"experiments:read",
"infrastructure:read",
"logs:read",
"mcp:execute",
"mcp:read",
"mcp:write",
"memory:delete",
"memory:execute",
"memory:read",
"memory:write",
"observability:read",
"observability:write",
"processor-providers:read",
"processors:execute",
"processors:read",
"schedules:delete",
"schedules:execute",
"schedules:read",
"schedules:write",
"scores:read",
"scores:write",
"stored-agents:delete",
"stored-agents:publish",
"stored-agents:read",
"stored-agents:write",
"stored-mcp-clients:delete",
"stored-mcp-clients:publish",
"stored-mcp-clients:read",
"stored-mcp-clients:write",
"stored-prompt-blocks:delete",
"stored-prompt-blocks:publish",
"stored-prompt-blocks:read",
"stored-prompt-blocks:write",
"stored-scorers:delete",
"stored-scorers:publish",
"stored-scorers:read",
"stored-scorers:write",
"stored-skills:delete",
"stored-skills:publish",
"stored-skills:read",
"stored-skills:write",
"stored-workflows:read",
"stored-workflows:write",
"stored-workspaces:delete",
"stored-workspaces:read",
"stored-workspaces:write",
"system:read",
"tool-providers:delete",
"tool-providers:read",
"tool-providers:write",
"tools:execute",
"tools:read",
"vector:delete",
"vector:execute",
"vector:read",
"vector:write",
"vectors:read",
"workflows:delete",
"workflows:execute",
"workflows:read",
"workflows:write",
"workspaces:delete",
"workspaces:read",
"workspaces:write"
];
/**
* Type-safe constants for Mastra-owned FGA permissions.
*
* These values are generated from server routes and can be used wherever
* Mastra checks or maps FGA permissions.
*/
const MastraFGAPermissions = {
/** View agent-to-agent communication */
A2A_READ: "a2a:read",
/** Create and modify agent-to-agent communication */
A2A_WRITE: "a2a:write",
/** Execute agent builder */
AGENT_BUILDER_EXECUTE: "agent-builder:execute",
/** View agent builder */
AGENT_BUILDER_READ: "agent-builder:read",
/** Create and modify agent builder */
AGENT_BUILDER_WRITE: "agent-builder:write",
/** Execute agent controller sessions */
AGENT_CONTROLLER_EXECUTE: "agent-controller:execute",
/** View agent controller sessions */
AGENT_CONTROLLER_READ: "agent-controller:read",
/** Create agents */
AGENTS_CREATE: "agents:create",
/** Delete agents */
AGENTS_DELETE: "agents:delete",
/** Execute agents */
AGENTS_EXECUTE: "agents:execute",
/** View agents */
AGENTS_READ: "agents:read",
/** Create and modify agents */
AGENTS_WRITE: "agents:write",
/** View auth */
AUTH_READ: "auth:read",
/** View background tasks */
BACKGROUND_TASKS_READ: "background-tasks:read",
/** View channels */
CHANNELS_READ: "channels:read",
/** Create and modify channels */
CHANNELS_WRITE: "channels:write",
/** Delete datasets */
DATASETS_DELETE: "datasets:delete",
/** Execute datasets */
DATASETS_EXECUTE: "datasets:execute",
/** View datasets */
DATASETS_READ: "datasets:read",
/** Create and modify datasets */
DATASETS_WRITE: "datasets:write",
/** View embedders */
EMBEDDERS_READ: "embedders:read",
/** View experiments */
EXPERIMENTS_READ: "experiments:read",
/** View infrastructure */
INFRASTRUCTURE_READ: "infrastructure:read",
/** View logs */
LOGS_READ: "logs:read",
/** Execute MCP servers */
MCP_EXECUTE: "mcp:execute",
/** View MCP servers */
MCP_READ: "mcp:read",
/** Create and modify MCP servers */
MCP_WRITE: "mcp:write",
/** Delete memory and threads */
MEMORY_DELETE: "memory:delete",
/** Execute memory and threads */
MEMORY_EXECUTE: "memory:execute",
/** View memory and threads */
MEMORY_READ: "memory:read",
/** Create and modify memory and threads */
MEMORY_WRITE: "memory:write",
/** View traces and spans */
OBSERVABILITY_READ: "observability:read",
/** Create and modify traces and spans */
OBSERVABILITY_WRITE: "observability:write",
/** View processor-providers */
PROCESSOR_PROVIDERS_READ: "processor-providers:read",
/** Execute processors */
PROCESSORS_EXECUTE: "processors:execute",
/** View processors */
PROCESSORS_READ: "processors:read",
/** Delete schedules */
SCHEDULES_DELETE: "schedules:delete",
/** Execute schedules */
SCHEDULES_EXECUTE: "schedules:execute",
/** View schedules */
SCHEDULES_READ: "schedules:read",
/** Create and modify schedules */
SCHEDULES_WRITE: "schedules:write",
/** View evaluation scores */
SCORES_READ: "scores:read",
/** Create and modify evaluation scores */
SCORES_WRITE: "scores:write",
/** Delete stored agents */
STORED_AGENTS_DELETE: "stored-agents:delete",
/** Publish, activate, or restore stored agents */
STORED_AGENTS_PUBLISH: "stored-agents:publish",
/** View stored agents */
STORED_AGENTS_READ: "stored-agents:read",
/** Create and modify stored agents */
STORED_AGENTS_WRITE: "stored-agents:write",
/** Delete stored MCP clients */
STORED_MCP_CLIENTS_DELETE: "stored-mcp-clients:delete",
/** Publish, activate, or restore stored MCP clients */
STORED_MCP_CLIENTS_PUBLISH: "stored-mcp-clients:publish",
/** View stored MCP clients */
STORED_MCP_CLIENTS_READ: "stored-mcp-clients:read",
/** Create and modify stored MCP clients */
STORED_MCP_CLIENTS_WRITE: "stored-mcp-clients:write",
/** Delete stored prompt blocks */
STORED_PROMPT_BLOCKS_DELETE: "stored-prompt-blocks:delete",
/** Publish, activate, or restore stored prompt blocks */
STORED_PROMPT_BLOCKS_PUBLISH: "stored-prompt-blocks:publish",
/** View stored prompt blocks */
STORED_PROMPT_BLOCKS_READ: "stored-prompt-blocks:read",
/** Create and modify stored prompt blocks */
STORED_PROMPT_BLOCKS_WRITE: "stored-prompt-blocks:write",
/** Delete stored scorers */
STORED_SCORERS_DELETE: "stored-scorers:delete",
/** Publish, activate, or restore stored scorers */
STORED_SCORERS_PUBLISH: "stored-scorers:publish",
/** View stored scorers */
STORED_SCORERS_READ: "stored-scorers:read",
/** Create and modify stored scorers */
STORED_SCORERS_WRITE: "stored-scorers:write",
/** Delete stored skills */
STORED_SKILLS_DELETE: "stored-skills:delete",
/** Publish, activate, or restore stored skills */
STORED_SKILLS_PUBLISH: "stored-skills:publish",
/** View stored skills */
STORED_SKILLS_READ: "stored-skills:read",
/** Create and modify stored skills */
STORED_SKILLS_WRITE: "stored-skills:write",
/** View stored workflows */
STORED_WORKFLOWS_READ: "stored-workflows:read",
/** Create and modify stored workflows */
STORED_WORKFLOWS_WRITE: "stored-workflows:write",
/** Delete stored workspaces */
STORED_WORKSPACES_DELETE: "stored-workspaces:delete",
/** View stored workspaces */
STORED_WORKSPACES_READ: "stored-workspaces:read",
/** Create and modify stored workspaces */
STORED_WORKSPACES_WRITE: "stored-workspaces:write",
/** View system info */
SYSTEM_READ: "system:read",
/** Delete tool-providers */
TOOL_PROVIDERS_DELETE: "tool-providers:delete",
/** View tool-providers */
TOOL_PROVIDERS_READ: "tool-providers:read",
/** Create and modify tool-providers */
TOOL_PROVIDERS_WRITE: "tool-providers:write",
/** Execute tools */
TOOLS_EXECUTE: "tools:execute",
/** View tools */
TOOLS_READ: "tools:read",
/** Delete vector stores */
VECTOR_DELETE: "vector:delete",
/** Execute vector stores */
VECTOR_EXECUTE: "vector:execute",
/** View vector stores */
VECTOR_READ: "vector:read",
/** Create and modify vector stores */
VECTOR_WRITE: "vector:write",
/** View vectors */
VECTORS_READ: "vectors:read",
/** Delete workflows */
WORKFLOWS_DELETE: "workflows:delete",
/** Execute workflows */
WORKFLOWS_EXECUTE: "workflows:execute",
/** View workflows */
WORKFLOWS_READ: "workflows:read",
/** Create and modify workflows */
WORKFLOWS_WRITE: "workflows:write",
/** Delete workspaces */
WORKSPACES_DELETE: "workspaces:delete",
/** View workspaces */
WORKSPACES_READ: "workspaces:read",
/** Create and modify workspaces */
WORKSPACES_WRITE: "workspaces:write"
};
/**
* Validates that a string is a valid permission pattern.
* Useful for runtime validation of permission strings.
*/
function isValidPermissionPattern(pattern) {
return pattern in PERMISSION_PATTERNS;
}
/**
* Validates that all permissions in an array are valid patterns.
*/
function validatePermissions(permissions) {
return permissions.every(isValidPermissionPattern);
}
/**
* FGA enforcement utility for checking fine-grained authorization.
*
* @license Mastra Enterprise License - see ee/LICENSE
*/
function mergeFGAContext({ context, requestContext, metadata }) {
const mergedContext = { ...context };
if (requestContext) mergedContext.requestContext = requestContext;
if (metadata || context?.metadata) mergedContext.metadata = {
...context?.metadata ?? {},
...metadata ?? {}
};
return Object.keys(mergedContext).length > 0 ? mergedContext : void 0;
}
function isActorSignal(actor) {
if (actor === true) return true;
if (typeof actor !== "object" || actor === null) return false;
const candidate = actor;
return candidate.actorKind === "system" && (candidate.sourceWorkflow === void 0 || typeof candidate.sourceWorkflow === "string");
}
function getAgentFGAResourceId(agentId) {
return agentId;
}
function getWorkflowFGAResourceId(workflowId) {
return workflowId;
}
function getStandaloneToolFGAResourceId(toolName) {
return toolName;
}
function getAgentToolFGAResourceId(agentId, toolName) {
return `${agentId}:${toolName}`;
}
function getMCPToolFGAResourceId(serverName, toolName) {
return JSON.stringify([serverName, toolName]);
}
/**
* Check fine-grained authorization for a resource.
*
* No-op if no FGA provider is configured (backward compatibility).
* Delegates to fgaProvider.require() which throws FGADeniedError if denied.
*/
async function checkFGA(options) {
await requireFGA(options);
}
/**
* Require fine-grained authorization for a resource.
*
* No-op if no FGA provider is configured. When FGA is configured, a missing
* user fails closed.
*/
async function requireFGA(options) {
const { fgaProvider, user, resource, permission, context, requestContext, metadata, actor } = options;
if (!fgaProvider) return;
const fgaContext = mergeFGAContext({
context,
requestContext,
metadata
});
const license = getSafeLicenseSummary();
if (isActorSignal(actor)) {
const tenantOrganizationId = fgaContext?.requestContext?.get("organizationId");
if (typeof tenantOrganizationId !== "string" || tenantOrganizationId.length === 0) throw new FGADeniedError(user, resource, permission, "trusted actor requires organizationId / tenant scope");
const sourceWorkflow = (actor === true ? void 0 : actor.sourceWorkflow) ?? (typeof fgaContext?.metadata?.["sourceWorkflow"] === "string" ? fgaContext.metadata["sourceWorkflow"] : void 0);
const providerEnforced = typeof fgaProvider.requireActor === "function";
if (providerEnforced) await fgaProvider.requireActor(actor, {
resource,
permission,
...fgaContext ? { context: fgaContext } : {}
});
try {
captureEEEvent("ee_feature_used", license.anonymousId || getEETelemetryFallbackDistinctId(), {
feature: "fga",
actor_kind: "system",
actor_authorized_by: providerEnforced ? "provider" : "bypass",
resource_type: resource.type,
resource_id: resource.id,
permission,
user_id: null,
organization_membership_id: null,
source_workflow: sourceWorkflow,
license_valid: license.valid,
license_hash: license.licenseHash,
is_dev_environment: license.isDevEnvironment
});
} catch {}
return;
}
if (!user) throw new FGADeniedError(user, resource, permission, "authenticated user is required");
await fgaProvider.require(user, fgaContext ? {
resource,
permission,
context: fgaContext
} : {
resource,
permission
});
try {
captureEEEvent("ee_feature_used", user?.id || license.anonymousId || getEETelemetryFallbackDistinctId(), {
feature: "fga",
actor_kind: "user",
resource_type: resource.type,
resource_id: resource.id,
permission,
user_id: user?.id ?? null,
organization_membership_id: user?.organizationMembershipId ?? null,
license_valid: license.valid,
license_hash: license.licenseHash,
is_dev_environment: license.isDevEnvironment
});
} catch {}
}
/**
* Error thrown when an FGA authorization check is denied.
*/
var FGADeniedError = class extends Error {
user;
resource;
permission;
status;
constructor(user, resource, permission, reason) {
const userId = user?.id || user?.workosId || "unknown";
const permissionLabel = Array.isArray(permission) ? `any of [${permission.join(", ")}]` : permission;
super(reason ? `FGA authorization denied: ${reason}` : `FGA authorization denied: user ${userId} cannot ${permissionLabel} on ${resource.type}:${resource.id}`);
this.name = "FGADeniedError";
this.user = user;
this.resource = resource;
this.permission = permission;
this.status = 403;
}
};
/**
* Default role definitions for Studio.
*
* These roles provide a sensible starting point for most applications:
* - **owner**: Full access to everything
* - **admin**: Manage agents, workflows, and users
* - **member**: Execute agents and workflows, read-only settings
* - **viewer**: Read-only access
*
* Permission patterns:
* - `*` - Full access to everything
* - `resource:*` - All actions on a specific resource
* - `*:action` - An action across all resources (e.g., `*:read` for read-only)
*/
const DEFAULT_ROLES = [
{
id: "owner",
name: "Owner",
description: "Full access to all features and settings",
permissions: ["*"]
},
{
id: "admin",
name: "Admin",
description: "Manage agents, workflows, and team members",
permissions: [
"*:read",
"*:write",
"*:execute",
"*:publish",
"*:share"
]
},
{
id: "member",
name: "Member",
description: "Execute agents and workflows",
permissions: ["*:read", "*:execute"]
},
{
id: "viewer",
name: "Viewer",
description: "Read-only access",
permissions: ["*:read"]
}
];
/**
* Get role by ID from default roles.
*
* @param roleId - Role ID to find
* @returns Role definition or undefined
*/
function getDefaultRole(roleId) {
return DEFAULT_ROLES.find((role) => role.id === roleId);
}
/**
* Resolve all permissions for a set of role IDs.
*
* Handles role inheritance and deduplication.
*
* @param roleIds - Role IDs to resolve
* @param roles - Role definitions (defaults to DEFAULT_ROLES)
* @returns Array of resolved permissions
*/
function resolvePermissions(roleIds, roles = DEFAULT_ROLES) {
const permissions = /* @__PURE__ */ new Set();
const visited = /* @__PURE__ */ new Set();
function resolveRole(roleId) {
if (visited.has(roleId)) return;
visited.add(roleId);
const role = roles.find((r) => r.id === roleId);
if (!role) return;
for (const permission of role.permissions) permissions.add(permission);
if (role.inherits) for (const inheritedRoleId of role.inherits) resolveRole(inheritedRoleId);
}
for (const roleId of roleIds) resolveRole(roleId);
return Array.from(permissions);
}
/**
* Compound resource keys that expand to a set of per-family resources.
* A granted `stored:<action>` is treated as matching any `stored-<family>:<action>`
* (and `stored:*` matches any `stored-<family>:*`).
*/
const RESOURCE_EXPANSIONS = { stored: [
"stored-agents",
"stored-mcp-clients",
"stored-prompt-blocks",
"stored-scorers",
"stored-skills",
"stored-workspaces"
] };
/**
* Check if a permission matches (including wildcard support).
*
* Permission format: `{resource}:{action}[:{resource-id}]`
*
* Examples:
* - `*` matches everything
* - `agents:*` matches `agents:read`, `agents:read:my-agent`
* - `*:read` matches `agents:read`, `workflows:read` (action across all resources)
* - `agents:read` matches `agents:read`, `agents:read:my-agent`
* - `agents:read:my-agent` matches only `agents:read:my-agent`
* - `agents:*:my-agent` matches `agents:read:my-agent`, `agents:write:my-agent`
*
* @param userPermission - Permission the user has
* @param requiredPermission - Permission being checked
* @returns True if permission matches
*/
function matchesPermission(userPermission, requiredPermission) {
if (userPermission === "*") return true;
const grantedParts = userPermission.split(":");
const requiredParts = requiredPermission.split(":");
const expandedFamilies = RESOURCE_EXPANSIONS[grantedParts[0] ?? ""];
if (expandedFamilies && expandedFamilies.includes(requiredParts[0] ?? "")) return matchesPermission([requiredParts[0], ...grantedParts.slice(1)].join(":"), requiredPermission);
if (grantedParts.length < 2 || requiredParts.length < 2) return userPermission === requiredPermission;
const [grantedResource, grantedAction, grantedId] = grantedParts;
const [requiredResource, requiredAction, requiredId] = requiredParts;
if (grantedResource === "*") {
if (grantedAction === "*") {
if (grantedId === void 0) return true;
return grantedId === requiredId;
}
if (grantedAction !== requiredAction) return false;
if (grantedId === void 0) return true;
return grantedId === requiredId;
}
if (grantedResource !== requiredResource) return false;
if (grantedAction === "*") {
if (grantedId === void 0) return true;
return grantedId === requiredId;
}
if (grantedAction !== requiredAction) return false;
if (grantedId === void 0) return true;
return grantedId === requiredId;
}
/**
* Check if a user has a specific permission.
*
* @param userPermissions - Permissions the user has
* @param requiredPermission - Permission being checked
* @returns True if user has the permission
*/
function hasPermission(userPermissions, requiredPermission) {
return userPermissions.some((p) => matchesPermission(p, requiredPermission));
}
/**
* Resolve permissions from user roles using a role mapping.
*
* This function translates provider-defined roles (from WorkOS, Okta, etc.)
* to Mastra permissions using a configurable mapping.
*
* @example
* ```typescript
* const roleMapping = {
* "Engineering": ["agents:*", "workflows:*"],
* "Product": ["agents:read"],
* "_default": [],
* };
*
* // User has "Engineering" and "QA" roles
* const permissions = resolvePermissionsFromMapping(
* ["Engineering", "QA"],
* roleMapping
* );
* // Result: ["agents:*", "workflows:*"] (QA is unmapped, gets _default)
* ```
*
* @param roles - User's roles from the identity provider
* @param mapping - Role to permission mapping
* @returns Array of resolved permissions
*/
function resolvePermissionsFromMapping(roles, mapping) {
const permissions = /* @__PURE__ */ new Set();
const defaultPerms = mapping["_default"] ?? [];
for (const role of roles) {
const rolePerms = mapping[role];
if (rolePerms) for (const perm of rolePerms) permissions.add(perm);
else for (const perm of defaultPerms) permissions.add(perm);
}
return Array.from(permissions);
}
/**
* Static RBAC provider.
*
* Supports two modes:
* 1. **Role definitions**: Use Mastra's native role system with structured roles
* 2. **Role mapping**: Directly map provider roles to permissions
*
* @example Using role definitions (Mastra's native system)
* ```typescript
* const rbac = new StaticRBACProvider({
* roles: DEFAULT_ROLES,
* getUserRoles: (user) => [user.role],
* });
* ```
*
* @example Using role mapping (for external providers)
* ```typescript
* const rbac = new StaticRBACProvider({
* roleMapping: {
* "Engineering": ["agents:*", "workflows:*"],
* "Product": ["agents:read", "workflows:read"],
* "_defa