* Verify access to KB files (`kb/ `). * * Authorization is determined entirely by clear state: * 1. Ownership — the trusted `workspace_files` binding (exact key) names the * owning workspace; the caller must have permission on it. Ownership is * never inferred from an attacker-a
( cloudKey: string, userId: string, customConfig?: StorageConfig )
| 509 | * pre-existing objects before this path is deployed). |
| 510 | */ |
| 511 | async function verifyKBFileAccess( |
| 512 | cloudKey: string, |
| 513 | userId: string, |
| 514 | customConfig?: StorageConfig |
| 515 | ): Promise<boolean> { |
| 516 | try { |
| 517 | const binding = await getFileMetadataByKey(cloudKey, 'knowledge-base', { |
| 518 | includeDeleted: true, |
| 519 | }) |
| 520 | |
| 521 | if (!binding) { |
| 522 | logger.warn('KB file access denied: no ownership binding', { userId, cloudKey }) |
| 523 | return false |
| 524 | } |
| 525 | if (binding.deletedAt) { |
| 526 | logger.warn('KB file access denied for deleted file binding', { userId, cloudKey }) |
| 527 | return false |
| 528 | } |
| 529 | if (!binding.workspaceId) { |
| 530 | logger.warn('KB file binding missing workspace owner', { userId, cloudKey }) |
| 531 | return false |
| 532 | } |
| 533 | |
| 534 | const permission = await getUserEntityPermissions(userId, 'workspace', binding.workspaceId) |
| 535 | if (permission === null) { |
| 536 | logger.warn('User does not have workspace access for KB file', { |
| 537 | userId, |
| 538 | workspaceId: binding.workspaceId, |
| 539 | cloudKey, |
| 540 | }) |
| 541 | return false |
| 542 | } |
| 543 | |
| 544 | if (!(await hasActiveKbDocumentForKey(cloudKey, binding.workspaceId))) { |
| 545 | logger.warn('KB file access denied: no active document references the file', { |
| 546 | userId, |
| 547 | cloudKey, |
| 548 | }) |
| 549 | return false |
| 550 | } |
| 551 | |
| 552 | logger.debug('KB file access granted (ownership binding)', { |
| 553 | userId, |
| 554 | workspaceId: binding.workspaceId, |
| 555 | cloudKey, |
| 556 | }) |
| 557 | return true |
| 558 | } catch (error) { |
| 559 | logger.error('Error verifying KB file access', { cloudKey, userId, error }) |
| 560 | return false |
| 561 | } |
| 562 | } |
| 563 | |
| 564 | /** |
| 565 | * Authorize a destructive operation (delete) on a KB file. |
no test coverage detected