Replies: 1 comment
|
[2026-04-28 update] 经过安全分析,本评论原推荐的"aevatar 本地加密持 refresh_token (Local stop-gap)"路径已被否决。最终方向走 NyxID broker 模型:aevatar 仅持不透明 下文保留原分析(NyxID 已有 OAuth/OIDC surface 与 RFC 8693 Token Exchange)作为评估上下文,但结论部分(走 Local)请以 ADR-0017 为准。 NyxID 已经是完整 OAuth/OIDC server,#400 的 5 个 ask 大部分是已有能力的重复发明回头扫了一遍 (
#400 列的 5 个 NyxID 侧改动 → 已有 OAuth primitive 的对照:
但 RFC 8693 Token Exchange 不能完全替代 broker 语义 —— 它仍要求接入方先持有 user 的 access_token( 最终方向:NyxID broker,aevatar 持不透明 binding_idaevatar 注册成 NyxID OAuth client ( aevatar grain state / projection / log 持有 zero long-lived secret material,对齐 #375 不变量。 为什么否决 Local stop-gapaevatar 是跑任意 LLM tool 的 agent runtime(prompt injection / tool 越权属于固有风险)。这类 host 上 grain state 内的 secret material 即便加密,RCE 后攻击者几乎一定能拿到
第二个权衡是 unblock 速度 vs. 长期正确性:Local 立即 unblock,但 NyxID#549 落地后还要做数据 wipe + 加密字段下线,迁移成本不便宜;直接走 Remote 等待时间换的是终态架构上 zero secret material。aevatar 当前 bot owner-shared 模式可继续运行(不 regression),等待是可接受的代价。 落地路径aevatar 侧实现 gated on ChronoAIProject/NyxID#549。在此之前可平行落地:
NyxID#549 ready 后: 详见 ADR-0017 (#477)。 |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
相关:#375(Aevatar 线上零 secret material + capability broker 边界)、ChronoAIProject/NyxID#505(NyxID as Capability Broker scope)、本提案对应 NyxID 侧讨论:ChronoAIProject/NyxID#511
背景
目前 Lark bot 的消息链路是:
/api/webhooks/nyxid-relayNyxIdRelayAuthValidator验 JWT → 解出scope_idscope_id来自ChannelBotRegistrationEntry,也就是谁注册了这个 botConversationGAgentactor id ={canonicalKey}:scope:sha256(scope_id)ChannelConversationTurnRunner.BuildReplyMetadata把scope_id和user_access_token塞进AgentToolRequestContext去打 LLM结果:任何人跟 Lark bot 聊天都是在代表 bot owner 的 NyxID 账号说话。消息里的
sender.canonical_id(Lark user_open_id)只被记录,不影响 credential 选择。对于个人生产力场景(每个人自己的 LLM 额度、自己的 NyxID 配置、自己的 tool 权限),这是错误的默认值。
提议
把"Lark bot"理解为一个带完整鉴权的 CLI 壳:每个 Lark user 第一次交互时走
/init走一轮 NyxID 登录,之后这个 Lark user 发来的消息用他自己的 NyxID subject 跑 LLM、tool、capability。本质上是"外部 subject 绑定 NyxID subject"的一个实例 —— 以后 Telegram、Discord、Slack 同理。
架构草案(延续 #375)
新概念
ExternalSubjectRef(platform, tenant, external_user_id)NyxSubjectRefExternalIdentityBindingGAgentExternalSubjectRef → NyxSubjectRef的权威 actorBindingChallengegrain state 只存
NyxSubjectRef和jti(都是 opaque 标识符,不是 secret material),满足 #375 的不变量。/init交互流程Handle 不跨 event sourcing 边界,跟
reply_token一样只活在 actor runtime state,一次 turn 用完即弃。需要改的地方
Aevatar.GAgents.Channel.Identity(或类似命名)承载ExternalIdentityBindingGAgent+ projection +IExternalIdentityBindingQueryPortChannelConversationTurnRunner.RunInboundAsync开头增加 slash-command 前置路由BuildReplyMetadata从"透传 bot owner user_access_token"改成"ResolveAsync 找 nyx_subject → broker.IssueShortLivedAsync → 写nyxid.capability_handle"nyxid.access_token改成nyxid.capability_handle,更诚实CapabilityHandle/BindingChallenge不得出现在任何 grain state / event / projection document 字段树需要 NyxID 侧做什么
见对应的 NyxID discussion(见顶部链接)。总结:
POST /api/v1/bindings/challenges签 challenge/cli-auth页支持binding_jti参数jwt_keys)GET /api/v1/bindings?external_subject=...查询这些都在 NyxID 现有产品范围内(身份 + credential broker),不是让它做 general vault。跟 #505 的 capability broker scope 放在一起就能装下。
待决问题
/init,否则拒答(最纯粹)/init是 turn runner 前置 intent 还是 LLM tool?BindingTool让 LLM 也能触发自然语言场景。跟 #375 的关系
这个 RFC 是 #375 的具体应用场景 #1,不是并行提案:
INyxIdCapabilityBroker由本提案驱动落地,但 broker 的通用约束(arch test、zero secret material)完全承袭 [RFC] Aevatar 线上零 secret material — 从 Day One 演化到 capability-broker 边界 #375ListAsync/IssueShortLivedAsync保留,本提案补充StartExternalBindingAsync/ResolveBindingAsync/RevokeBindingAsync三个 binding-specific 方法落地顺序
ExternalIdentityBindingGAgent+ proto + projectionINyxIdCapabilityBroker接口 + stub 实现评论区留给 scope / UX / 协议选型讨论。
All reactions