Commit Graph

8 Commits

Author SHA1 Message Date
Blizzard ac38d5e663 fix(prod): 后端生产级 A 类硬伤全清(7 项:授权/崩溃点/全表扫/限流/鉴权/限额)
部署前生产级审计(可靠性/数据层/安全三路)后,清掉 7 处代码级硬伤:

A1 后台定时器 goroutine 无 panic recover → 单个 DB panic 崩整个 gateway。加 safeGo/
   safeCall,包住订阅/掉单补偿/微信推送/探针 goroutine,单轮 tick 再兜一层。
A2 提示词控制面(建/激活/停用,热广播全服务)只 RequireAuth → 任意登录用户改全局提示词。
   三写端点+列表挂 RequireAdmin。
A3 HITL 审批端点无角色门 → viewer 可放行烧钱执行。加 RequireTenantRole(member)。
A4 审计/护栏列表 limit 无校验,limit=-1 让 gorm 取消 LIMIT 全表扫。加 clampLimit/
   clampOffset,AdminTasks/AdminSpaces 补上界。
A5 限流 Redis 一挂就完全放行(fail-open)。加进程内固定窗口兜底(fail-safe) + 登录/注册
   按 IP 专用严限流(10/min)。
A6 公开 by-id 端点(stream/exec/report导出/kb导入流)无鉴权无租户过滤。加
   AuthFromHeaderOrQuery(从 ?token= 取 JWT) + task/report 按 owner 归属校验;桌面端
   5 处 EventSource/下载 URL 经 tokenQuery 附 JWT。
A7 文件上传无大小上限(整文件进内存 OOM 面) → 50MB 闸(KB_MAX_UPLOAD_BYTES)+ LimitReader;
   http.Server 加 ReadHeaderTimeout/ReadTimeout/MaxHeaderBytes(不设 WriteTimeout 保 SSE)。

带单测:clampLimit/safeCall/procLimiter/AuthFromHeaderOrQuery/TaskOwner。
build+vet+全量 test 绿;desktop tsc 绿。B(迁移工具/实时探针/出网韧性/登录锁定/leader选举)
与 C(TLS/PG HA/K8s/备份自动化/可观测)分期后做,参照 production_readiness.md。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 15:04:47 +08:00
Blizzard 23b8fa5e8a feat(gateway): 安全收口 —— CORS 生产收紧 + 限流按用户(T4.F)
- CORS:开发期缺省仍放行 *(便利);生产(APP_ENV=prod/GIN_MODE=release)未显式配
  CORS_ALLOW_ORIGIN 则不发 ACAO 头(浏览器按同源拦截),逼运维显式配置允许的源
- 限流键改「已认证按 uid、未认证按 IP」:企业网多人共享出口 IP 不再互相拖累,
  单用户换 IP 也绕不过;中间件顺序调整 Auth 前置于 RateLimit(否则取不到 uid)
- isProd() 判定与 middleware.RequireAdmin 同口径
- live 冒烟:登录/认证请求正常(重排未破链),dev CORS 仍 *

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 13:55:20 +08:00
Blizzard 9e43d07428 feat(gateway): 护栏拦截事件落库 + 安全事件流(T4.B)
- store.GuardrailEvent 表(sundynix_guardrail_event) + AppendGuardrailEvent/ListGuardrailEvents
- middleware.Guardrail(db):命中 blocked/suspect 时 best-effort 落库
  (actor/kind/reason/signals/method/path/ip,独立超时 ctx)
- GET /api/v1/admin/guardrail-events:安全事件流(倒序,翻页)
- store.clampPage 抽出分页归一(audit/guardrail 共用)
- live:注入 "ignore all previous instructions" → 422 硬拦 + 事件留痕(kind=blocked)
- DEPTH_ROADMAP T4.B 护栏事件打勾

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 09:31:31 +08:00
Blizzard 7bfea74cc0 feat(perf): 容量压测器 + 平台天花板实测曲线
cmd/loadtest:闭环加压器,阶梯并发,经 SSE 流检测完成(非轮询,避免轮询放大把网关
压成假瓶颈),输出吞吐 + 延迟分位。配套两个 benchmark 开关:
- dispatcher LLM_FORCE_STUB=1 + LLM_STUB_TTFT_MS/INTERTOKEN_MS=0:绕开真实 LLM 推理,
  量平台自身全链路天花板(不烧 token、不被模型节奏掩盖)。
- gateway RATE_LIMIT_PER_MIN 可配(缺省 120):压测放开限流。

实测(单 dispatcher、并发64、stub):
- 单任务纯平台开销 ~42ms;吞吐峰值 ~110 全链路任务/秒(饱和点 并发32–64);
  并发128 优雅降速,256 硬崩。
- 吞吐瓶颈不是 DB 连接数(池 25→80 吞吐不变),是每任务多跳管线综合成本;
  256 崩根因为 DSN 用 localhost、pgx 每连接解析 → 连接churn致 DNS 取消(易修)。
- 关键判断:平台 42ms ≪ LLM 秒级出答案,平台不是瓶颈、GPU 才是;横向拆服务喂满 GPU 集群
  的意义成立。细节与曲线见 project_analysis「容量实测」。

stub 延迟改 env 可配(默认值不变);不影响线上路径。dispatcher+gateway build/vet/test 全绿。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 11:46:50 +08:00
Blizzard 2f78fc565e feat(harness): 输入护栏升级 —— 归一化反绕过(Tier1) + LLM 越狱分类器(Tier2)
原输入护栏纯正则,空格/编码/同形字一改写即漏,且 bannedTerms 空置。升级为两层:

Tier1(网关同步、无 LLM):先归一化再匹配,干掉绕过——
- 小写 + 去零宽字符 + 去变音符 + 同形字折叠(西里尔/希腊→拉丁) +
  拆字间隔还原(i g n o r e / i.g.n.o.r.e → ignore) + base64 解码回扫
- 多视图(原文/归一化/紧凑/解码)匹配高精度注入正则,无需穷举变体
- bannedTerms 经 GUARDRAIL_BANNED_TERMS env 落地
- 软信号(jailbreak/developer mode/无限制…)→ 灰区,放行但打 safety_check 标志

Tier2(dispatcher harness LLM 分类器,escalation):
- 仅对灰区任务执行前调 LLM 裁决 jailbreak+severity,≥0.7 → rejected
- 明确干净/恶意的不付 LLM 成本;模型抖动/解析失败 fail-open 不误锁正常用户

契约新增 MetaSafetyCheck 透传灰区标志;orchestrator 加执行前护栏门控 + SetGuardian。
网关 6 单测 + dispatcher 4 单测,三模块全绿。live:拆字/base64/西里尔同形字均 422 拦,
恶意灰区被 LLM 拒(severity 1)、良性灰区(海盗 roleplay)放行完成。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 09:38:34 +08:00
Blizzard e63632adf5 feat(gateway): 输入护栏拦提示词注入/超大体(弃用空桩)+ 单测
Guardrail 中间件此前是空桩(直接 c.Next)。落地输入护栏:

- 新增纯逻辑包 internal/guardrail:Inspect(body) 检测提示词注入(忽略既定指令/
  角色越权/诱导泄露提示词,中英文模式)+ 超大体(>256KB),与 HTTP 解耦便于单测;
  敏感词黑名单留空可扩展。
- 中间件:仅对带 JSON 体的 POST/PUT 检查(文件上传 multipart 与 GET/SSE 跳过);
  限读 + 命中拦截返回 422;未命中则还原请求体(io.NopCloser)供 handler 读取。
- 输出护栏不在网关做:Token 流是 SSE 实时流,网关缓冲会破坏流式 —— 标到路线图,
  应在 dispatcher token 发射层做。

验证:
- 单测:正常输入不误拦、中英文注入均拦、超大体拦、边界恰好放行。
- 实跑(nats+gateway):注入(中/英) → 422 带原因;干净输入 → 202 且 body 正确还原、
  handler 正常发布到 NATS。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 15:19:14 +08:00
Blizzard e5fa0ae36c feat: Gateway store 桩换真实 GORM/Postgres + go-redis (含自动迁移与优雅降级)
第 2 层网关持久层落地,遵守 sundynix_ 表名前缀 + AutoMigrate 约定。

- store: GORM(NamingStrategy 前缀 sundynix_/单数) → User=sundynix_user, Task=sundynix_task
  启动 AutoMigrate;go-redis/v9 滑动窗口限流(Incr+Expire,按 IP)
- 优雅降级:连不上库则 warn 继续(不 fatal),保证无 Docker 的 make demo 仍跑通
- handler: SubmitTask 持久化任务(best-effort),Billing 真实读库返回 tasks_submitted
- main: OpenPostgres/OpenRedis 读 POSTGRES_DSN/REDIS_ADDR 环境变量
- 验证: 4 模块 build ✓;e2e 3 测试 PASS;live 双路径(真实库持久化 + 坏DSN降级)实测通过

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 11:43:53 +08:00
Blizzard c7a02c3905 feat: 初始化 sundynix-agentix 分层式 AI Agent 平台脚手架
5 层 + 1 条 NATS 零拷贝消息总线的 monorepo(Monolith First → Microservices Morph B)。
纵向主干(任务流 + Token 流回流)已真实跑通,横向各层能力为带注释的桩。

已贯通(real code):
- sundynix-shared: 共享契约 + JetStream/core NATS 真实收发(bus) + 内嵌 NATS(devnats) + e2e 测试
- sundynix-gateway: Gin 接入 + DSL 解析组装 + NATS Publish + SSE 流式输出
- sundynix-dispatcher: NATS 消费 + Eino Orchestrator 流式回流 + 熔断器 + LLM Pool 占位流式
- 链路: HTTP POST → DSL → sundynix.tasks.* → Dispatcher → Token 经 sundynix.streams.<id> 回流 → SSE
- 基础设施: docker-compose(nats/postgres/redis/neo4j/milvus) + Makefile(make demo/e2e)

待填(桩):
- Eino 图编排 compose.NewGraph、LLM Pool 接 vLLM/Ollama
- Gateway store 换真实 pgx/redis
- sundynix-mcp-go: Bleve+Milvus+Neo4j 混合检索 / UniOffice / 外部 API
- sundynix-mcp-py: gVisor 沙箱 / MinerU(PaddleOCR) / Docker 解释器
- sundynix-desktop: React Flow 画布 → DSL 导出 → SSE 展示
2026-06-10 11:00:29 +08:00