Skip to content

Add a VS Code integration for LoopForge workflows - #174

Open
Zhong-Chenchen wants to merge 4 commits into
Tencent:mainfrom
Zhong-Chenchen:feat/vscode-extension-issue-113
Open

Zhong-Chenchen wants to merge 4 commits into
Tencent:mainfrom
Zhong-Chenchen:feat/vscode-extension-issue-113

Conversation

@Zhong-Chenchen

@Zhong-Chenchen Zhong-Chenchen commented Nov 11, 2026 •

Copy link
Copy Markdown
Contributor

What changed

Adds a standalone VS Code extension that connects to an existing LoopForge platform. Users can start a workflow with the active file and selected text, inspect runs and logs, respond to approvals, and open artifacts or available workspace files and diffs.

Remote platform URLs require HTTPS; plain HTTP is accepted only for localhost, 127.0.0.0/8 and ::1 to protect API tokens.

Also updates the Go toolchain and Docker build image from 1.26.10 to 1.26.11 to fix GO-2026-6859, which blocked the platform vulnerability scan.

Closes #113. This is a draft because successful ordinary workflows may have their workspace reclaimed immediately, so reopening a diff after completion is not guaranteed.

Scope

  • Public adapter / deployment
  • Platform core / API / runner (Go toolchain security update)
  • Classic
  • Portable
  • Shared behavior contract
  • Installer / CLI
  • Documentation only

Compatibility

Go builds now require Go 1.26.11 or newer. Desktop VS Code 1.85+; requires a reachable LoopForge platform API. The extension stores its API token in VS Code SecretStorage and does not upload or mount the local project. Workspace files and diffs depend on platform workspace availability; saved artifacts are separate. See the extension README for setup and limitations.

Validation

  • node --test --test-reporter=spec test/*.test.js in vscode-extension: passed, including remote HTTP rejection and loopback HTTP acceptance.
  • go test -count=1 -v ./vscode-extension/acceptance: passed against the latest base using an in-memory test database and real HTTP handlers/workflow engine.
  • Installed the VSIX in an isolated VS Code 1.85.2 desktop instance and exercised selection context, workflow start, status and logs requests, approval, artifact opening, workspace file/diff viewing, and connection failure. The workspace diff fixture was created manually during the approval step; this does not test AI-generated code changes.
  • python3 scripts/check-public.py: passed.
  • go run golang.org/x/vuln/cmd/govulncheck@v1.9.0 ./... with Go 1.26.11: passed, no reachable vulnerabilities found.
  • Full repository Go tests, go vet, local host validation/install/e2e scripts, and scripts/scan-secrets.sh: not run for this change.

Safety

  • I did not include credentials, internal endpoints, production data, or organization-specific infrastructure.
  • I preserved user files and unrelated changes.
  • I updated generated Classic host bundles when applicable. (Not applicable.)
  • I documented third-party content and licensing changes when applicable.

@Zhong-Chenchen
Zhong-Chenchen marked this pull request as ready for review November 11, 2026 12:15
@fx-kurumi

Copy link
Copy Markdown
Collaborator

💬 结论:Comment(仅意见,不阻塞也不批准)

审查 head daabaec(草稿,先给早期反馈,不阻塞)

整体方向不错:扩展只通过现有 /api 与平台交互,不上传/挂载本地项目;API token 存在 VS Code SecretStorage;loopforge.serverUrl 使用 "scope": "machine",工作区里的 .vscode/settings.json 无法把 token 重定向到别的服务器;客户端禁止 URL 中带凭据/query、redirect: 'error' 防止跟随跳转泄露 Authorization 头。approve/reject 带上 expected(status/attempt/reworkCount)做并发保护,也很好。以下是建议在转为 ready 前处理的几点:

1. Go 版本升级提交已与 main 重复
go.mod / Dockerfile / Makefile 升级到 1.26.11 的提交(daabaec)在当前 main(367b41d)上已经存在(main 的 go.mod 已是 go 1.26.11)。建议 rebase 后删掉这个提交,让 PR 只包含 VS Code 扩展本身,PR 描述的 Scope 里也可以去掉 "Platform core"。

2. 非回环地址允许明文 HTTP,Bearer token 会明文传输
vscode-extension/lib/client.js 的 normalizeBaseUrl 对任意主机都接受 http:。README 里只写了"远程服务器请用 HTTPS",代码层面没有约束。建议:非 127.0.0.1/localhost/::1 的 http: 地址直接拒绝,或至少在带 token 请求前弹出一次性确认。

3. 轮询无条件执行,且每次拉取全量 run 列表
extension.js:350-351 在激活后(onStartupFinished,即每个 VS Code 窗口启动都会激活)就 setInterval 每 10 秒调用 refresh(),与配置说明 "Seconds between status refreshes while a run is active" 不一致:没有配置 token、服务器不可达、或没有活动 run 时也会一直轮询。同时 GET /api/runs 服务端没有分页/limit(internal/httpapi/runs.go 的 runs 直接返回 RunSummariesFor 的全部结果),客户端再 slice(0, maxRuns);未设置 projectId 时就是全平台的 run 列表。多个开发者、多个窗口同时打开时,这会给平台带来持续的无效负载。建议:仅在视图可见且存在非终态 run 时轮询(可用 view.onDidChangeVisibility),连续失败时退避;服务端如有需要可加 limit 参数。另外 pollInterval 修改后不会生效(只在 activate 时读取一次),可以监听 onDidChangeConfiguration。

4. 受限(Untrusted)工作区下的 projectId/workflowId 预设
loopforge.projectId / loopforge.workflowId 是默认 window scope,可由仓库自带的 .vscode/settings.json 设置;startWorkflow 在已配置 workflowId 时不会再弹出选择(chooseWorkflow 中 if (value && !force) return value),用户只看到一个输入框,就会以自己的 token 在平台上启动由仓库预设的工作流。建议在 package.json 中声明 capabilities.untrustedWorkspaces(supported: "limited",并把这两个配置列入 restrictedConfigurations),或在启动前的输入框/确认中明确展示将要运行的项目和工作流名称。

5. 工作流输入里附带本机绝对路径
extension.js:190 会把 项目路径:${folder.uri.fsPath} 拼进 run input。平台侧并不能访问这个路径(README 也说明不挂载本地项目),它对 agent 没有用处,反而可能误导 agent 去访问不存在的路径,并把本机用户名/目录结构写入平台的 run 记录和日志。建议去掉,或只保留工作区名称和相对文件路径。

6. 草稿原因:完成后工作区被回收
本地跑 acceptance 测试时也能看到 cleaned terminal workspace ...,即 run 结束后 openFile/openDiff 拿不到内容。建议扩展端在 run 处于终态时直接隐藏/禁用这两个入口并提示改看产物;平台侧如果希望支持事后查看 diff,更合适的是在节点完成时把 diff 作为 artifact 持久化,而不是延长工作区生命周期。

可选小点:

  • UI 文案中英混杂且硬编码中文,可考虑使用 vscode.l10n / package.nls.json。
  • vscode-extension/acceptance 作为 Go 包会被 go test ./... 收录并依赖 node;它通过 AGENTFLOW_AUTH_REQUIRED=false 关闭了鉴权,因此 Bearer token 路径未被覆盖,可以考虑加一个带 personal token 的用例。
  • ExtensionState.refresh 中被 refreshing 挡掉的调用直接返回,startWorkflow 之后的 refresh 可能被跳过,新 run 要等下一个轮询周期才出现。

验证

  • cd vscode-extension && npm test:10/10 通过。
  • go test -count=1 -p 4 -v ./vscode-extension/acceptance:通过(本地 web/native-chat 未构建,测试时放了一个临时占位文件以满足 go:embed,测完已删除)。
  • git merge-tree HEAD origin/main:无冲突。
  • 截图:本 PR 不改 web/chatbot 界面,扩展 UI 需要 VS Code 桌面环境,未截图。

@fx-kurumi fx-kurumi left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

结论:Request changes

审查的 head 是 daabaec。上一轮我在这里只发了 Comment;复核后,下面这条属于凭据泄露问题,改为阻塞项。

[P1] 非回环地址的 HTTP 也会把 API token 明文发出去

vscode-extension/lib/client.js:16:normalizeBaseUrl 只限制协议为 http:/https:,不检查主机是不是回环地址。:39 随后对任何 baseUrl 都附带 Authorization: Bearer <token>,这个 token 取自 SecretStorage。README 第 30 行只是"建议远程用 HTTPS",代码没有强制。只要用户把 loopforge.serverUrl 配成 http://<内网或公网主机>:8090,同一网段或链路上的任何人都能拿到这个平台 token;它有用户的完整 API 权限,可以 approve/取消运行等。

复现(当前 head):

node -e "const {normalizeBaseUrl}=require('./vscode-extension/lib/client.js');console.log(normalizeBaseUrl('http://remote.example:8090'))"
# => http://remote.example:8090   (被接受)

(没有真正向任何远端发送 token。)

建议:只对 localhost / 127.0.0.0/8 / ::1 放行 http:,其他主机一律要求 https: 并给出清楚的报错。如果确实需要支持内网 HTTP,就加一个显式的 machine-scope 开关(例如 loopforge.allowInsecureHttp),默认关闭。另外在 test/ 里补上 "远端 http 拒绝 / 回环 http 允许" 两条用例。

验证

  • node --test vscode-extension/test/*.test.js:10/10 通过
  • 上面那段 URL 边界调用:http://remote.example:8090、http://10.0.0.5:8090 都被接受
  • 限制:这是 VS Code 扩展,本机没有 VS Code 宿主,所以没有界面截图;这个结论来自代码和函数调用,不代表扩展界面已经验收。

if (!raw) throw new LoopForgeError('LoopForge server URL is empty. Set loopforge.serverUrl first.');
let url;
try { url = new URL(raw); } catch (_) { throw new LoopForgeError(`Invalid LoopForge server URL: ${raw}`); }
if (!['http:', 'https:'].includes(url.protocol)) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[P1] 这里只检查协议,不检查主机。http://remote.example:8090 也会被接受,之后 request() 会对它附带 Authorization: Bearer <token>,token 走明文。建议非回环主机强制 https(或者加一个默认关闭的 machine-scope 开关),并补测试。

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

收到 我立刻解决

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

fixed in a4061ed

@Robert0622

Copy link
Copy Markdown
Collaborator

LoopForge PR Review Bot

  • Head SHA: a4061ed50a22adedb915eee1105a74ad950e35af
  • Conclusion: ⚠️ Verification blocked (CI still running)

Checks performed (isolated worktree, Go 1.26.11 matching go.mod):

  • npm test in vscode-extension (node --test) → 11/11 passed, including the new allows HTTP only for loopback addresses and requires HTTPS elsewhere test added in this commit (Require HTTPS for remote LoopForge servers)
  • npm --prefix chatbot ci --include=dev && npm run build → succeeded, web/native-chat/index.html present (unchanged by this commit, re-verified since go.mod/Dockerfile carry the shared Go 1.26.11 bump)
  • go build ./... → succeeded; go vet ./vscode-extension/... ./internal/httpapi/... ./internal/repo/... → clean
  • go test -count=1 ./vscode-extension/acceptance/... → PASS (TestExtensionClientAgainstRealPlatform against real HTTP handlers)
  • Reviewed the new normalizeBaseUrl HTTPS-enforcement logic in lib/client.js: requires HTTPS for any non-loopback host, loopback carve-out matches localhost, 127.0.0.0/8, ::1; relies on WHATWG URL's IPv4 canonicalization ahead of the regex check, which matches Node's URL behavior. No injection/exec risk found (child_process/exec(/eval(/Function( not present).
  • GitHub Actions on this SHA: 12 of 16 checks completed success so far (validate×2, curl-install, secrets, tcmcp, opensource-scan, 4× e2e matrix); first-run, e2e-browser, browser, core were still in_progress as of this review and had not completed after ~2 minutes of polling.

Missing to resolve: wait for the remaining 4 in-progress checks (first-run, e2e-browser, browser, core) to finish. All local evidence for this increment (the security-relevant HTTPS enforcement) is already clean; this will likely become a Pass once CI completes, pending no new findings there.

@fx-kurumi

Copy link
Copy Markdown
Collaborator

复审 head a4061ed:上次的 [P1] 已修复,撤销 Request changes

vscode-extension/lib/client.js:21-24:非回环主机现在强制 HTTPS,构造 LoopForgeClient 时就会抛错,不会走到附带 Authorization 的 request()。extension.js:125 是唯一构造入口,也会经过这层校验。

验证(本机):

  • node --test vscode-extension/test/*.test.js:11/11 通过(含新加的回环/非回环用例)
  • 边界调用 normalizeBaseUrl:http://remote.example:8090、http://10.0.0.5:8090、http://localhost. 均被拒绝;http://0x7f000001、http://2130706433、http://127.1 被 WHATWG URL 规范化成 127.0.0.1 后放行,http://[0:0:0:0:0:0:0:1] 规范化为 [::1] 后放行,都确实是回环地址,符合预期。
  • 限制:本机没有 VS Code 宿主,没有扩展界面截图。

@fx-kurumi
fx-kurumi dismissed their stale review November 11, 2026 15:18

Re-reviewed at current head: the blocking issue is fixed. See the latest fx-kurumi re-review comment.

@Robert0622

Copy link
Copy Markdown
Collaborator

LoopForge PR Review — head 8f35a709197bea92922b7bb53818ebeb1dd01b7f
Verdict: ✅ Pass

  • Scope: 17 files, +993/-5. Adds a standalone VS Code extension (vscode-extension/) that talks to an existing LoopForge platform (start a workflow with the active file/selection as context, inspect runs/logs, respond to approvals, open artifacts/workspace files/diffs), and bumps the Go toolchain 1.26.10→1.26.11 (Dockerfile, Makefile, go.mod) to close GO-2026-6859, which was blocking the platform vulnerability scan. Closes [Feature]: 提供 VS Code 插件 #113.
  • Security-relevant check: vscode-extension/lib/client.js#normalizeBaseUrl rejects credentials/query/fragment in the server URL and requires HTTPS for every non-loopback host (plain HTTP allowed only for localhost, 127.0.0.0/8, ::1); requests also set redirect: 'error' to prevent a silent cross-host redirect from leaking the bearer token. The API token itself is stored via VS Code SecretStorage, never written to settings or logs.
  • Local verification (isolated sandbox, no secrets/prod access):
    • node --test --test-reporter=spec vscode-extension/test/*.test.js — 11/11 pass (URL normalization incl. loopback-only HTTP, bearer/JSON request building, path encoding, artifact/diff flows, approve/reject stale-decision handling, mocked vscode API).
    • node -c vscode-extension/extension.js — syntax OK.
    • Searched workflows/Dockerfile/Makefile/go.mod for leftover 1.26.10 references — none found; the toolchain bump is applied consistently.
  • Not run locally: go build ./... and vscode-extension/acceptance/platform_test.go (spins up a real httptest Go server and shells out to platform-client.js) — this sandbox has no Go toolchain installed. CI on this head (8f35a70) is green across all checks (platform-required, e2e-required, validate ×2, e2e ×4, core, browser, secrets, curl-install, tcmcp, first-run), which covers the Go build/test this review couldn't run directly.
  • No blocking issues found in the reviewed diff.

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.

[Feature]: 提供 VS Code 插件

3 participants