From 453f7e5d905eee38d8512ac31f9bde7ab0cb23fe Mon Sep 17 00:00:00 2001 From: ryan Date: Wed, 26 Aug 2026 13:14:59 +0800 Subject: [PATCH] =?UTF-8?q?=E5=91=A8=E6=9C=9F=E6=80=A7=20-race=20=E9=87=8D?= =?UTF-8?q?=E8=B7=91=E6=8A=93=E5=88=B0=E7=9C=9F=E5=AE=9E=20bug=EF=BC=9AwsC?= =?UTF-8?q?lientCore.enqueue=20close=20=E5=90=8E=20select=20=E9=9A=8F?= =?UTF-8?q?=E6=9C=BA=E9=80=89=E6=8B=A9=E8=87=B4=E5=A5=91=E7=BA=A6=E8=BF=9D?= =?UTF-8?q?=E5=8F=8D=EF=BC=9B=E7=A1=AE=E5=AE=9A=E6=80=A7=E5=85=88=E6=9F=A5?= =?UTF-8?q?=20done=20=E4=BF=AE=E5=A4=8D+=E6=B5=8B=E8=AF=95=E5=BE=AA?= =?UTF-8?q?=E7=8E=AF=E5=8A=A0=E5=9B=BA+gofmt=20=E5=AD=98=E9=87=8F=E6=BC=82?= =?UTF-8?q?=E7=A7=BB=E6=B8=85=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Result: {"status":"keep","total_issues":8,"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":95,"tsc_errors":0,"vitest_failed":0,"vitest_total":126} --- .auto/ideas.md | 14 ++++++++++++++ .auto/log.jsonl | 1 + internal/apps/openflare/websocket/agent_hub.go | 3 --- internal/apps/openflare/websocket/client_core.go | 5 +++++ .../apps/openflare/websocket/client_core_test.go | 8 ++++++-- internal/apps/openflare/websocket/flared_hub.go | 1 - internal/apps/openflare/websocket/relay_hub.go | 1 - 7 files changed, 26 insertions(+), 7 deletions(-) diff --git a/.auto/ideas.md b/.auto/ideas.md index a1ff6c44..05a1f350 100644 --- a/.auto/ideas.md +++ b/.auto/ideas.md @@ -141,3 +141,17 @@ value='' 时 placeholder 不显示,combobox 无名需 aria-label 兜底。 - 抽查其余页面(websites/[zoneId]、origins/detail、responses 编辑器等富交互页) ——contrast 已由主题修复覆盖,预期只剩个别控件名。 - 周期性 go test -race ./... 全量重跑(上次干净为 run #49 后)。 + +## Run #56(富交互页抽查,keep,63e3b852) + +- 扫描 11 页:websites/origins/proxy-routes/certificates/dns-accounts 直接 0 违规 + (indigo-600 主题修复已覆盖全站 contrast)。 +- 修复 3 处并复扫归零: + 1. cloudflare/components/sync-tasks-panel.tsx 状态筛选 SelectTrigger 加 aria-label + (Radix SelectValue value='' 时 placeholder 不渲染,combobox 无名)。 + 2. components/common/settings/access-token.tsx 安全提示 text-amber-600→amber-700 + (12px 小字对比度不足)。 + 3. settings/notifications 面包屑页缺 h1 → sr-only h1。教训:h1 不能作为 + BreadcrumbList 子元素(axe list 规则报 list 语义破坏),须放 外; + BreadcrumbPage 无 asChild 支持。 +- a11y 维度至此穷尽:累计 14 页 axe 全部 0 违规。 diff --git a/.auto/log.jsonl b/.auto/log.jsonl index 77ec0d5b..314c6844 100644 --- a/.auto/log.jsonl +++ b/.auto/log.jsonl @@ -54,3 +54,4 @@ {"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 属可接受的瞬态层级。无代码缺陷。已认证页面需后端才能审计"}} {"run":54,"commit":"451ce52","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":93,"tsc_errors":0,"vitest_failed":0,"vitest_total":126},"status":"keep","description":"认证页 axe a11y 审计+修复:7 处布局级真实违规全修,复扫验证 dashboard/admin/system 归零;基准 total_issues 保持 8 不变(纯质量收益)","timestamp":1787718397798,"segment":0,"confidence":null,"asi":{"hypothesis":"认证页 axe a11y 审计(起后端+登录突破登录墙):修复布局级真实违规","next_action_hint":"已验证 / 与 /admin/system 归零。剩余页面级:admin 表格行内操作按钮/Switch 无 aria-label、muted 文本对比度——需逐表补标签,工作量大已归档 ideas.md","result":"修复 7 处全局问题并复扫验证:sidebar 折叠按钮 aria-label、Sidebar role=navigation(region 违规 18 节点/页清零)、header Kbd 对比度 text-foreground/70(每页 1 处)、dashboard 4 个 Progress aria-label、分页按钮 aria-label、空态/错误/加载 h3→p(heading-order 清零)、admin/system 无内容 Tabs 改 aria-pressed 按钮组(aria-valid-attr-value critical 清零)。dashboard 与 admin/system 现 0 违规","setup":"审计环境:后端 go run . api @:3100(CONFIG_PATH=/tmp/of-audit/config.yaml,sqlite+redis host 网络 docker)、前端 pnpm dev --port 3002(WAVELET_BACKEND_URL=:3100)、admin 密码经 reset-passwd 重置"}} {"run":55,"commit":"e66dea9","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":85,"tsc_errors":0,"vitest_failed":0,"vitest_total":126},"status":"keep","description":"a11y 收尾:主题级对比度根因修复(indigo-500→600)+12 处控件 accessible name+4 处 heading-order,7 页复扫全 0 违规;基准 total_issues 保持 8","timestamp":1787719908229,"segment":0,"confidence":null,"asi":{"hypothesis":"页面级 a11y 批量收尾:主题级 color-contrast 根因 + 表格/表单控件 accessible name","next_action_hint":"7 页复扫全 0 违规。剩余:其余页面(websites/origins/cloudflare 等仅扫过 contrast 已由主题修复覆盖)可抽查;-race 周期重跑","result":"根因1:--primary indigo-500(#6366f1) 对 #fafafa 仅 4.27 → 改 indigo-600 oklch(51.1% 0.262 276.966)(~6.8 AA),全站 contrast 清零(一处主题修复覆盖所有页面)。修复 12 处控件名:access-analytics 刷新按钮、events-tab Switch/edit/delete、openflare-ops ToggleRow Switch+geoip/kuma Select+FieldInput Input htmlFor+discovery Textarea、table-browser/sql-console SelectTrigger;heading-order:cache-manager/user-detail-sheet h4→p、task-manager h3→p、file-manager noFiles h3→p;新增 admin.logs.analytics.refresh i18n 键(en/zh)+merge-i18n-fragments。教训:settings 表单异步渲染,早前扫描漏报 label 违规需 wait 5s 后再 axe.run;Radix SelectValue value='' 时 placeholder 不显示致 combobox 无名,须 aria-label 兜底","setup":"审计环境同 run#54:后端:3100(sqlite) + docker redis host 网络 + pnpm dev --port 3002"}} +{"run":56,"commit":"63e3b85","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":85,"tsc_errors":0,"vitest_failed":0,"vitest_total":126},"status":"keep","description":"富交互页 a11y 抽查收尾:8+3 页扫描,修复 cloudflare 筛选器无名/access-token amber 对比度/notifications 缺 h1 共 3 处,全部复扫归零;基准 total_issues 保持 8","timestamp":1787720716912,"segment":0,"confidence":null,"asi":{"hypothesis":"富交互页抽查(websites/origins/proxy-routes/certificates/cloudflare/dns-accounts/settings 子页)","next_action_hint":"11 页扫描全部归零,a11y 维度已穷尽。剩余:周期性 -race 重跑;审计环境复用法在 ideas.md","result":"websites/origins/proxy-routes/certificates/dns-accounts 5 页直接 0 违规(主题修复覆盖);3 处新发现全修复并复扫验证:cloudflare 同步面板状态筛选 SelectTrigger 加 aria-label(statusPlaceholder);access-token 安全提示 amber-600→amber-700(12px 小字对比度 4.5 不达标);notifications 面包屑页加 sr-only h1——教训:h1 不能放 BreadcrumbList 内(破坏 list 语义 axe list 规则),BreadcrumbPage 无 asChild 需放 Breadcrumb 外","setup":"审计环境同前:后端:3100 + docker redis host 网络 + pnpm dev --port 3002"}} diff --git a/internal/apps/openflare/websocket/agent_hub.go b/internal/apps/openflare/websocket/agent_hub.go index 1c63d996..9fe4ff64 100644 --- a/internal/apps/openflare/websocket/agent_hub.go +++ b/internal/apps/openflare/websocket/agent_hub.go @@ -12,7 +12,6 @@ import ( "time" "github.com/gin-gonic/gin" - ) const ( @@ -35,8 +34,6 @@ type agentClient struct { onStatus AgentStatusHandler } - - type agentHub struct { mu sync.RWMutex clients map[string]*agentClient diff --git a/internal/apps/openflare/websocket/client_core.go b/internal/apps/openflare/websocket/client_core.go index 097f8e86..d9358729 100644 --- a/internal/apps/openflare/websocket/client_core.go +++ b/internal/apps/openflare/websocket/client_core.go @@ -36,9 +36,14 @@ func (c *wsClientCore) close() { // enqueue best-effort delivers message; it never blocks and fails fast when // the client is closed or its send buffer is full. func (c *wsClientCore) enqueue(message Message) bool { + // 先确定性检查 closed:若与发送合并在同一个 select,两个 case 同时就绪时 + // Go 会随机选择,close 后仍可能投递成功。 select { case <-c.done: return false + default: + } + select { case c.send <- message: return true default: diff --git a/internal/apps/openflare/websocket/client_core_test.go b/internal/apps/openflare/websocket/client_core_test.go index 4e6cdd52..28c63274 100644 --- a/internal/apps/openflare/websocket/client_core_test.go +++ b/internal/apps/openflare/websocket/client_core_test.go @@ -35,8 +35,12 @@ func TestWSClientCoreEnqueueFailsAfterClose(t *testing.T) { done: make(chan struct{}), } core.close() - if core.enqueue(Message{Type: messageTypePing}) { - t.Fatal("enqueue must fail after close") + // 循环多次:若 close 检查与发送合并在同一个 select,两 case 同时就绪时 + // Go 随机选择,单次调用可能碰巧通过。 + for range 50 { + if core.enqueue(Message{Type: messageTypePing}) { + t.Fatal("enqueue must fail after close") + } } } diff --git a/internal/apps/openflare/websocket/flared_hub.go b/internal/apps/openflare/websocket/flared_hub.go index 203ee28e..1b56b8ae 100644 --- a/internal/apps/openflare/websocket/flared_hub.go +++ b/internal/apps/openflare/websocket/flared_hub.go @@ -23,7 +23,6 @@ type flaredClient struct { wsClientCore } - type flaredHub struct { mu sync.RWMutex clients map[string]*flaredClient diff --git a/internal/apps/openflare/websocket/relay_hub.go b/internal/apps/openflare/websocket/relay_hub.go index b39cbe79..fe36be3a 100644 --- a/internal/apps/openflare/websocket/relay_hub.go +++ b/internal/apps/openflare/websocket/relay_hub.go @@ -17,7 +17,6 @@ type relayClient struct { wsClientCore } - type relayHub struct { mu sync.RWMutex clients map[string]*relayClient