mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-11-12 09:45:47 +00:00
* fix: Route Delete-User CLI Through the Shared Account Erasure Cascade The operator CLI ran raw deleteMany calls that dropped File metadata while leaving storage objects, skipped skills, MCP servers and agent checkpoints, and used the wrong field for agent API keys. Account self-deletion and the CLI now share eraseUserData in packages/api, so both remove stored file objects before metadata, open checkpoint deletion around conversations, and clear skills, MCP servers and shared links with ACL cleanup. * fix: Erase Favorites, Projects, Queued Turns and Refresh Bridges With the Account Account erasure left tool favorites, chat projects, queued agent turns and their sequences, and OpenID refresh token bridges behind. The shared eraseUserData cascade now clears them, adding deleteUserToolFavorites and deleteUserChatProjects where no delete-by-user method existed. * fix: Move MCP Server Erasure Queries Into Data Methods and Propagate Their Failures * test: Cover Delete-User CLI and Self-Service Erasure Scenarios * fix: Delete Stored Files When Account Deletion Arrives Without a Body * fix: Delete Stored Files Before User Keys and Keep Provider Failures Best Effort * fix: Propagate Agent and Prompt Erasure Failures Before Deleting the User * fix: Delete Erasure Retry Anchors Last When Removing User-Owned Resources * fix: Retire Session Hint From the Shared Erasure Cascade After Sessions Are Revoked * fix: Propagate Skill and Agent Reference Cleanup Failures Before Deleting the User * fix: Scope CLI Account Erasure to the Deleted User's Tenant and Legacy Refresh Bridges * fix: Clean Shared-User MCP OAuth State When Account Erasure Removes a Server * fix: Keep CLI Erasure System-Scoped Except ID-Keyed Cleanup and Await Shared-Link ACL Cleanup * fix: Scope CLI MCP OAuth Lookups to the Tenant and Fail Erasure When Shared-User Cleanup Fails * fix: Run CLI MCP OAuth Teardown and Allowlist Resolution Per User in the Tenant * fix: Tear Down Shared-User MCP OAuth State Before Removing the Server Retry Anchors * fix: Pin Agent Reference and MCP Token Cleanup to the Deleted User's Own Tenant
62 lines
2.3 KiB
JavaScript
62 lines
2.3 KiB
JavaScript
const fs = require('fs');
|
|
const path = require('path');
|
|
const { ResourceType } = require('librechat-data-provider');
|
|
|
|
/**
|
|
* Maps each ResourceType to the cleanup function name that must appear in
|
|
* deleteUserController's source to prove it is handled during user deletion.
|
|
*
|
|
* When a new ResourceType is added, this test will fail until a corresponding
|
|
* entry is added here (or to NO_USER_CLEANUP_NEEDED) AND the actual cleanup
|
|
* logic is implemented.
|
|
*/
|
|
const HANDLED_RESOURCE_TYPES = {
|
|
[ResourceType.AGENT]: 'deleteUserAgents',
|
|
[ResourceType.CODE_ENVIRONMENT]: 'deleteUserCodeEnvironments',
|
|
[ResourceType.REMOTE_AGENT]: 'deleteUserAgents',
|
|
[ResourceType.PROMPTGROUP]: 'deleteUserPrompts',
|
|
[ResourceType.MCPSERVER]: 'deleteUserMCPServers',
|
|
[ResourceType.SKILL]: 'deleteUserSkills',
|
|
[ResourceType.SHARED_LINK]: 'deleteAllSharedLinksWithCleanup',
|
|
};
|
|
|
|
/**
|
|
* ResourceTypes that are ACL-tracked but have no per-user deletion semantics
|
|
* (e.g., system resources, public-only). Must be explicitly listed here with
|
|
* a justification to prevent silent omissions.
|
|
*/
|
|
const NO_USER_CLEANUP_NEEDED = new Set([
|
|
// Example: ResourceType.SYSTEM_TEMPLATE — public/system; not user-owned
|
|
]);
|
|
|
|
describe('deleteUserController - resource type coverage guard', () => {
|
|
let controllerSource;
|
|
|
|
beforeAll(() => {
|
|
/** The controller delegates the data cascade to the shared erasure service. */
|
|
controllerSource = [
|
|
path.resolve(__dirname, '../UserController.js'),
|
|
path.resolve(__dirname, '../../../../packages/api/src/user/erasure.ts'),
|
|
]
|
|
.map((file) => fs.readFileSync(file, 'utf-8'))
|
|
.join('\n');
|
|
});
|
|
|
|
test('every ResourceType must have a documented cleanup handler or explicit exclusion', () => {
|
|
const allTypes = Object.values(ResourceType);
|
|
const handledTypes = Object.keys(HANDLED_RESOURCE_TYPES);
|
|
const unhandledTypes = allTypes.filter(
|
|
(t) => !handledTypes.includes(t) && !NO_USER_CLEANUP_NEEDED.has(t),
|
|
);
|
|
|
|
expect(unhandledTypes).toEqual([]);
|
|
});
|
|
|
|
test('every cleanup handler referenced in HANDLED_RESOURCE_TYPES must appear in the controller source', () => {
|
|
const uniqueHandlers = [...new Set(Object.values(HANDLED_RESOURCE_TYPES))];
|
|
|
|
for (const handler of uniqueHandlers) {
|
|
expect(controllerSource).toContain(handler);
|
|
}
|
|
});
|
|
});
|