refactor: Sanitize log inputs across various handlers to enhance security

- Implemented input sanitization for logging in chunk, evaluation, initialization, knowledge, knowledgebase, mcp_service, model, tenant, and session handlers.
- Updated logging statements to use sanitized values for sensitive information, preventing potential injection attacks.
This commit is contained in:
wizardchen
2025-11-25 23:33:34 +08:00
parent bf35a2861c
commit 016df3a4db
11 changed files with 136 additions and 106 deletions
+11 -7
View File
@@ -33,6 +33,7 @@ func (h *ChunkHandler) GetChunkByIDOnly(c *gin.Context) {
c.Error(errors.NewBadRequestError("Chunk ID cannot be empty"))
return
}
safeChunkID := secutils.SanitizeForLog(chunkID)
// Get tenant ID from context
tenantID, exists := c.Get(types.TenantIDContextKey.String())
@@ -42,13 +43,13 @@ func (h *ChunkHandler) GetChunkByIDOnly(c *gin.Context) {
return
}
logger.Infof(ctx, "Retrieving chunk by ID, chunk ID: %s, tenant ID: %d", secutils.SanitizeForLog(chunkID), tenantID)
logger.Infof(ctx, "Retrieving chunk by ID, chunk ID: %s, tenant ID: %d", safeChunkID, tenantID)
// Get chunk by ID
chunk, err := h.service.GetChunkByID(ctx, chunkID)
if err != nil {
if err == service.ErrChunkNotFound {
logger.Warnf(ctx, "Chunk not found, chunk ID: %s", chunkID)
logger.Warnf(ctx, "Chunk not found, chunk ID: %s", safeChunkID)
c.Error(errors.NewNotFoundError("Chunk not found"))
return
}
@@ -62,7 +63,7 @@ func (h *ChunkHandler) GetChunkByIDOnly(c *gin.Context) {
logger.Warnf(
ctx,
"Tenant has no permission to access chunk, chunk ID: %s, req tenant: %d, chunk tenant: %d",
chunkID, tenantID.(uint), chunk.TenantID,
safeChunkID, tenantID.(uint64), chunk.TenantID,
)
c.Error(errors.NewForbiddenError("No permission to access this chunk"))
return
@@ -147,6 +148,7 @@ func (h *ChunkHandler) validateAndGetChunk(c *gin.Context) (*types.Chunk, string
logger.Error(ctx, "Knowledge ID is empty")
return nil, "", errors.NewBadRequestError("Knowledge ID cannot be empty")
}
safeKnowledgeID := secutils.SanitizeForLog(knowledgeID)
// Validate chunk ID
id := c.Param("id")
@@ -154,6 +156,7 @@ func (h *ChunkHandler) validateAndGetChunk(c *gin.Context) (*types.Chunk, string
logger.Error(ctx, "Chunk ID is empty")
return nil, knowledgeID, errors.NewBadRequestError("Chunk ID cannot be empty")
}
safeChunkID := secutils.SanitizeForLog(id)
// Get tenant ID from context
tenantID, exists := c.Get(types.TenantIDContextKey.String())
@@ -162,13 +165,13 @@ func (h *ChunkHandler) validateAndGetChunk(c *gin.Context) (*types.Chunk, string
return nil, knowledgeID, errors.NewUnauthorizedError("Unauthorized")
}
logger.Infof(ctx, "Retrieving knowledge chunk information, knowledge ID: %s, chunk ID: %s", knowledgeID, id)
logger.Infof(ctx, "Retrieving knowledge chunk information, knowledge ID: %s, chunk ID: %s", safeKnowledgeID, safeChunkID)
// Get existing chunk
chunk, err := h.service.GetChunkByID(ctx, id)
if err != nil {
if err == service.ErrChunkNotFound {
logger.Warnf(ctx, "Chunk not found, knowledge ID: %s, chunk ID: %s", knowledgeID, id)
logger.Warnf(ctx, "Chunk not found, knowledge ID: %s, chunk ID: %s", safeKnowledgeID, safeChunkID)
return nil, knowledgeID, errors.NewNotFoundError("Chunk not found")
}
logger.ErrorWithFields(ctx, err, nil)
@@ -180,7 +183,7 @@ func (h *ChunkHandler) validateAndGetChunk(c *gin.Context) (*types.Chunk, string
logger.Warnf(
ctx,
"Tenant has no permission to access chunk, knowledge ID: %s, chunk ID: %s, req tenant: %d, chunk tenant: %d",
knowledgeID, id, tenantID, chunk.TenantID,
safeKnowledgeID, safeChunkID, tenantID, chunk.TenantID,
)
return nil, knowledgeID, errors.NewForbiddenError("No permission to access this chunk")
}
@@ -219,7 +222,8 @@ func (h *ChunkHandler) UpdateChunk(c *gin.Context) {
return
}
logger.Infof(ctx, "Knowledge chunk updated successfully, knowledge ID: %s, chunk ID: %s", knowledgeID, chunk.ID)
logger.Infof(ctx, "Knowledge chunk updated successfully, knowledge ID: %s, chunk ID: %s",
secutils.SanitizeForLog(knowledgeID), secutils.SanitizeForLog(chunk.ID))
c.JSON(http.StatusOK, gin.H{
"success": true,
"data": chunk,
+8 -8
View File
@@ -7,6 +7,7 @@ import (
"github.com/Tencent/WeKnora/internal/logger"
"github.com/Tencent/WeKnora/internal/types"
"github.com/Tencent/WeKnora/internal/types/interfaces"
secutils "github.com/Tencent/WeKnora/internal/utils"
"github.com/gin-gonic/gin"
)
@@ -34,7 +35,7 @@ func (e *EvaluationHandler) Evaluation(c *gin.Context) {
logger.Info(ctx, "Start processing evaluation request")
var request *EvaluationRequest
var request EvaluationRequest
if err := c.ShouldBind(&request); err != nil {
logger.Error(ctx, "Failed to parse request parameters", err)
c.Error(errors.NewBadRequestError("Invalid request parameters").WithDetails(err.Error()))
@@ -49,13 +50,12 @@ func (e *EvaluationHandler) Evaluation(c *gin.Context) {
}
logger.Infof(ctx, "Executing evaluation, tenant: %v, dataset: %s, knowledge_base: %s, chat: %s, rerank: %s",
tenantID, request.DatasetID, request.KnowledgeBaseID, request.ChatModelID, request.RerankModelID)
if request == nil {
logger.Error(ctx, "Request is nil")
c.Error(errors.NewBadRequestError("Invalid request parameters"))
return
}
tenantID,
secutils.SanitizeForLog(request.DatasetID),
secutils.SanitizeForLog(request.KnowledgeBaseID),
secutils.SanitizeForLog(request.ChatModelID),
secutils.SanitizeForLog(request.RerankModelID),
)
task, err := e.evaluationService.Evaluation(ctx,
request.DatasetID,
+20 -10
View File
@@ -1589,18 +1589,28 @@ func (h *InitializationHandler) TestMultimodalFunction(c *gin.Context) {
c.Error(errors.NewBadRequestError("图片文件大小不能超过10MB"))
return
}
logger.Infof(ctx, "Processing image: %s, size: %d bytes", header.Filename, header.Size)
logger.Infof(ctx, "Processing image: %s, size: %d bytes", secutils.SanitizeForLog(header.Filename), header.Size)
// 解析文档分割配置
chunkSizeInt64, err := strconv.ParseInt(req.ChunkSize, 10, 0)
chunkSize := int(chunkSizeInt64)
if err != nil || chunkSize < 100 || chunkSize > 10000 {
chunkSizeInt32, err := strconv.ParseInt(req.ChunkSize, 10, 32)
if err != nil {
logger.Error(ctx, "Failed to parse chunk size", err)
c.Error(errors.NewBadRequestError("Failed to parse chunk size"))
return
}
chunkSize := int32(chunkSizeInt32)
if chunkSize < 100 || chunkSize > 10000 {
chunkSize = 1000
}
chunkOverlapInt64, err := strconv.ParseInt(req.ChunkOverlap, 10, 0)
chunkOverlap := int(chunkOverlapInt64)
if err != nil || chunkOverlap < 0 || chunkOverlap >= chunkSize {
chunkOverlapInt32, err := strconv.ParseInt(req.ChunkOverlap, 10, 32)
if err != nil {
logger.Error(ctx, "Failed to parse chunk overlap", err)
c.Error(errors.NewBadRequestError("Failed to parse chunk overlap"))
return
}
chunkOverlap := int32(chunkOverlapInt32)
if chunkOverlap < 0 || chunkOverlap >= chunkSize {
chunkOverlap = 200
}
@@ -1660,7 +1670,7 @@ func (h *InitializationHandler) TestMultimodalFunction(c *gin.Context) {
func (h *InitializationHandler) testMultimodalWithDocReader(
ctx context.Context,
imageContent []byte, filename string,
chunkSize, chunkOverlap int, separators []string,
chunkSize, chunkOverlap int32, separators []string,
req *testMultimodalForm,
) (map[string]string, error) {
// 获取文件扩展名
@@ -1680,8 +1690,8 @@ func (h *InitializationHandler) testMultimodalWithDocReader(
FileName: filename,
FileType: fileExt,
ReadConfig: &proto.ReadConfig{
ChunkSize: int32(chunkSize),
ChunkOverlap: int32(chunkOverlap),
ChunkSize: chunkSize,
ChunkOverlap: chunkOverlap,
Separators: separators,
EnableMultimodal: true, // 启用多模态处理
VlmConfig: &proto.VLMConfig{
+20 -20
View File
@@ -70,7 +70,7 @@ func (h *KnowledgeHandler) handleDuplicateKnowledgeError(c *gin.Context,
) bool {
if dupErr, ok := err.(*types.DuplicateKnowledgeError); ok {
ctx := c.Request.Context()
logger.Warnf(ctx, "Detected duplicate %s: %s", duplicateType, dupErr.Error())
logger.Warnf(ctx, "Detected duplicate %s: %s", duplicateType, secutils.SanitizeForLog(dupErr.Error()))
c.JSON(http.StatusConflict, gin.H{
"success": false,
"message": dupErr.Error(),
@@ -107,11 +107,11 @@ func (h *KnowledgeHandler) CreateKnowledgeFromFile(c *gin.Context) {
displayFileName := file.Filename
if customFileName != "" {
displayFileName = customFileName
logger.Infof(ctx, "Using custom filename: %s (original: %s)", customFileName, file.Filename)
logger.Infof(ctx, "Using custom filename: %s (original: %s)", secutils.SanitizeForLog(customFileName), secutils.SanitizeForLog(file.Filename))
}
logger.Infof(ctx, "File upload successful, filename: %s, size: %.2f KB", displayFileName, float64(file.Size)/1024)
logger.Infof(ctx, "Creating knowledge, knowledge base ID: %s, filename: %s", kbID, displayFileName)
logger.Infof(ctx, "File upload successful, filename: %s, size: %.2f KB", secutils.SanitizeForLog(displayFileName), float64(file.Size)/1024)
logger.Infof(ctx, "Creating knowledge, knowledge base ID: %s, filename: %s", secutils.SanitizeForLog(kbID), secutils.SanitizeForLog(displayFileName))
// Parse metadata if provided
var metadata map[string]string
@@ -122,7 +122,7 @@ func (h *KnowledgeHandler) CreateKnowledgeFromFile(c *gin.Context) {
c.Error(errors.NewBadRequestError("Invalid metadata format").WithDetails(err.Error()))
return
}
logger.Infof(ctx, "Received file metadata: %v", metadata)
logger.Infof(ctx, "Received file metadata: %s", secutils.SanitizeForLog(fmt.Sprintf("%v", metadata)))
}
enableMultimodelForm := c.PostForm("enable_multimodel")
@@ -153,7 +153,7 @@ func (h *KnowledgeHandler) CreateKnowledgeFromFile(c *gin.Context) {
return
}
logger.Infof(ctx, "Knowledge created successfully, ID: %s, title: %s", knowledge.ID, knowledge.Title)
logger.Infof(ctx, "Knowledge created successfully, ID: %s, title: %s", secutils.SanitizeForLog(knowledge.ID), secutils.SanitizeForLog(knowledge.Title))
c.JSON(http.StatusOK, gin.H{
"success": true,
"data": knowledge,
@@ -198,7 +198,7 @@ func (h *KnowledgeHandler) CreateKnowledgeFromURL(c *gin.Context) {
return
}
logger.Infof(ctx, "Knowledge created successfully from URL, ID: %s, title: %s", knowledge.ID, knowledge.Title)
logger.Infof(ctx, "Knowledge created successfully from URL, ID: %s, title: %s", secutils.SanitizeForLog(knowledge.ID), secutils.SanitizeForLog(knowledge.Title))
c.JSON(http.StatusCreated, gin.H{
"success": true,
"data": knowledge,
@@ -236,7 +236,7 @@ func (h *KnowledgeHandler) CreateManualKnowledge(c *gin.Context) {
return
}
logger.Infof(ctx, "Manual knowledge created successfully, knowledge ID: %s", knowledge.ID)
logger.Infof(ctx, "Manual knowledge created successfully, knowledge ID: %s", secutils.SanitizeForLog(knowledge.ID))
c.JSON(http.StatusOK, gin.H{
"success": true,
"data": knowledge,
@@ -257,7 +257,7 @@ func (h *KnowledgeHandler) GetKnowledge(c *gin.Context) {
return
}
logger.Infof(ctx, "Retrieving knowledge, ID: %s", id)
logger.Infof(ctx, "Retrieving knowledge, ID: %s", secutils.SanitizeForLog(id))
knowledge, err := h.kgService.GetKnowledgeByID(ctx, id)
if err != nil {
logger.ErrorWithFields(ctx, err, nil)
@@ -265,7 +265,7 @@ func (h *KnowledgeHandler) GetKnowledge(c *gin.Context) {
return
}
logger.Infof(ctx, "Knowledge retrieved successfully, ID: %s, title: %s", knowledge.ID, knowledge.Title)
logger.Infof(ctx, "Knowledge retrieved successfully, ID: %s, title: %s", secutils.SanitizeForLog(knowledge.ID), secutils.SanitizeForLog(knowledge.Title))
c.JSON(http.StatusOK, gin.H{
"success": true,
"data": knowledge,
@@ -297,7 +297,7 @@ func (h *KnowledgeHandler) ListKnowledge(c *gin.Context) {
tagID := c.Query("tag_id")
logger.Infof(ctx, "Retrieving knowledge list under knowledge base, knowledge base ID: %s, tag_id: %s, page: %d, page size: %d",
kbID, tagID, pagination.Page, pagination.PageSize)
secutils.SanitizeForLog(kbID), secutils.SanitizeForLog(tagID), pagination.Page, pagination.PageSize)
// Retrieve paginated knowledge entries
result, err := h.kgService.ListPagedKnowledgeByKnowledgeBaseID(ctx, kbID, &pagination, tagID)
@@ -307,7 +307,7 @@ func (h *KnowledgeHandler) ListKnowledge(c *gin.Context) {
return
}
logger.Infof(ctx, "Knowledge list retrieved successfully, knowledge base ID: %s, total: %d", kbID, result.Total)
logger.Infof(ctx, "Knowledge list retrieved successfully, knowledge base ID: %s, total: %d", secutils.SanitizeForLog(kbID), result.Total)
c.JSON(http.StatusOK, gin.H{
"success": true,
"data": result.Data,
@@ -331,7 +331,7 @@ func (h *KnowledgeHandler) DeleteKnowledge(c *gin.Context) {
return
}
logger.Infof(ctx, "Deleting knowledge, ID: %s", id)
logger.Infof(ctx, "Deleting knowledge, ID: %s", secutils.SanitizeForLog(id))
err := h.kgService.DeleteKnowledge(ctx, id)
if err != nil {
logger.ErrorWithFields(ctx, err, nil)
@@ -339,7 +339,7 @@ func (h *KnowledgeHandler) DeleteKnowledge(c *gin.Context) {
return
}
logger.Infof(ctx, "Knowledge deleted successfully, ID: %s", id)
logger.Infof(ctx, "Knowledge deleted successfully, ID: %s", secutils.SanitizeForLog(id))
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "Deleted successfully",
@@ -360,7 +360,7 @@ func (h *KnowledgeHandler) DownloadKnowledgeFile(c *gin.Context) {
return
}
logger.Infof(ctx, "Retrieving knowledge file, ID: %s", id)
logger.Infof(ctx, "Retrieving knowledge file, ID: %s", secutils.SanitizeForLog(id))
// Get file content and filename
file, filename, err := h.kgService.GetKnowledgeFile(ctx, id)
@@ -371,7 +371,7 @@ func (h *KnowledgeHandler) DownloadKnowledgeFile(c *gin.Context) {
}
defer file.Close()
logger.Infof(ctx, "Knowledge file retrieved successfully, ID: %s, filename: %s", id, filename)
logger.Infof(ctx, "Knowledge file retrieved successfully, ID: %s, filename: %s", secutils.SanitizeForLog(id), secutils.SanitizeForLog(filename))
// Set response headers for file download
c.Header("Content-Description", "File Transfer")
@@ -472,7 +472,7 @@ func (h *KnowledgeHandler) UpdateKnowledge(c *gin.Context) {
return
}
logger.Infof(ctx, "Knowledge updated successfully, knowledge ID: %s", knowledge.ID)
logger.Infof(ctx, "Knowledge updated successfully, knowledge ID: %s", secutils.SanitizeForLog(knowledge.ID))
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "Knowledge chunk updated successfully",
@@ -511,7 +511,7 @@ func (h *KnowledgeHandler) UpdateManualKnowledge(c *gin.Context) {
return
}
logger.Infof(ctx, "Manual knowledge updated successfully, knowledge ID: %s", knowledge.ID)
logger.Infof(ctx, "Manual knowledge updated successfully, knowledge ID: %s", secutils.SanitizeForLog(knowledge.ID))
c.JSON(http.StatusOK, gin.H{
"success": true,
"data": knowledge,
@@ -571,7 +571,7 @@ func (h *KnowledgeHandler) UpdateImageInfo(c *gin.Context) {
}
// Update chunk properties
logger.Infof(ctx, "Updating knowledge chunk, knowledge ID: %s, chunk ID: %s", id, chunkID)
logger.Infof(ctx, "Updating knowledge chunk, knowledge ID: %s, chunk ID: %s", secutils.SanitizeForLog(id), secutils.SanitizeForLog(chunkID))
err := h.kgService.UpdateImageInfo(ctx, id, chunkID, request.ImageInfo)
if err != nil {
logger.ErrorWithFields(ctx, err, nil)
@@ -579,7 +579,7 @@ func (h *KnowledgeHandler) UpdateImageInfo(c *gin.Context) {
return
}
logger.Infof(ctx, "Knowledge chunk updated successfully, knowledge ID: %s, chunk ID: %s", id, chunkID)
logger.Infof(ctx, "Knowledge chunk updated successfully, knowledge ID: %s, chunk ID: %s", secutils.SanitizeForLog(id), secutils.SanitizeForLog(chunkID))
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "Knowledge chunk image updated successfully",
+1 -1
View File
@@ -126,7 +126,7 @@ func (h *KnowledgeBaseHandler) validateAndGetKnowledgeBase(c *gin.Context) (*typ
ctx,
"Tenant has no permission to access this knowledge base, knowledge base ID: %s, "+
"request tenant ID: %d, knowledge base tenant ID: %d",
id, tenantID.(uint), kb.TenantID,
id, tenantID.(uint64), kb.TenantID,
)
return nil, id, errors.NewForbiddenError("No permission to operate")
}
+1 -1
View File
@@ -44,7 +44,7 @@ func (h *MCPServiceHandler) CreateMCPService(c *gin.Context) {
service.TenantID = tenantID
if err := h.mcpServiceService.CreateMCPService(ctx, &service); err != nil {
logger.ErrorWithFields(ctx, err, map[string]interface{}{"service_name": service.Name})
logger.ErrorWithFields(ctx, err, map[string]interface{}{"service_name": secutils.SanitizeForLog(service.Name)})
c.Error(errors.NewInternalServerError("Failed to create MCP service: " + err.Error()))
return
}
+13 -13
View File
@@ -110,7 +110,7 @@ func (h *ModelHandler) CreateModel(c *gin.Context) {
return
}
logger.Infof(ctx, "Model created successfully, ID: %s, Name: %s", model.ID, model.Name)
logger.Infof(ctx, "Model created successfully, ID: %s, Name: %s", secutils.SanitizeForLog(model.ID), secutils.SanitizeForLog(model.Name))
// Hide sensitive information for builtin models (though newly created models are unlikely to be builtin)
responseModel := hideSensitiveInfo(model)
@@ -138,11 +138,11 @@ func (h *ModelHandler) GetModel(c *gin.Context) {
return
}
logger.Infof(ctx, "Retrieving model, ID: %s", id)
logger.Infof(ctx, "Retrieving model, ID: %s", secutils.SanitizeForLog(id))
model, err := h.service.GetModelByID(ctx, id)
if err != nil {
if err == service.ErrModelNotFound {
logger.Warnf(ctx, "Model not found, ID: %s", id)
logger.Warnf(ctx, "Model not found, ID: %s", secutils.SanitizeForLog(id))
c.Error(errors.NewNotFoundError("Model not found"))
return
}
@@ -151,12 +151,12 @@ func (h *ModelHandler) GetModel(c *gin.Context) {
return
}
logger.Infof(ctx, "Retrieved model successfully, ID: %s, Name: %s", model.ID, model.Name)
logger.Infof(ctx, "Retrieved model successfully, ID: %s, Name: %s", secutils.SanitizeForLog(model.ID), secutils.SanitizeForLog(model.Name))
// Hide sensitive information for builtin models
responseModel := hideSensitiveInfo(model)
if model.IsBuiltin {
logger.Infof(ctx, "Builtin model detected, hiding sensitive information for model: %s", model.ID)
logger.Infof(ctx, "Builtin model detected, hiding sensitive information for model: %s", secutils.SanitizeForLog(model.ID))
}
c.JSON(http.StatusOK, gin.H{
@@ -196,7 +196,7 @@ func (h *ModelHandler) ListModels(c *gin.Context) {
for i, model := range models {
responseModels[i] = hideSensitiveInfo(model)
if model.IsBuiltin {
logger.Infof(ctx, "Builtin model detected in list, hiding sensitive information for model: %s", model.ID)
logger.Infof(ctx, "Builtin model detected in list, hiding sensitive information for model: %s", secutils.SanitizeForLog(model.ID))
}
}
@@ -240,11 +240,11 @@ func (h *ModelHandler) UpdateModel(c *gin.Context) {
return
}
logger.Infof(ctx, "Retrieving model information, ID: %s", id)
logger.Infof(ctx, "Retrieving model information, ID: %s", secutils.SanitizeForLog(id))
model, err := h.service.GetModelByID(ctx, id)
if err != nil {
if err == service.ErrModelNotFound {
logger.Warnf(ctx, "Model not found, ID: %s", id)
logger.Warnf(ctx, "Model not found, ID: %s", secutils.SanitizeForLog(id))
c.Error(errors.NewNotFoundError("Model not found"))
return
}
@@ -264,14 +264,14 @@ func (h *ModelHandler) UpdateModel(c *gin.Context) {
model.Source = req.Source
model.Type = req.Type
logger.Infof(ctx, "Updating model, ID: %s, Name: %s", id, model.Name)
logger.Infof(ctx, "Updating model, ID: %s, Name: %s", secutils.SanitizeForLog(id), secutils.SanitizeForLog(model.Name))
if err := h.service.UpdateModel(ctx, model); err != nil {
logger.ErrorWithFields(ctx, err, nil)
c.Error(errors.NewInternalServerError(err.Error()))
return
}
logger.Infof(ctx, "Model updated successfully, ID: %s", id)
logger.Infof(ctx, "Model updated successfully, ID: %s", secutils.SanitizeForLog(id))
// Hide sensitive information for builtin models (though builtin models cannot be updated)
responseModel := hideSensitiveInfo(model)
@@ -299,10 +299,10 @@ func (h *ModelHandler) DeleteModel(c *gin.Context) {
return
}
logger.Infof(ctx, "Deleting model, ID: %s", id)
logger.Infof(ctx, "Deleting model, ID: %s", secutils.SanitizeForLog(id))
if err := h.service.DeleteModel(ctx, id); err != nil {
if err == service.ErrModelNotFound {
logger.Warnf(ctx, "Model not found, ID: %s", id)
logger.Warnf(ctx, "Model not found, ID: %s", secutils.SanitizeForLog(id))
c.Error(errors.NewNotFoundError("Model not found"))
return
}
@@ -311,7 +311,7 @@ func (h *ModelHandler) DeleteModel(c *gin.Context) {
return
}
logger.Infof(ctx, "Model deleted successfully, ID: %s", id)
logger.Infof(ctx, "Model deleted successfully, ID: %s", secutils.SanitizeForLog(id))
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "Model deleted",
+31 -21
View File
@@ -46,8 +46,8 @@ func (h *Handler) SearchKnowledge(c *gin.Context) {
logger.Infof(
ctx,
"Knowledge search request, knowledge base ID: %s, query: %s",
request.KnowledgeBaseID,
request.Query,
secutils.SanitizeForLog(request.KnowledgeBaseID),
secutils.SanitizeForLog(request.Query),
)
// Directly call knowledge retrieval service without LLM summarization
@@ -80,6 +80,7 @@ func (h *Handler) KnowledgeQA(c *gin.Context) {
c.Error(errors.NewBadRequestError(errors.ErrInvalidSessionID.Error()))
return
}
safeSessionID := secutils.SanitizeForLog(sessionID)
// Parse request body
var request CreateKnowledgeQARequest
@@ -104,12 +105,12 @@ func (h *Handler) KnowledgeQA(c *gin.Context) {
return
}
logger.Infof(ctx, "Knowledge QA request, session ID: %s, query: %s", secutils.SanitizeForLog(sessionID), secutils.SanitizeForLog(request.Query))
logger.Infof(ctx, "Knowledge QA request, session ID: %s, query: %s", safeSessionID, secutils.SanitizeForLog(request.Query))
// Get session to prepare knowledge base IDs
session, err := h.sessionService.GetSession(ctx, sessionID)
if err != nil {
logger.Errorf(ctx, "Failed to get session, session ID: %s, error: %v", secutils.SanitizeForLog(sessionID), err)
logger.Errorf(ctx, "Failed to get session, session ID: %s, error: %v", safeSessionID, err)
c.Error(errors.NewInternalServerError(err.Error()))
return
}
@@ -137,6 +138,7 @@ func (h *Handler) AgentQA(c *gin.Context) {
c.Error(errors.NewBadRequestError(errors.ErrInvalidSessionID.Error()))
return
}
safeSessionID := secutils.SanitizeForLog(sessionID)
// Parse request body
var request CreateKnowledgeQARequest
@@ -145,7 +147,11 @@ func (h *Handler) AgentQA(c *gin.Context) {
c.Error(errors.NewBadRequestError(err.Error()))
return
}
logger.Infof(ctx, "Agent QA request, request: %+v", request)
if requestJSON, err := json.Marshal(request); err == nil {
logger.Infof(ctx, "Agent QA request, request: %s", secutils.SanitizeForLog(string(requestJSON)))
} else {
logger.Warnf(ctx, "Agent QA request received but failed to marshal for logging: %s", secutils.SanitizeForLog(err.Error()))
}
// Validate query content
if request.Query == "" {
@@ -169,7 +175,7 @@ func (h *Handler) AgentQA(c *gin.Context) {
c.Error(errors.NewInternalServerError(err.Error()))
return
}
logger.Infof(ctx, "Before AgentQA, Session: %s", string(sessionJSON))
logger.Infof(ctx, "Before AgentQA, Session: %s", secutils.SanitizeForLog(string(sessionJSON)))
// Create assistant message
assistantMessage := &types.Message{
@@ -210,7 +216,10 @@ func (h *Handler) AgentQA(c *gin.Context) {
}
}
if knowledgeBasesChanged {
logger.Infof(ctx, "Knowledge bases changed from %v to %v", session.AgentConfig.KnowledgeBases, request.KnowledgeBaseIDs)
logger.Infof(ctx, "Knowledge bases changed from %s to %s",
secutils.SanitizeForLog(fmt.Sprintf("%v", session.AgentConfig.KnowledgeBases)),
secutils.SanitizeForLog(fmt.Sprintf("%v", request.KnowledgeBaseIDs)),
)
}
}
@@ -239,14 +248,14 @@ func (h *Handler) AgentQA(c *gin.Context) {
// If configuration changed, clear context and update session
if configChanged {
logger.Warnf(ctx, "Configuration changed, clearing context for session: %s", sessionID)
logger.Warnf(ctx, "Configuration changed, clearing context for session: %s", safeSessionID)
// Clear the LLM context to prevent contamination
if err := h.sessionService.ClearContext(ctx, sessionID); err != nil {
logger.Errorf(ctx, "Failed to clear context for session %s: %v", sessionID, err)
logger.Errorf(ctx, "Failed to clear context for session %s: %v", safeSessionID, err)
// Continue anyway - this is not a fatal error
}
if err := h.sessionService.DeleteWebSearchTempKBState(ctx, sessionID); err != nil {
logger.Errorf(ctx, "Failed to delete temp knowledge base for session %s: %v", sessionID, err)
logger.Errorf(ctx, "Failed to delete temp knowledge base for session %s: %v", safeSessionID, err)
// Continue anyway - this is not a fatal error
}
session.AgentConfig.KnowledgeBases = request.KnowledgeBaseIDs
@@ -255,16 +264,16 @@ func (h *Handler) AgentQA(c *gin.Context) {
session.SummaryModelID = summaryModelID
// Persist the session changes
if err := h.sessionService.UpdateSession(ctx, session); err != nil {
logger.Errorf(ctx, "Failed to update session %s: %v", sessionID, err)
logger.Errorf(ctx, "Failed to update session %s: %v", safeSessionID, err)
c.Error(errors.NewInternalServerError("Failed to update session configuration"))
return
}
logger.Infof(ctx, "Session configuration updated successfully for session: %s", sessionID)
logger.Infof(ctx, "Session configuration updated successfully for session: %s", safeSessionID)
}
// If Agent mode is disabled, delegate to KnowledgeQA
if !request.AgentEnabled {
logger.Infof(ctx, "Agent mode disabled, delegating to KnowledgeQA for session: %s", sessionID)
logger.Infof(ctx, "Agent mode disabled, delegating to KnowledgeQA for session: %s", safeSessionID)
// Use knowledge bases from request or session config
knowledgeBaseIDs := request.KnowledgeBaseIDs
@@ -285,7 +294,7 @@ func (h *Handler) AgentQA(c *gin.Context) {
return
}
logger.Infof(ctx, "Delegating to KnowledgeQA with knowledge bases: %v", knowledgeBaseIDs)
logger.Infof(ctx, "Delegating to KnowledgeQA with knowledge bases: %s", secutils.SanitizeForLog(fmt.Sprintf("%v", knowledgeBaseIDs)))
// Use shared function to handle KnowledgeQA request (no title generation for AgentQA fallback)
h.handleKnowledgeQARequest(ctx, c, session, request.Query, knowledgeBaseIDs, assistantMessage, false, request.SummaryModelID, request.WebSearchEnabled)
@@ -325,7 +334,7 @@ func (h *Handler) AgentQA(c *gin.Context) {
}
assistantMessage = assistantMessagePtr
logger.Infof(ctx, "Calling agent QA service, session ID: %s", sessionID)
logger.Infof(ctx, "Calling agent QA service, session ID: %s", safeSessionID)
// Write initial agent_query event to StreamManager
h.writeAgentQueryEvent(ctx, sessionID, assistantMessage.ID)
@@ -338,7 +347,7 @@ func (h *Handler) AgentQA(c *gin.Context) {
// Start async title generation if session has no title
if session.Title == "" {
logger.Infof(ctx, "Session has no title, starting async title generation, session ID: %s", sessionID)
logger.Infof(ctx, "Session has no title, starting async title generation, session ID: %s", safeSessionID)
h.sessionService.GenerateTitleAsync(asyncCtx, session, request.Query, eventBus)
}
@@ -353,11 +362,11 @@ func (h *Handler) AgentQA(c *gin.Context) {
logger.ErrorWithFields(asyncCtx,
errors.NewInternalServerError(fmt.Sprintf("Agent QA service panicked: %v\n%s", r, string(buf))),
map[string]interface{}{
"session_id": sessionID,
"session_id": safeSessionID,
})
}
h.completeAssistantMessage(asyncCtx, assistantMessage)
logger.Infof(asyncCtx, "Agent QA service completed for session: %s", sessionID)
logger.Infof(asyncCtx, "Agent QA service completed for session: %s", safeSessionID)
}()
err := h.sessionService.AgentQA(asyncCtx, session, request.Query, assistantMessage.ID, eventBus)
if err != nil {
@@ -394,6 +403,7 @@ func (h *Handler) handleKnowledgeQARequest(
webSearchEnabled bool, // Whether web search is enabled
) {
sessionID := session.ID
safeSessionID := secutils.SanitizeForLog(sessionID)
requestID := getRequestID(c)
// Create user message
@@ -415,7 +425,7 @@ func (h *Handler) handleKnowledgeQARequest(
return
}
logger.Infof(ctx, "Using knowledge bases: %v", knowledgeBaseIDs)
logger.Infof(ctx, "Using knowledge bases: %s", secutils.SanitizeForLog(fmt.Sprintf("%v", knowledgeBaseIDs)))
// Set headers for SSE
setSSEHeaders(c)
@@ -434,7 +444,7 @@ func (h *Handler) handleKnowledgeQARequest(
// Generate title if needed
if generateTitle && session.Title == "" {
logger.Infof(ctx, "Session has no title, starting async title generation, session ID: %s", sessionID)
logger.Infof(ctx, "Session has no title, starting async title generation, session ID: %s", safeSessionID)
h.sessionService.GenerateTitleAsync(asyncCtx, session, query, eventBus)
}
@@ -445,7 +455,7 @@ func (h *Handler) handleKnowledgeQARequest(
}
assistantMessage.Content += data.Content
if data.Done {
logger.Infof(asyncCtx, "Knowledge QA service completed for session: %s", sessionID)
logger.Infof(asyncCtx, "Knowledge QA service completed for session: %s", safeSessionID)
h.completeAssistantMessage(asyncCtx, assistantMessage)
// Emit completion event when stream finishes
if err := eventBus.Emit(asyncCtx, event.Event{
+8 -7
View File
@@ -13,6 +13,7 @@ import (
"github.com/Tencent/WeKnora/internal/logger"
"github.com/Tencent/WeKnora/internal/types"
"github.com/Tencent/WeKnora/internal/types/interfaces"
secutils "github.com/Tencent/WeKnora/internal/utils"
)
// TenantHandler implements HTTP request handlers for tenant management
@@ -54,7 +55,7 @@ func (h *TenantHandler) CreateTenant(c *gin.Context) {
return
}
logger.Infof(ctx, "Creating tenant, name: %s", tenantData.Name)
logger.Infof(ctx, "Creating tenant, name: %s", secutils.SanitizeForLog(tenantData.Name))
createdTenant, err := h.service.CreateTenant(ctx, &tenantData)
if err != nil {
@@ -69,7 +70,7 @@ func (h *TenantHandler) CreateTenant(c *gin.Context) {
return
}
logger.Infof(ctx, "Tenant created successfully, ID: %d, name: %s", createdTenant.ID, createdTenant.Name)
logger.Infof(ctx, "Tenant created successfully, ID: %d, name: %s", createdTenant.ID, secutils.SanitizeForLog(createdTenant.Name))
c.JSON(http.StatusCreated, gin.H{
"success": true,
"data": createdTenant,
@@ -86,7 +87,7 @@ func (h *TenantHandler) GetTenant(c *gin.Context) {
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
if err != nil {
logger.Errorf(ctx, "Invalid tenant ID: %s", c.Param("id"))
logger.Errorf(ctx, "Invalid tenant ID: %s", secutils.SanitizeForLog(c.Param("id")))
c.Error(errors.NewBadRequestError("Invalid tenant ID"))
return
}
@@ -122,7 +123,7 @@ func (h *TenantHandler) UpdateTenant(c *gin.Context) {
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
if err != nil {
logger.Errorf(ctx, "Invalid tenant ID: %s", c.Param("id"))
logger.Errorf(ctx, "Invalid tenant ID: %s", secutils.SanitizeForLog(c.Param("id")))
c.Error(errors.NewBadRequestError("Invalid tenant ID"))
return
}
@@ -134,7 +135,7 @@ func (h *TenantHandler) UpdateTenant(c *gin.Context) {
return
}
logger.Infof(ctx, "Updating tenant, ID: %d, Name: %s", id, tenantData.Name)
logger.Infof(ctx, "Updating tenant, ID: %d, Name: %s", id, secutils.SanitizeForLog(tenantData.Name))
tenantData.ID = id
updatedTenant, err := h.service.UpdateTenant(ctx, &tenantData)
@@ -150,7 +151,7 @@ func (h *TenantHandler) UpdateTenant(c *gin.Context) {
return
}
logger.Infof(ctx, "Tenant updated successfully, ID: %d, Name: %s", updatedTenant.ID, updatedTenant.Name)
logger.Infof(ctx, "Tenant updated successfully, ID: %d, Name: %s", updatedTenant.ID, secutils.SanitizeForLog(updatedTenant.Name))
c.JSON(http.StatusOK, gin.H{
"success": true,
"data": updatedTenant,
@@ -169,7 +170,7 @@ func (h *TenantHandler) DeleteTenant(c *gin.Context) {
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
if err != nil {
logger.Errorf(ctx, "Invalid tenant ID: %s", c.Param("id"))
logger.Errorf(ctx, "Invalid tenant ID: %s", secutils.SanitizeForLog(c.Param("id")))
c.Error(errors.NewBadRequestError("Invalid tenant ID"))
return
}