Skip to content

Support personal conversation workspaces - #175

Open
Zhong-Chenchen wants to merge 4 commits into
Tencent:mainfrom
Zhong-Chenchen:feat/personal-workspace-issue-167
Open

Zhong-Chenchen wants to merge 4 commits into
Tencent:mainfrom
Zhong-Chenchen:feat/personal-workspace-issue-167

Conversation

@Zhong-Chenchen

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

Copy link
Copy Markdown
Contributor

What changed

个人对话现在可以直接打开可写工作区;项目未配置仓库时也可以创建空工作区,供文件操作、命令执行和预览使用。个人工作区按用户和会话隔离,并限制其产物进入共享知识库。

同时将 Go 工具链和 Docker 构建镜像更新到 1.26.11,修复导致 CI 漏洞扫描失败的 GO-2026-6859。

Closes #167

Scope

  • Platform core / API / runner
  • Public adapter / deployment
  • Classic
  • Portable
  • Shared behavior contract
  • Installer / CLI
  • Documentation only

Compatibility

已有项目仓库的检出和提交路径保持不变。空工作区不支持仓库提交或 PR/MR。项目运行删除后,已有知识库提交仍可查看和管理;个人工作区产物不能提交到共享知识库。Go 构建现在要求 1.26.11 或更新版本。

Validation

  • Go 1.26.11:工作区创建、切换与恢复、权限隔离及知识库相关定向测试通过(./internal/httpapi ./internal/engine ./internal/repo);安全更新后重新运行了这些包中名称包含 Personal 或 Scratch 的测试。
  • go run golang.org/x/vuln/cmd/govulncheck@v1.9.0 ./...(Go 1.26.11):通过,未发现代码可触达的漏洞。
  • 运行删除后的知识条目查看、编辑、发布、驳回和删除回归测试及个人工作区隔离测试通过;go vet ./internal/httpapi ./internal/engine ./internal/repo 通过。
  • python3 scripts/check-public.py、git diff --check 通过。
  • 本机无法访问 Docker daemon,未完成真实 Docker / runner 端到端验证。完整测试套件未运行;本机 Git 2.25 不支持部分现有测试使用的 git init -b。

Safety

  • I did not include credentials, internal endpoints, production data, or organization-specific infrastructure.
  • I preserved user files and unrelated changes.

@Robert0622

Copy link
Copy Markdown
Collaborator

LoopForge PR Review Bot

  • Head SHA: 6b4444daefa5b75b901edfb68b9a92838d4388a8
  • Conclusion: ✅ Pass

Checks performed (isolated worktree, Go 1.26.11 matching the go.mod bump for GO-2026-6859):

  • npm --prefix chatbot ci && npm run build → succeeded (13.87s)
  • go build ./... → succeeded
  • go test ./internal/httpapi/... ./internal/engine/... ./internal/repo/... -count=1 -timeout=300s → all passed: ok agentflow/internal/httpapi 180.932s, ok agentflow/internal/engine 53.203s, ok agentflow/internal/repo 22.856s

Not run: full repository test suite and Docker/runner end-to-end verification for personal-workspace isolation — no Docker daemon access in this environment. Relying on the targeted package tests above plus the PR author's reported govulncheck / check-public.py results.

No blocking issues found in the reviewed scope (personal conversation workspace support, empty-workspace creation when no repository is configured, per-user/session isolation). Closes #167 as described.

@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.

PR #175 review — head 6b4444daefa5b75b901edfb68b9a92838d4388a8

Request changes: knowledge submissions from deleted project runs become invisible and undeletable.

  • Where: internal/httpapi/knowledge.go:162 (restrictedKnowledgeSubmission): return !ok || run.IsWorkspace() && run.ExecutionContext.ProjectID == "". It gates list, get, update, delete, publish and reject.
  • Scenario: RunsRepo.DeleteRun (internal/repo/runs.go) does not cascade to knowledge_submissions. After a normal project run is deleted (DELETE /api/runs/:id), RunState misses (!ok). Every submission derived from that run is then treated as restricted, including published ones:
    • it disappears from the list;
    • get, update, delete, publish and reject all return 403.
  • Why it matters: admins can neither see nor clean up this existing data. That goes beyond the PR's goal of keeping personal workspaces out of the shared knowledge base, and beyond what the PR description calls conservative hiding.
  • Reproduction: a temporary handler test seeded {ProjectID:"workbench", RunID:"deleted-project-run", ArtifactID:"a1", Status:published}. Result: list visible=false, GET 403, DELETE 403.
  • Suggested fix: when the run is gone, fall back to the submission's own ProjectID: if !ok { return item.ProjectID == "" }. Submit stores the run's project, which is empty for personal workspaces. At minimum, do not block DELETE.

Non-blocking

runWriteGuard adds a RunState lookup to every /api/runs/:id* request, including SSE and log polling. The candidates/submissions endpoints also do one RunState per row.

Executed checks

  • go vet on httpapi, engine and repo: ok.
  • go test ./internal/httpapi -run 'Personal|Scratch|Knowledge|WorkspaceOpen|SubmitMR|Sandbox': 38 pass.

Comment thread internal/httpapi/knowledge.go Outdated
return item.ArtifactID != ""
}
run, ok := h.repo.RunState(item.RunID)
return !ok || run.IsWorkspace() && run.ExecutionContext.ProjectID == ""

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.

When the run has been deleted, RunState misses (!ok). Deletion does not cascade to knowledge_submissions, so every submission from a deleted project run, including published ones, becomes hidden and returns 403 on get, update, delete, publish and reject. A temporary test reproduced this: list visible=false, GET 403, DELETE 403.

Suggested fix: fall back to the stored project, e.g. if !ok { return item.ProjectID == "" }. Personal workspaces store an empty ProjectID. At minimum, keep DELETE allowed.

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 49d5871. Knowledge submissions remain accessible and manageable after their source run is deleted, with regression tests added. All CI checks pass. Could you take another look?

@fx-kurumi

Copy link
Copy Markdown
Collaborator

❌ 结论:Request changes(需要修改)

审查 head 6b4444d

个人工作区的权限隔离:我逐条检查了以下路径,没有发现越权:

  • runWriteGuard 对 /api/runs/:id* 的属主校验,覆盖读取、浏览器流、预览、终端和 artifacts。
  • /api/runs 列表过滤。
  • mayUseWorkspace:要求属主本人发起、私有会话、非共享、未关联运行,并且属于本会话打开过的工作区。
  • bindConversationWorkspace 对个人会话禁止 issue、仓库、分支和需求参数。
  • borrowableSOPRun 对空项目返回 false。
  • ConversationSandbox 在空项目下只允许共享沙箱。
  • 浏览器 canControl 只允许属主。

无仓库工作区禁止 submit_mr 的处理也正确。

Robert0622 的 bot 结论是 Pass,但它没有覆盖下面这个知识库行为变化,PR 描述里也请维护者评估这一点。我验证后认为这是需要修复的回归。

[P2] 关联运行被删除后,正常项目知识提交被隐藏且无法管理

internal/httpapi/knowledge.go:155-163(restrictedKnowledgeSubmission)把以下两类提交视为受限:

  • RunState(item.RunID) 查不到运行的提交。
  • RunID 为空但 ArtifactID 不为空的提交。

submissions GET 列表会过滤掉它们。submission 的 GET/PUT/DELETE、publish、reject 对它们一律返回 403(knowledge.go:209,237,252)。

  • 失败场景:
    1. 项目 SOP 运行或项目对话工作区的知识产物被提交进沉淀队列。
    2. 之后运行被删除。常见路径有 DELETE /api/runs/:id、删除需求(issue_routes.go:340)、清理对话(assistant_conversation_cleanup.go)。
    3. 结果:这条提交从审核队列和历史列表中消失,管理员也无法删除、驳回或发布,数据永久滞留在库里。
  • 复现:我用临时测试走了一遍(workbenchFixture)。项目运行 proj-run-kb 带知识产物,POST /api/knowledge/submissions 返回 200。repo.DeleteRun 之后:
    • 列表不再包含该条。
    • DELETE /api/knowledge/submissions/<id> 返回 403 个人工作区产物不能提交到共享知识库,reject 同样返回 403。
    • 同一个测试在 main 上:删除运行后列表仍可见,DELETE 返回 200。
  • 这一限制没有安全收益:提交只有 POST /api/knowledge/submissions 一个入口。knowledge.Service.Submit 只在带 ArtifactID 时写入 RunID,而本 PR 已在入口拒绝个人工作区产物(knowledge.go:186-197)。在本 PR 之前,引擎要求必须有项目,个人工作区运行不存在。所以不可能存在“来源是个人工作区、运行又已删除”的真实提交。“运行已删除就隐藏”实际只影响项目数据,错误文案对用户也有误导。
  • 建议:
    • 只在运行仍存在、并且确认是个人工作区(IsWorkspace() && ProjectID == "")时限制。运行缺失时按普通提交处理,必要时可以参考提交里保存的 ProjectID。
    • 相应调整 TestPersonalWorkspacePeripheralEndpoints 中 missing-run-* 的断言。
    • 顺带建议:candidates、submissions 列表对每一项调用 RunState,会加载完整的 events 和 artifacts,条目多时成本明显。只判断归属的话改用轻量的 h.repo.Run,或者批量查询即可。

可选建议(不阻塞):Go 1.26.11 的升级 main 已经包含,与 main 合并无冲突(git merge-tree)。可以在 rebase 时去掉这个提交,让 PR 只保留功能改动。

验证

  • go vet ./internal/httpapi ./internal/engine ./internal/repo:通过。
  • go test -p 4 -count=1 ./internal/httpapi ./internal/engine ./internal/repo(Go 1.26.11):
    • internal/repo 通过。
    • internal/httpapi 只有 TestMainBotBrowserStartsAndDrivesRunBrowser、TestBrowserStreamPushesFramesAndRunsCommands 两个用例失败。
    • internal/engine 只有 TestPushConversationWorkspaceCommitsAndPushesWorkBranch、TestPrepareRepositoryAppliesResponsibleUserGitIdentityOnCloneAndResume 两个用例失败。
    • 这 4 个失败与本机的浏览器、git 身份环境有关。同一批其他评审在 main 上复现了同样的失败;我自己在 main 上复跑时,engine 的两项同样失败,httpapi 的两项因为共享检出缺少 native-chat 构建产物而没能在 main 上跑起来。我判断这 4 个失败与本 PR 无关。
  • go test -count=1 -run 'Personal|Scratch|NoRepository' -v ./internal/httpapi ./internal/engine:全部通过,包含本 PR 新增的隔离、切换、外围端点和沙箱用例。
  • 临时复现测试(审查后已删除):项目运行知识提交在 DeleteRun 之后,本 PR 上列表不可见,DELETE 和 reject 返回 403;main 上可见,DELETE 返回 200。
  • 未做 Docker 或 runner 端到端验证(本环境没有 Docker daemon)。本 PR 不涉及前端可见改动,没有截图。

@Robert0622

Copy link
Copy Markdown
Collaborator

LoopForge PR Review Bot

  • Head SHA: 49d5871dabceb8c675b7adca3ae2dea8946ff108
  • Conclusion: ✅ Pass

Re-review: head moved from 6b4444daefa5b75b901edfb68b9a92838d4388a8 (previously Pass) to 49d5871dabceb8c675b7adca3ae2dea8946ff108.

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

  • npm --prefix chatbot ci --include=dev && npm run build → succeeded, web/native-chat/index.html present
  • go build ./... → succeeded
  • go vet ./internal/httpapi/... ./internal/engine/... ./internal/repo/... → clean
  • go test -count=1 ./internal/httpapi/... ./internal/engine/... ./internal/repo/... → all passed: ok agentflow/internal/httpapi 196.737s, ok agentflow/internal/engine 56.250s, ok agentflow/internal/repo 29.176s (2 MySQL-dependent tests skipped — isolated Docker MySQL required, unavailable here)
  • GitHub Actions on this SHA: all 16 checks (platform-required, e2e-required, core, browser, first-run, 4× e2e matrix, e2e-browser, validate×2, curl-install, secrets, tcmcp, opensource-scan) completed success

No blocking issues found in the reviewed scope (personal workspace write-access guard, knowledge-submission restriction for personal-workspace runs, workspace binding).

@fx-kurumi

Copy link
Copy Markdown
Collaborator

复审 head 49d5871:上次的阻塞问题已修复,撤销 Request changes

internal/httpapi/knowledge.go:157:restrictedKnowledgeSubmission 改成只有「run 仍存在且是个人工作区」才限制,run 被删除后不再一律 403,已删除项目 run 的提交可以继续查看、删除、发布、驳回。个人工作区产物在创建提交时(submissions 第 181 行起)就被拦下,所以这层放宽不会让个人工作区数据进入共享知识库。新增的 RunsRepo.RunHeader(internal/repo/runs.go)只读 run 行,不再加载节点和事件,也顺带解决了上次提的每行一次 RunState 的开销。

验证(本机,Go 1.26.11):go test -count=1 ./internal/httpapi -run 'Knowledge|Personal|Scratch|Workspace' 通过(73.6s),包括新的「run 删除后提交仍可管理」回归用例。本次提交只改后端,没有界面变化,不需要新截图。

@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.

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]: 个人对话可打开工作区,且不再强制绑定 Git 仓库

3 participants