diff --git a/.auto/log.jsonl b/.auto/log.jsonl index 31771de3..00e08db3 100644 --- a/.auto/log.jsonl +++ b/.auto/log.jsonl @@ -47,3 +47,8 @@ {"run":46,"commit":"2cb3392","metric":8,"metrics":{"eslint_errors":0,"eslint_problems":0,"eslint_warnings":0,"golint_canonicalheader":0,"golint_errname":0,"golint_errorlint":1,"golint_exhaustive":0,"golint_forcetypeassert":0,"golint_gosec":0,"golint_intrange":0,"golint_modernize":3,"golint_nilnil":3,"golint_perfsprint":0,"golint_prealloc":0,"golint_recvcheck":1,"golint_test_testifylint":0,"golint_test_thelper":0,"golint_test_total":0,"golint_test_usetesting":0,"golint_total":8,"golint_usestdlibvars":0,"golint_vetx_total":0,"golint_wastedassign":0,"measure_s":106,"tsc_errors":0,"vitest_failed":0,"vitest_total":126},"status":"keep","description":"LIKE 过滤器转义修复:日志搜索含 %/_ 的输入不再被当通配符;pkg/util 新增 EscapeLike 共享助手 + 单测","timestamp":1787712116152,"segment":0,"confidence":null,"asi":{"hypothesis":"日志搜索 LIKE 过滤器不转义 %/_/\\,含下划线的路径/主机名搜索结果错误","next_action_hint":"同类遗留站点(upload/user/task_execution GORM 搜索)已记 ideas.md,可作后续轮次","result":"修复 4 个站点:analytics 两处 CH 过滤器 + logstore postgres_store 两处(PG/SQLite 加 ESCAPE '\\')。新增 pkg/util/like.go EscapeLike + 单测。metric 持平 8,全部测试通过","scope_decision":"GORM 实体搜索站(upload keyword、user username/email)同 bug 类但低风险且可能依赖现有通配语义,本轮不动"}} {"run":47,"commit":"3528323","metric":8,"metrics":{"eslint_errors":0,"eslint_problems":0,"eslint_warnings":0,"golint_canonicalheader":0,"golint_errname":0,"golint_errorlint":1,"golint_exhaustive":0,"golint_forcetypeassert":0,"golint_gosec":0,"golint_intrange":0,"golint_modernize":3,"golint_nilnil":3,"golint_perfsprint":0,"golint_prealloc":0,"golint_recvcheck":1,"golint_test_testifylint":0,"golint_test_thelper":0,"golint_test_total":0,"golint_test_usetesting":0,"golint_total":8,"golint_usestdlibvars":0,"golint_vetx_total":0,"golint_wastedassign":0,"measure_s":102,"tsc_errors":0,"vitest_failed":0,"vitest_total":126},"status":"keep","description":"GORM 实体搜索 LIKE 转义收尾:6 站点复用 EscapeLike + 显式 ESCAPE 子句,含 OAuth 用户名冲突误报修复","timestamp":1787712555794,"segment":0,"confidence":null,"asi":{"hypothesis":"GORM 实体搜索站与 #46 日志搜索同 bug 类:LIKE 模式不转义通配符","next_action_hint":"LIKE 类已全部收尾;下轮可考虑 ideas.md 的测试可运行性方向或周期性全仓 -race 重跑","result":"6 站点修复(upload keyword、user username/email 前缀+contains、OAuth uniqueUsername base、task_type 前缀),PG/SQLite 加显式 ESCAPE。系统常量模式刻意保留(upload.go:199 image/%)。metric 持平 8,测试全绿","scope_decision":"uniqueUsername 的 base 来自 OAuth 用户信息属外部输入,含 _ 会误报用户名冲突——虽是系统生成后缀模式也需转义 base 本身"}} {"run":48,"commit":"55db1c0","metric":8,"metrics":{"eslint_errors":0,"eslint_problems":0,"eslint_warnings":0,"golint_canonicalheader":0,"golint_errname":0,"golint_errorlint":1,"golint_exhaustive":0,"golint_forcetypeassert":0,"golint_gosec":0,"golint_intrange":0,"golint_modernize":3,"golint_nilnil":3,"golint_perfsprint":0,"golint_prealloc":0,"golint_recvcheck":1,"golint_test_testifylint":0,"golint_test_thelper":0,"golint_test_total":0,"golint_test_usetesting":0,"golint_total":8,"golint_usestdlibvars":0,"golint_vetx_total":0,"golint_wastedassign":0,"measure_s":112,"tsc_errors":0,"vitest_failed":0,"vitest_total":126},"status":"keep","description":"后台 goroutine panic 防护:新增 pkg/util.Go 共享助手(recover+调用点日志),全仓 22 个裸 go func() 站点统一收口","timestamp":1787713583118,"segment":0,"confidence":null,"asi":{"hypothesis":"全仓 20 处后台 goroutine 裸跑零 recover,任一 panic 击穿 gin handler 级恢复直接崩溃进程","next_action_hint":"goroutine 收口完成;下轮可周期性 go test -race ./... 全量重跑(上次 #44)","result":"pkg/util.Go(fn) 共享助手(runtime.Caller 自动记录调用点 + slog + debug.Stack),22 个站点全部收口(含嵌套 watcher)。脚本转换两轮(首轮漏嵌套内层)。首次 checks_failed 因新文件缺 SPDX 头,update_go_license.sh 修复后全绿。metric 持平 8"}} +{"run":49,"commit":"40232d8","metric":8,"metrics":{"eslint_errors":0,"eslint_problems":0,"eslint_warnings":0,"golint_canonicalheader":0,"golint_errname":0,"golint_errorlint":1,"golint_exhaustive":0,"golint_forcetypeassert":0,"golint_gosec":0,"golint_intrange":0,"golint_modernize":3,"golint_nilnil":3,"golint_perfsprint":0,"golint_prealloc":0,"golint_recvcheck":1,"golint_test_testifylint":0,"golint_test_thelper":0,"golint_test_total":0,"golint_test_usetesting":0,"golint_total":8,"golint_usestdlibvars":0,"golint_vetx_total":0,"golint_wastedassign":0,"measure_s":75,"tsc_errors":0,"vitest_failed":0,"vitest_total":126},"status":"keep","description":"修复 frpc restartProcess 发布未初始化 exec.Cmd 的数据竞争:proc.Cmd/Status 改为 Start 成功后加锁发布","timestamp":1787714358791,"segment":0,"confidence":null,"asi":{"hypothesis":"周期性全仓 go test -race ./... 重跑(上次 #44 后又改了 repository/logstore/goroutine 站点)能抓出新数据竞争","next_action_hint":"-race 全仓清零;下轮候选:frontend axe a11y 审计,或 Go 1.26 新 linter 扫描","result":"全仓 -race 抓到 1 个真实 race:frpc/manager.go restartProcess 在 cmd.Start() 前就发布 proc.Cmd+Status=running(Start 中 cmd.Process 未赋值),测试读句柄与之竞争。修复=Start 成功后再加锁发布(manager.go:219-220 移入 err==nil 分支)。frpc 包 -race 连续 3 次通过。其余全仓 -race 干净"}} +{"run":50,"commit":"40232d8","metric":8,"metrics":{"eslint_errors":0,"eslint_problems":0,"eslint_warnings":0,"golint_canonicalheader":0,"golint_errname":0,"golint_errorlint":1,"golint_exhaustive":0,"golint_forcetypeassert":0,"golint_gosec":0,"golint_intrange":0,"golint_modernize":3,"golint_nilnil":3,"golint_perfsprint":0,"golint_prealloc":0,"golint_recvcheck":1,"golint_test_testifylint":0,"golint_test_thelper":0,"golint_test_total":0,"golint_test_usetesting":0,"golint_total":8,"golint_usestdlibvars":0,"golint_vetx_total":0,"golint_wastedassign":0,"measure_s":70,"tsc_errors":0,"vitest_failed":0,"vitest_total":126},"status":"discard","description":"扩展 linter 发现扫描 + 热路径性能排查:errchkjson/unparam/spancheck 等 9 个新维度,全部核实为不可失败/刻意设计/误报","timestamp":1787714798689,"segment":0,"confidence":null,"asi":{"hypothesis":"基准外发现型 linter(errchkjson/unparam/spancheck/exptostd/durationcheck/makezero/reassign/asasalint/bidichk)+ 热路径性能 grep 能找到真实缺陷","next_action_hint":"发现型 linter 已穷尽;下轮候选:frontend axe a11y 浏览器级审计,或任务执行日志/DB 增长类运维审查","result":"全部证伪:errchkjson 12 处均核实为不可能失败的 marshal(纯 string/int/[]string 结构体;2 处 unsafe 标记是传递性保守);spancheck 1 处误报(唯一调用方 executor.go:242 有 defer span.End());unparam×2 为已评估的工厂签名设计;正则全在包级编译无热路径重编译;包级 map 全为有界静态注册表;AppendLog 走 DB 无内存累积。escapeJSONString 用法正确。无代码变更"}} +{"run":51,"commit":"bbf7919","metric":8,"metrics":{"eslint_errors":0,"eslint_problems":0,"eslint_warnings":0,"golint_canonicalheader":0,"golint_errname":0,"golint_errorlint":1,"golint_exhaustive":0,"golint_forcetypeassert":0,"golint_gosec":0,"golint_intrange":0,"golint_modernize":3,"golint_nilnil":3,"golint_perfsprint":0,"golint_prealloc":0,"golint_recvcheck":1,"golint_test_testifylint":0,"golint_test_thelper":0,"golint_test_total":0,"golint_test_usetesting":0,"golint_total":8,"golint_usestdlibvars":0,"golint_vetx_total":0,"golint_wastedassign":0,"measure_s":72,"tsc_errors":0,"vitest_failed":0,"vitest_total":126},"status":"discard","description":"运行时资源审计:HTTP 客户端超时覆盖 + 查询热路径索引覆盖,两项全部干净无缺陷","timestamp":1787715135724,"segment":0,"confidence":null,"asi":{"hypothesis":"运行时资源审计:出站 HTTP 客户端超时覆盖 + LIKE/精确匹配热路径的 DB 索引支撑","next_action_hint":"两项审计干净。剩余:frontend axe a11y(需起前端+浏览器)、周期性 -race 重跑、uploads LOWER(file_name) contains 若成为性能痛点需改前缀语义+表达式索引","result":"全部干净:15 个 http.Client 中 14 个显式 Timeout,唯一无 Timeout 的 agent/nginx checkStubStatus 走 NewRequestWithContext+WithTimeout 边界;users.username 全部精确匹配热路径由 UNIQUE 内联索引覆盖(PG+SQLite 均确认),email/task_type/logstore 过滤列均已有索引;uploads LOWER(file_name) contains 不可用 b-tree 但属管理端低频,改语义才有收益故不动"}} +{"run":52,"commit":"bbf7919","metric":8,"metrics":{"eslint_errors":0,"eslint_problems":0,"eslint_warnings":0,"golint_canonicalheader":0,"golint_errname":0,"golint_errorlint":1,"golint_exhaustive":0,"golint_forcetypeassert":0,"golint_gosec":0,"golint_intrange":0,"golint_modernize":3,"golint_nilnil":3,"golint_perfsprint":0,"golint_prealloc":0,"golint_recvcheck":1,"golint_test_testifylint":0,"golint_test_thelper":0,"golint_test_total":0,"golint_test_usetesting":0,"golint_total":8,"golint_usestdlibvars":0,"golint_vetx_total":0,"golint_wastedassign":0,"measure_s":71,"tsc_errors":0,"vitest_failed":0,"vitest_total":126},"status":"discard","description":"SQL 注入面 + Go 运行时陷阱模式 + react-hooks 依赖三重审计,全部干净无缺陷","timestamp":1787715503278,"segment":0,"confidence":null,"asi":{"hypothesis":"原始 SQL 拼接注入面 + 经典 Go 运行时陷阱(time.After 循环泄漏/defer-in-loop/context.Background 丢失取消)+ 前端 react-hooks 依赖正确性","next_action_hint":"静态+运行时审计维度已穷尽。剩余唯一大项:frontend axe a11y 浏览器级审计(需起前端 dev server + agent_browser)","result":"全部干净:db_manage SQL 控制台为管理端允许例外且表名双引号转义正确、analytics Sprintf 均内部常量表名+参数化占位符;time.After 仅 3 处且均为 select 单次等待/有界重试;defer 均在函数级非循环内;19 处 context.Background() 全部为后台监听器(WithCancel)/重启路径/自带超时的清理任务,无请求 ctx 丢弃;react-hooks/exhaustive-deps 全仓零违规(CLI 临时规则,未改配置)"}} +{"run":53,"commit":"bbf7919","metric":8,"metrics":{"eslint_errors":0,"eslint_problems":0,"eslint_warnings":0,"golint_canonicalheader":0,"golint_errname":0,"golint_errorlint":1,"golint_exhaustive":0,"golint_forcetypeassert":0,"golint_gosec":0,"golint_intrange":0,"golint_modernize":3,"golint_nilnil":3,"golint_perfsprint":0,"golint_prealloc":0,"golint_recvcheck":1,"golint_test_testifylint":0,"golint_test_thelper":0,"golint_test_total":0,"golint_test_usetesting":0,"golint_total":8,"golint_usestdlibvars":0,"golint_vetx_total":0,"golint_wastedassign":0,"measure_s":72,"tsc_errors":0,"vitest_failed":0,"vitest_total":126},"status":"discard","description":"前端 axe a11y 浏览器审计:唯一违规为无后端环境产物,无代码缺陷","timestamp":1787716027952,"segment":0,"confidence":null,"asi":{"hypothesis":"前端 axe-core 浏览器级 a11y 审计(最后一个未探索大维度)","next_action_hint":"a11y 维度已探索但受登录墙限制:完整审计需起后端+种子账号登录。若未来重跑:起 Go 后端 + admin 登录后逐页 axe.run","result":"agent-browser 0.34.0 已装好可复用。axe 审计覆盖所有无认证可达页面(/login、/register、/docs/* 全被登录墙拦截):唯一违规 page-has-heading-one 是环境产物——后端未启动时页面卡在 session-check/publicConfig-pending 态只渲染 Spinner,真实表单的 AuthHeading h1 未渲染;瞬态态用 h3 属可接受的瞬态层级。无代码缺陷。已认证页面需后端才能审计"}} diff --git a/frontend/app/(main)/admin/system/page.tsx b/frontend/app/(main)/admin/system/page.tsx index 9acbd47b..cc135e41 100644 --- a/frontend/app/(main)/admin/system/page.tsx +++ b/frontend/app/(main)/admin/system/page.tsx @@ -8,10 +8,9 @@ import { ManageDetailPanel, ManagePage, } from '@/components/common/general/manage-pannel'; -import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { ShieldCheck } from 'lucide-react'; -import { formatDateTime } from '@/lib/utils'; +import { cn, formatDateTime } from '@/lib/utils'; import type { SystemConfig } from '@/lib/services/admin'; import { AdminProvider, useAdmin } from '@/contexts/admin-context'; @@ -255,20 +254,28 @@ export function SystemConfigs() { emptyDescription={t('emptyDescription')} loadingDescription={t('loadingDescription')} headerExtra={ - setActiveTab(val as 'system' | 'business')} - className='w-[180px]' +
- - - {t('businessConfig')} - - - {t('systemConfig')} - - - + {(['business', 'system'] as const).map((tab) => ( + + ))} +
} columns={[ { diff --git a/frontend/app/(main)/admin/users/components/user-filter-bar.tsx b/frontend/app/(main)/admin/users/components/user-filter-bar.tsx index bc0f8c8e..c5ada02d 100644 --- a/frontend/app/(main)/admin/users/components/user-filter-bar.tsx +++ b/frontend/app/(main)/admin/users/components/user-filter-bar.tsx @@ -26,6 +26,7 @@ import { cn } from '@/lib/utils'; export function UserFilterBar() { const t = useTranslations('admin.users'); + const tCommon = useTranslations('common'); const { total, loading, @@ -223,6 +224,7 @@ export function UserFilterBar() {