diff --git a/internal/app/app.go b/internal/app/app.go index 070e0e53..9ce10592 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -101,13 +101,12 @@ func New(cfg *config.Config, log *logger.Logger, configPath string) (*App, error return nil, fmt.Errorf("初始化数据库失败: %w", err) } - // 认证管理器(数据库初始化后挂载 RBAC,以兼容旧的单密码配置) - authManager, err := security.NewAuthManager(cfg.Auth.Password, cfg.Auth.SessionDurationHours) - if err != nil { - return nil, fmt.Errorf("初始化认证失败: %w", err) - } - if err := authManager.AttachRBACStore(db); err != nil { + // 认证管理器(数据库初始化后挂载 RBAC) + authManager := security.NewAuthManager(cfg.Auth.SessionDurationHours) + if generatedPassword, err := authManager.AttachRBACStore(db); err != nil { return nil, fmt.Errorf("初始化RBAC失败: %w", err) + } else if generatedPassword != "" { + config.PrintBootstrapAdminPassword(generatedPassword) } for platform, userID := range cfg.Robots.ServiceAccountUserIDs() { user, userErr := db.GetRBACUserByID(userID) @@ -125,6 +124,9 @@ func New(cfg *config.Config, log *logger.Logger, configPath string) (*App, error monitorRetention.PurgeExpired() monitor.StartRetentionLoop(monitorRetention, log.Logger) + if err := handler.NewHITLManager(db, log.Logger).EnsureSchema(); err != nil { + log.Logger.Warn("初始化 HITL 表失败", zap.Error(err)) + } hitlRetention := hitl.NewService(db, cfg, log.Logger) hitlRetention.PurgeExpired() hitl.StartRetentionLoop(hitlRetention, log.Logger) @@ -146,13 +148,6 @@ func New(cfg *config.Config, log *logger.Logger, configPath string) (*App, error registerProjectFactTools(mcpServer, db, cfg, log.Logger) registerVisionTools(mcpServer, cfg, log.Logger) - if cfg.Auth.GeneratedPassword != "" { - config.PrintGeneratedPasswordWarning(cfg.Auth.GeneratedPassword, cfg.Auth.GeneratedPasswordPersisted, cfg.Auth.GeneratedPasswordPersistErr) - cfg.Auth.GeneratedPassword = "" - cfg.Auth.GeneratedPasswordPersisted = false - cfg.Auth.GeneratedPasswordPersistErr = "" - } - // 创建外部MCP管理器(使用与内部MCP服务器相同的存储) externalMCPMgr := mcp.NewExternalMCPManagerWithStorage(log.Logger, db) externalMCPMgr.SetToolAuthorizer(externalMCPToolAuthorizer()) @@ -181,7 +176,7 @@ func New(cfg *config.Config, log *logger.Logger, configPath string) (*App, error var knowledgeHandler *handler.KnowledgeHandler var knowledgeDBConn *database.DB - log.Logger.Info("检查知识库配置", zap.Bool("enabled", cfg.Knowledge.Enabled)) + log.Logger.Debug("检查知识库配置", zap.Bool("enabled", cfg.Knowledge.Enabled)) if cfg.Knowledge.Enabled { // 确定知识库数据库路径 knowledgeDBPath := cfg.Database.KnowledgeDBPath @@ -324,7 +319,7 @@ func New(cfg *config.Config, log *logger.Logger, configPath string) (*App, error } skillsDir := skillpackage.SkillsRootFromConfig(cfg.SkillsDir, configPath) - log.Logger.Info("Skills 目录(Eino ADK skill 中间件 + Web 管理 API)", zap.String("skillsDir", skillsDir)) + log.Logger.Debug("Skills 目录(Eino ADK skill 中间件 + Web 管理 API)", zap.String("skillsDir", skillsDir)) configDir := filepath.Dir(configPath) plantaskRel := strings.TrimSpace(cfg.MultiAgent.EinoMiddleware.PlantaskRelDir) if plantaskRel == "" { @@ -350,7 +345,7 @@ func New(cfg *config.Config, log *logger.Logger, configPath string) (*App, error } markdownAgentsHandler := handler.NewMarkdownAgentsHandler(agentsDir) markdownAgentsHandler.SetAudit(auditSvc) - log.Logger.Info("多代理 Markdown 子 Agent 目录", zap.String("agentsDir", agentsDir)) + log.Logger.Debug("多代理 Markdown 子 Agent 目录", zap.String("agentsDir", agentsDir)) // 创建处理器 agentHandler := handler.NewAgentHandler(agent, db, cfg, log.Logger) @@ -635,20 +630,20 @@ func (a *App) RunWithContext(ctx context.Context) error { } switch tlsMode { case mainTLSFromFiles: - a.logger.Info("启动 HTTPS 主服务(已启用 HTTP/2 协商)", + a.logger.Debug("启动 HTTPS 主服务(已启用 HTTP/2 协商)", zap.String("address", addr), zap.String("cert", certFile), ) case mainTLSInMemorySelfSigned: - a.logger.Info("启动 HTTPS 主服务(内存自签证书,仅测试;已启用 HTTP/2 协商)", + a.logger.Debug("启动 HTTPS 主服务(内存自签证书,仅测试;已启用 HTTP/2 协商)", zap.String("address", addr), ) } if httpRedirect { - a.logger.Info("已启用 HTTP→HTTPS 自动跳转(同端口嗅探分流)", zap.String("address", addr)) + a.logger.Debug("已启用 HTTP→HTTPS 自动跳转(同端口嗅探分流)", zap.String("address", addr)) } } else { - a.logger.Info("启动 HTTP 主服务", zap.String("address", addr)) + a.logger.Debug("启动 HTTP 主服务", zap.String("address", addr)) } // 监听 context 取消,优雅关闭 HTTP 服务器 @@ -1508,7 +1503,7 @@ func registerWebshellTools(mcpServer *mcp.Server, db *database.DB, webshellHandl } mcpServer.RegisterTool(writeTool, writeHandler) - logger.Info("WebShell 工具注册成功") + logger.Debug("WebShell 工具注册成功") } // registerWebshellManagementTools 注册 WebShell 连接管理 MCP 工具 @@ -1879,7 +1874,7 @@ func registerWebshellManagementTools(mcpServer *mcp.Server, db *database.DB, web } mcpServer.RegisterTool(testTool, testHandler) - logger.Info("WebShell 管理工具注册成功") + logger.Debug("WebShell 管理工具注册成功") } // initializeKnowledge 初始化知识库组件(用于动态初始化) diff --git a/internal/app/c2_tools.go b/internal/app/c2_tools.go index b9d95f30..20a85f19 100644 --- a/internal/app/c2_tools.go +++ b/internal/app/c2_tools.go @@ -31,7 +31,7 @@ func registerC2Tools(mcpServer *mcp.Server, c2Manager *c2.Manager, logger *zap.L registerC2EventTool(mcpServer, c2Manager, logger) registerC2ProfileTool(mcpServer, c2Manager, logger) registerC2FileTool(mcpServer, c2Manager, logger) - logger.Info("C2 MCP tools registered (8 unified tools)") + logger.Debug("C2 MCP tools registered (8 unified tools)") } func makeC2Result(data interface{}, err error) (*mcp.ToolResult, error) { diff --git a/internal/app/mcp_http_auth_test.go b/internal/app/mcp_http_auth_test.go index d741b342..83ffbfc5 100644 --- a/internal/app/mcp_http_auth_test.go +++ b/internal/app/mcp_http_auth_test.go @@ -21,11 +21,15 @@ func TestStandaloneMCPPrefersUserRBACAndDisablesGlobalTokenByDefault(t *testing. t.Fatal(err) } t.Cleanup(func() { _ = db.Close() }) - auth, err := security.NewAuthManager("admin-secret", 12) + auth := security.NewAuthManager(12) + if _, err := auth.AttachRBACStore(db); err != nil { + t.Fatal(err) + } + hash, err := security.HashPassword("admin-secret") if err != nil { t.Fatal(err) } - if err := auth.AttachRBACStore(db); err != nil { + if err := db.UpdateRBACAdminPassword(hash); err != nil { t.Fatal(err) } token, _, err := auth.Authenticate("admin", "admin-secret") diff --git a/internal/app/project_fact_tools.go b/internal/app/project_fact_tools.go index 1365dbde..2d570919 100644 --- a/internal/app/project_fact_tools.go +++ b/internal/app/project_fact_tools.go @@ -90,7 +90,7 @@ func registerProjectFactTools(mcpServer *mcp.Server, db *database.DB, cfg *confi "description": "可选:关联的漏洞记录 ID", }, "links": map[string]interface{}{ - "type": "array", + "type": "array", "description": "可选:关系边(from → 当前 fact)。finding 至少 1 条 {from:target/*, type:discovered_on};finding 上记录 exploit 用 {from:exploit/*, type:exploits}。省略保留已有边;传 [] 清空全部关系边。", "items": map[string]interface{}{ "type": "object", @@ -357,7 +357,7 @@ func registerProjectFactTools(mcpServer *mcp.Server, db *database.DB, cfg *confi }) if logger != nil { - logger.Info("项目黑板 MCP 工具注册成功") + logger.Debug("项目黑板 MCP 工具注册成功") } } diff --git a/internal/app/vulnerability_tools.go b/internal/app/vulnerability_tools.go index dd9c097a..70575b28 100644 --- a/internal/app/vulnerability_tools.go +++ b/internal/app/vulnerability_tools.go @@ -190,7 +190,7 @@ func registerVulnerabilityTools(mcpServer *mcp.Server, db *database.DB, logger * registerListVulnerabilitiesTool(mcpServer, db, logger) registerGetVulnerabilityTool(mcpServer, db, logger) if logger != nil { - logger.Info("漏洞 MCP 工具注册成功", zap.Strings("tools", []string{ + logger.Debug("漏洞 MCP 工具注册成功", zap.Strings("tools", []string{ builtin.ToolRecordVulnerability, builtin.ToolListVulnerabilities, builtin.ToolGetVulnerability,