UNPKG

@stackmemoryai/stackmemory

Version:

Project-scoped memory for AI coding tools. Durable context across sessions with MCP integration, frames, smart retrieval, Claude Code skills, and automatic hooks.

186 lines (185 loc) 5.31 kB
import { fileURLToPath as __fileURLToPath } from 'url'; import { dirname as __pathDirname } from 'path'; const __filename = __fileURLToPath(import.meta.url); const __dirname = __pathDirname(__filename); import { ValidationError, ErrorCode } from "../errors/index.js"; import { logger } from "../monitoring/logger.js"; class PermissionManager { userPermissions = /* @__PURE__ */ new Map(); adminUsers = /* @__PURE__ */ new Set(); constructor() { this.initializeDefaultPermissions(); } /** * Check if user has permission for specific operation */ async checkPermission(context) { try { if (this.adminUsers.has(context.userId)) { return true; } const stackPermissions = this.getStackPermissions( context.userId, context.stackContext?.stackId || context.resourceId ); if (!stackPermissions) { logger.warn("No permissions found for user", { userId: context.userId, stackId: context.stackContext?.stackId, operation: context.operation }); return false; } switch (context.operation) { case "read": return stackPermissions.canRead; case "write": return stackPermissions.canWrite; case "handoff": return stackPermissions.canHandoff; case "merge": return stackPermissions.canMerge; case "administer": return stackPermissions.canAdminister; default: logger.error("Unknown operation type", { operation: context.operation }); return false; } } catch (error) { logger.error("Permission check failed", error); return false; } } /** * Enforce permission check - throws if access denied */ async enforcePermission(context) { const hasPermission = await this.checkPermission(context); if (!hasPermission) { throw new ValidationError( `Access denied: User ${context.userId} lacks ${context.operation} permission for ${context.resourceType} ${context.resourceId}`, ErrorCode.PERMISSION_VIOLATION, { userId: context.userId, operation: context.operation, resourceType: context.resourceType, resourceId: context.resourceId } ); } logger.debug("Permission granted", { userId: context.userId, operation: context.operation, resourceType: context.resourceType, resourceId: context.resourceId }); } /** * Set permissions for user on specific stack */ setStackPermissions(userId, stackId, permissions) { if (!this.userPermissions.has(userId)) { this.userPermissions.set(userId, /* @__PURE__ */ new Map()); } this.userPermissions.get(userId).set(stackId, permissions); logger.info("Updated stack permissions", { userId, stackId, permissions }); } /** * Get permissions for user on specific stack */ getStackPermissions(userId, stackId) { const userPerms = this.userPermissions.get(userId); if (!userPerms) return null; return userPerms.get(stackId) || null; } /** * Grant admin privileges to user */ grantAdminAccess(userId) { this.adminUsers.add(userId); logger.info("Granted admin access", { userId }); } /** * Revoke admin privileges from user */ revokeAdminAccess(userId) { this.adminUsers.delete(userId); logger.info("Revoked admin access", { userId }); } /** * Check if user is admin */ isAdmin(userId) { return this.adminUsers.has(userId); } /** * Get all permissions for user */ getUserPermissions(userId) { return this.userPermissions.get(userId) || /* @__PURE__ */ new Map(); } /** * Remove all permissions for user */ removeUserPermissions(userId) { this.userPermissions.delete(userId); this.adminUsers.delete(userId); logger.info("Removed all permissions for user", { userId }); } /** * Initialize default permissions */ initializeDefaultPermissions() { const defaultAdmin = process.env["STACKMEMORY_DEFAULT_ADMIN"]; if (defaultAdmin) { this.grantAdminAccess(defaultAdmin); } } /** * Create permission context helper */ createContext(userId, operation, resourceType, resourceId, stackContext) { return { userId, operation, resourceType, resourceId, stackContext }; } /** * Bulk permission update for multiple stacks */ setBulkStackPermissions(userId, stackPermissions) { if (!this.userPermissions.has(userId)) { this.userPermissions.set(userId, /* @__PURE__ */ new Map()); } const userPerms = this.userPermissions.get(userId); Object.entries(stackPermissions).forEach(([stackId, permissions]) => { userPerms.set(stackId, permissions); }); logger.info("Updated bulk stack permissions", { userId, stackCount: Object.keys(stackPermissions).length }); } /** * Get permission summary for debugging */ getPermissionSummary(userId) { return { isAdmin: this.isAdmin(userId), stackPermissions: Object.fromEntries(this.getUserPermissions(userId)) }; } } export { PermissionManager }; //# sourceMappingURL=permission-manager.js.map