Skip to content

feat(gateway): [EPIC-GW-02] 引入 neocode:// URL 唤醒分发与网关拦截#288

Merged
phantom5099 merged 8 commits into
1024XEngineer:mainfrom
pionxe:feat/gateway-step2-urlscheme-wake
Apr 14, 2026
Merged

feat(gateway): [EPIC-GW-02] 引入 neocode:// URL 唤醒分发与网关拦截#288
phantom5099 merged 8 commits into
1024XEngineer:mainfrom
pionxe:feat/gateway-step2-urlscheme-wake

Conversation

@pionxe

@pionxe pionxe commented Apr 14, 2026

Copy link
Copy Markdown
Collaborator

目标 (Motivation & Context)

本 PR 完整实现了网关重构计划的第二步 [EPIC-GW-02],使得操作系统、浏览器或外部 IDE 可以通过 neocode:// 协议唤醒本地系统,并将任务精准派发给常驻后台的 Gateway 进程。

💡 核心架构决议说明: 经过评估,本期遵循了“最小改动与职责单一”原则:

  1. 通信载体沿用:暂不引入 JSON-RPC 重构,继续使用当前成熟的 gateway.MessageFrame 作为 IPC 传输载体(JSON-RPC 改造已延后至 EPIC-GW-03)。
  2. “哑巴代理”与“智能网关”url-dispatch 仅做 URL 解析与无脑透传;业务合法性校验统一收拢在 Gateway 侧的 wake.go 处理器中。
  3. 白名单控制:本期 MVP 阶段,Gateway 仅允许 review action 通过,其余 action 一律快速失败(Fail Fast)。

Closes #271

✨ 主要变更 (Key Changes)

1. URL 协议层 (internal/gateway/protocol)

  • 新增 neocode_url.go,实现从 neocode://...WakeIntent 结构体的标准化解析。
  • 支持提取 Action、SessionID、工作目录及 Query 参数。

2. 调度器与客户端 (internal/gateway/adapters/urlscheme)

  • 新增 dispatcher.go,负责通过本地 IPC (UDS / Named Pipe) 连接网关并发送 wake.openUrl 帧。
  • 实现了严格的结构化错误输出:遇到网关拦截或连接失败时,打印标准 JSON 错误并以 os.Exit(1) 退出。
  • 新增了系统注册器占位(Windows 最小实现与非 Windows Stub)。

3. 网关服务端 (internal/gateway/handlers)

  • 新增 wake.go 处理器及 FrameActionWakeOpenURL 动作标识。
  • 白名单校验:拦截并拒绝所有非 review 的请求,返回 invalid_action;对 review 请求强制校验 path 参数。

4. CLI 命令框架优化 (internal/cli)

  • 修改 root.go,引入 shouldSkipGlobalPreload 钩子。
  • 修复 Bug:彻底隔离 url-dispatch 与全局重度业务配置(如模型 Provider 初始化),保证分发命令的极速启动和“纯粹代理”属性。

✅ 验收标准 (Acceptance Criteria)

  • 解析器能正确拆解 neocode://review?path=README.md
  • 成功执行时,终端打印结构化的 status=ok 响应。
  • 非法 Scheme 或未知 Action(如 neocode://open),网关正确拦截并返回 invalid_action,终端 Exit 1。
  • 单独运行 url-dispatch 时,不再触发全局配置(如 Provider 未找到)的无意义报错。

🧪 测试与验证结果 (Verification)

  • 单元测试:相关新增模块覆盖率均达 95% 以上,协议层/调度层覆盖率 100%。全仓 go test ./... -count=1 全绿。

  • CLI 行为打点

    # 成功链路验证 (网关开启状态)
    $ go run ./cmd/neocode url-dispatch --url "neocode://review?path=README.md"
    # 返回: {"status":"ok","payload":{...}}
    
    # 失败拦截验证 (网关开启状态,测试未知 action)
    $ go run ./cmd/neocode url-dispatch --url "neocode://fly?path=test"
    # 返回: {"error":"invalid_action","message":"unsupported action: fly"} (Exit Code: 1)
    
    # 网关离线验证 (网关未开启状态)
    $ go run ./cmd/neocode url-dispatch --url "neocode://review?path=README.md"
    # 返回: {"error":"gateway_unreachable", ...} (Exit Code: 1)
    # (已确认不会再报 provider not found)

实现了从 OS 层 URL 唤醒到网关底层派发的全链路闭环,当前基于 MessageFrame + IPC 通信。

主要改动:
1. 协议层:新增 neocode_url 解析器,标准化输出 WakeIntent。
2. 调度层:实现 url-dispatch 适配器,作为极简代理通过 IPC (UDS/Pipe) 将 URL 意图透传给网关。
3. 网关层:新增 wake.go 处理器,实施基于白名单的 Action 校验(本期 MVP 仅放行 'review')。
4. 错误处理:Dispatcher 接收到网关业务错误(如 invalid_action)时,统一输出结构化 JSON 并以 Exit(1) 退出。
5. CLI 架构:在 rootCmd 增加判定钩子,豁免 url-dispatch 的全局业务配置预加载,确保其“轻量代理”属性,修复未启动网关时因加载 Provider 导致的报错拦截。
@pionxe

pionxe commented Apr 14, 2026

Copy link
Copy Markdown
Collaborator Author

/review

@codecov

codecov Bot commented Apr 14, 2026

Copy link
Copy Markdown

fennoai[bot]

This comment was marked as outdated.

fennoai[bot]

This comment was marked as outdated.

fennoai[bot]

This comment was marked as outdated.

fennoai[bot]

This comment was marked as outdated.

fennoai[bot]

This comment was marked as outdated.

@pionxe

pionxe commented Apr 14, 2026

Copy link
Copy Markdown
Collaborator Author

/review

fennoai[bot]

This comment was marked as outdated.

@pionxe

pionxe commented Apr 14, 2026

Copy link
Copy Markdown
Collaborator Author

/review

fennoai[bot]

This comment was marked as outdated.

@pionxe

pionxe commented Apr 14, 2026

Copy link
Copy Markdown
Collaborator Author

/review

fennoai[bot]

This comment was marked as outdated.

@pionxe

pionxe commented Apr 14, 2026

Copy link
Copy Markdown
Collaborator Author

/review

fennoai[bot]

This comment was marked as outdated.

@pionxe

pionxe commented Apr 14, 2026

Copy link
Copy Markdown
Collaborator Author

/review

@fennoai fennoai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found 1 issue worth addressing (path sanitization false positive) in the new URL wake parser.

return "", nil
}

if strings.Contains(workdir, "..") {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

strings.Contains(workdir, "..") will reject legitimate absolute paths that merely contain .. in a segment name (for example /opt/app..prod/project). This turns valid requests into unsafe_path errors. Consider checking for traversal by inspecting path segments (reject segment exactly ..) instead of substring matching.

@fennoai fennoai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Focused review completed (code quality/performance/security/docs). I found two noteworthy issues in input validation paths that can cause incorrect behavior or unsafe downstream handling.

return "", nil
}

if strings.Contains(workdir, "..") {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sanitizeWorkdir currently rejects any value containing ".." as a substring. This causes false positives for legitimate absolute paths like /opt/releases/v1..2 (not traversal). Consider validating traversal by path semantics (e.g., inspect cleaned segments / compare normalized form) instead of raw substring matching.


switch action {
case protocol.WakeActionReview:
path := strings.TrimSpace(intent.Params["path"])

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For review, the path parameter is only checked for non-empty. Since this comes from external URL input, values like ../../etc/passwd or absolute paths are currently accepted and forwarded. Add path safety validation (reject traversal / absolute paths, or constrain to workdir) before returning ACK.

@fennoai fennoai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

聚焦代码质量/性能/安全/文档一致性后,保留 2 条建议修复项如下。

Comment thread internal/cli/gateway_commands.go Outdated
return nil
}

if err := writeURLDispatchSuccessOutput(os.Stdout, result); err != nil {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

writeURLDispatchSuccessOutput 失败时这里直接返回 error,随后上层只会 exit(1),不会再输出结构化 JSON 错误。这会让 url-dispatch 在 I/O 异常路径下打破当前“统一 JSON 输出”的契约(调用方只能拿到空输出或非结构化 stderr)。建议和上面的失败分支一致:将该错误映射为结构化 {"status":"error",...} 后再退出。

return "", nil
}

if strings.Contains(workdir, "..") {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

strings.Contains(workdir, "..") 会误伤合法绝对路径(例如 /tmp/a..b/projectC:\data\v1..2\repo),导致用户无法使用实际可用目录。更稳妥的做法是先 filepath.Clean,再按路径段判断是否存在 .. 跳转语义(而不是子串匹配),并结合绝对路径校验。

@fennoai fennoai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found one reliability/performance regression in the new URL dispatcher timeout handling.


// applyDispatchDeadline 为调度连接设置统一超时控制。
func applyDispatchDeadline(conn net.Conn, ctx context.Context) error {
if ctx == nil {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

applyDispatchDeadline returns immediately when ctx == nil, which disables the documented fallback I/O timeout (defaultDispatchIOTimeout). That means callers of exported Dispatch(nil, ...) can block indefinitely on IPC read/write if the peer stalls. Please still apply a default deadline when context is nil (or normalize nil to context.Background() before deadline logic).

@fennoai fennoai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

聚焦本次 PR diff 并汇总去重后,保留 2 条值得修复的问题:1) workdir 校验存在合法路径误杀;2) Dispatch(nil, ...) 会丢失默认 I/O 超时,可能导致阻塞。

return "", nil
}

if strings.Contains(workdir, "..") {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

strings.Contains(workdir, "..") 会误判合法路径(例如目录名包含 .. 的普通绝对路径),导致 unsafe_path 假阳性。建议改为按路径段语义判断是否存在真正的 .. 段,而不是子串匹配。


// applyDispatchDeadline 为调度连接设置统一超时控制。
func applyDispatchDeadline(conn net.Conn, ctx context.Context) error {
if ctx == nil {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

applyDispatchDeadlinectx == nil 时直接返回,导致不会应用 defaultDispatchIOTimeout。这会让对外暴露的 Dispatch(nil, ...) 在对端卡住时出现无界阻塞风险。建议在 nil context 下仍设置默认 deadline(或先归一化为 context.Background())。

@pionxe

pionxe commented Apr 14, 2026

Copy link
Copy Markdown
Collaborator Author

/simplify

@fennoai

fennoai Bot commented Apr 14, 2026

Copy link
Copy Markdown
Contributor

Result

I checked the historical review log and applied the unresolved fix that was still worth addressing.

Changes pushed to this PR branch:

  • Commit: 97d57d7
  • Branch: pionxe:feat/gateway-step2-urlscheme-wake

Implemented:

  • internal/gateway/handlers/wake.go
    • Added strict safety validation for review action params.path.
    • Rejects unsafe inputs with structured error code unsafe_path when path is absolute or contains traversal segment (..).
    • Kept existing behavior for valid relative paths.
  • internal/gateway/handlers/wake_test.go
    • Added regression tests for unsafe path cases (../../..., absolute path, Windows-style ..\\...).
    • Added helper-level safety tests, including false-positive protection for names containing ...

Simplification pass:

  • Ran a code-simplifier sub-agent and accepted a small cleanup (normalizePath extraction) in wake.go.

Validation executed:

  • go test ./internal/gateway/handlers -count=1
  • go test ./internal/gateway/... -count=1

Notes on other logged comments:

  • The previously reported workdir false-positive (strings.Contains("..")) and nil-context dispatch-timeout issues are already fixed in current branch code, so no additional change was needed there.

View job run

Generated with [codeagent](https://github.com/qbox/codeagent)
Co-authored-by: pionxe <148670367+pionxe@users.noreply.github.com>
@phantom5099 phantom5099 merged commit ada5044 into 1024XEngineer:main Apr 14, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[EPIC-GW-02] 步骤 2: 引入 neocode:// URL Scheme 唤醒适配与网关分发

3 participants