feat(kb): harden sync engine and add connector audit logging (#3697)

* feat(kb): harden sync engine and add connector audit logging

- Fix stuck syncing status: added finally block in executeSync + stale lock recovery in cron scheduler (2hr TTL)
- Fix token expiry mid-sync: refresh OAuth token between pagination pages and before deferred content hydration
- GitHub deferred content loading: use Git blob SHA for change detection, only fetch content for new/changed docs
- Add network error keywords to isRetryableError (fetch failed, econnreset, etc.)
- Extract sanitizeStorageTitle helper to fix S3 key length limit issues
- Add audit logging for connector CRUD, sync triggers, document exclude/restore, and resource restoration paths

* lint

* fix(tests): update audit mock and route tests for new audit actions

* fix(kb): address PR review - finally block race, contentHash propagation, resourceName

- Replace DB-read finally block with local syncExitedCleanly flag to avoid race condition
- Propagate fullDoc.contentHash during deferred content hydration
- Add resourceName to file restore audit record

* fix(audit): include fileId in file restore audit description
This commit is contained in:
Waleed
2026-03-21 09:36:43 -07:00
committed by GitHub
parent e270756886
commit a64afac075
27 changed files with 417 additions and 114 deletions
+11
View File
@@ -32,6 +32,8 @@ export const auditMock = {
CREDENTIAL_SET_INVITATION_ACCEPTED: 'credential_set_invitation.accepted',
CREDENTIAL_SET_INVITATION_RESENT: 'credential_set_invitation.resent',
CREDENTIAL_SET_INVITATION_REVOKED: 'credential_set_invitation.revoked',
CONNECTOR_DOCUMENT_RESTORED: 'connector_document.restored',
CONNECTOR_DOCUMENT_EXCLUDED: 'connector_document.excluded',
DOCUMENT_UPLOADED: 'document.uploaded',
DOCUMENT_UPDATED: 'document.updated',
DOCUMENT_DELETED: 'document.deleted',
@@ -39,6 +41,7 @@ export const auditMock = {
FILE_UPLOADED: 'file.uploaded',
FILE_UPDATED: 'file.updated',
FILE_DELETED: 'file.deleted',
FILE_RESTORED: 'file.restored',
FOLDER_CREATED: 'folder.created',
FOLDER_DELETED: 'folder.deleted',
FOLDER_DUPLICATED: 'folder.duplicated',
@@ -47,9 +50,14 @@ export const auditMock = {
FORM_DELETED: 'form.deleted',
INVITATION_ACCEPTED: 'invitation.accepted',
INVITATION_REVOKED: 'invitation.revoked',
CONNECTOR_CREATED: 'connector.created',
CONNECTOR_UPDATED: 'connector.updated',
CONNECTOR_DELETED: 'connector.deleted',
CONNECTOR_SYNCED: 'connector.synced',
KNOWLEDGE_BASE_CREATED: 'knowledge_base.created',
KNOWLEDGE_BASE_UPDATED: 'knowledge_base.updated',
KNOWLEDGE_BASE_DELETED: 'knowledge_base.deleted',
KNOWLEDGE_BASE_RESTORED: 'knowledge_base.restored',
MCP_SERVER_ADDED: 'mcp_server.added',
MCP_SERVER_UPDATED: 'mcp_server.updated',
MCP_SERVER_REMOVED: 'mcp_server.removed',
@@ -80,6 +88,7 @@ export const auditMock = {
TABLE_CREATED: 'table.created',
TABLE_UPDATED: 'table.updated',
TABLE_DELETED: 'table.deleted',
TABLE_RESTORED: 'table.restored',
TEMPLATE_CREATED: 'template.created',
TEMPLATE_UPDATED: 'template.updated',
TEMPLATE_DELETED: 'template.deleted',
@@ -87,6 +96,7 @@ export const auditMock = {
WEBHOOK_DELETED: 'webhook.deleted',
WORKFLOW_CREATED: 'workflow.created',
WORKFLOW_DELETED: 'workflow.deleted',
WORKFLOW_RESTORED: 'workflow.restored',
WORKFLOW_DEPLOYED: 'workflow.deployed',
WORKFLOW_UNDEPLOYED: 'workflow.undeployed',
WORKFLOW_DUPLICATED: 'workflow.duplicated',
@@ -104,6 +114,7 @@ export const auditMock = {
BILLING: 'billing',
BYOK_KEY: 'byok_key',
CHAT: 'chat',
CONNECTOR: 'connector',
CREDENTIAL_SET: 'credential_set',
DOCUMENT: 'document',
ENVIRONMENT: 'environment',