feat(repository-plugin): load trusted package code

This commit is contained in:
Tianyi Cui
2026-08-08 19:25:14 +08:00
parent a0c64f4906
commit 033fa4b0b1
34 changed files with 590 additions and 149 deletions

View File

@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write .agents/notes/implemented/bug-fix/2026-08-08-host-owned-git-repository-plugin-preparation.md
2026-08-08-host-owned-git-repository-plugin-preparation.md: 47410bf3c55455a971ec347eab4e8b37ea26c6a5
2026-08-08-host-owned-git-repository-plugin-preparation.zh.md: 64c37543d34147c41fc7a362040c7ada8fde0652
2026-08-08-host-owned-git-repository-plugin-preparation.md: b459184f802981f91f611b0b781651cede0c9efd
2026-08-08-host-owned-git-repository-plugin-preparation.zh.md: 5e24efa59ce44ffa8214f9c5ef9ff722ac0ca73a

View File

@@ -14,11 +14,11 @@ The checked-in headless fixture did not catch either defect because it mounted a
## Decision
The fixed authoring format now requires exact `scripts.prepack: "dsh-plugin-prepare"` metadata and no DSH dependency. pnpm's Git-hosted package preparation invokes `prepack` explicitly after its dependency-install step and before packlist selects the `.dsh-plugin` subtree, so the helper can still copy sibling repository assets such as `../skills` into the package.
The authoring format requires a non-empty `scripts.prepack` that invokes `dsh-plugin-prepare` and needs no DSH dependency for that helper. The package may declare its own build and runtime dependencies and run compilation before the helper. pnpm's Git-hosted package preparation invokes `prepack` explicitly after its dependency-install step and before packlist selects the `.dsh-plugin` subtree, so the helper can validate built entries and still copy sibling repository assets such as `../skills` into the package.
`@deepseek-ai/dsh-repository-plugin` materializes short-lived POSIX and Windows command wrappers that invoke its own built `dsh-plugin-prepare` entry. `RepositoryCache` accepts caller-owned executable directories, resolves them absolutely, and prepends them to the credential-scrubbed lifecycle `PATH` passed to bundled pnpm. The command directory exists only for the installation transaction and is removed on success or failure. The repository remains trusted package-manager input: DSH supplies one command, but other lifecycle scripts and dependencies still execute under the existing trust contract.
The Node 24 consumer lane passes an exact source derived from the pull request head repository and SHA. Because that repository is private, the workflow writes a job-scoped Git configuration that uses the read-only job token for GitHub HTTPS and rewrites pnpm's SSH fallback to that authenticated transport. Its built-entry acceptance launches the real `apps/cli/lib/bin.js run` command with a one-run patch selecting a `private: true`, dependency-free GitHub fixture. It requires the run to reach the mock LLM, finds the repository skill description in the actual model request, and verifies the generated wrapper and copied skill under the immutable DSH cache. The test fails if CI omits the exact source instead of silently skipping.
The Node 24 consumer lane passes an exact source derived from the pull request head repository and SHA. Because that repository is private, the workflow writes a job-scoped Git configuration that uses the read-only job token for GitHub HTTPS and rewrites pnpm's SSH fallback to that authenticated transport. Its built-entry acceptance launches the real `apps/cli/lib/bin.js run` command with a one-run patch selecting a `private: true` GitHub fixture. That fixture installs pinned npm dependencies, type-checks and bundles a TypeScript Cordis entry and MCP server in `prepack`, invokes the host helper, and proves the skill, MCP call, and code entry through real model requests and immutable-cache artifacts. The test fails if CI omits the exact source instead of silently skipping.
## Alternatives considered
@@ -34,10 +34,10 @@ The Node 24 consumer lane passes an exact source derived from the pull request h
- A repository author can commit the fixed `.dsh-plugin/package.json` and source assets to GitHub without publishing either the Plugin or its preparation helper to npm.
- Private GitHub sources use the host's standard Git authentication. CI proves that path with a temporary read-only configuration rather than persistent runner credentials.
- `prepack`, not `prepare`, is part of the pre-release authoring format. Invalid lifecycle metadata fails during source preparation or installed-package validation instead of producing an ambiguous partial format.
- `prepack`, not `prepare`, is part of the pre-release authoring format. It may contain package-owned build steps but must invoke the host helper; missing or empty lifecycle metadata fails installed-package validation instead of producing an ambiguous partial format.
- Exact source strings still identify immutable cache generations; a changed ref or source configuration selects another generation.
- This repair does not expand the contribution surface: prepared repository Plugins still contribute only declared skills and common MCP definitions, while arbitrary package lifecycle code remains trusted installation code rather than a model-facing Cordis Plugin API.
- The host supplies only the preparation executable. Package dependencies, compilation, and the trusted `dsh.entry` contribution remain owned by the repository package and the [trusted-code decision](../architecture/2026-08-08-trusted-repository-package-code.md).
## Testing
`packages/ui/app-boot/tests/repository-cache.spec.ts` runs a local Git subpath through bundled pnpm with an injected command directory and proves that visible environment survives while credential-shaped variables are scrubbed. `packages/cordis/repository-plugin/tests/repository-plugin.spec.ts` pins the exact `prepack` metadata and temporary command cleanup. `examples/headless-agent/tests/keyless-smoke.e2e.ts` keeps the checked-in prepared fixture on that source contract. `apps/cli/tests/github-repository-plugin.built.e2e.ts` is the product acceptance: fresh DSH home, exact authenticated private GitHub source, actual built `dsh run`, real headless composition, mock LLM request observation, and prepared cache inspection.
`packages/ui/app-boot/tests/repository-cache.spec.ts` runs a local Git subpath through bundled pnpm with an injected command directory and proves that visible environment survives while credential-shaped variables are scrubbed. `packages/cordis/repository-plugin/tests/repository-plugin.spec.ts` pins helper-bearing `prepack` metadata and temporary command cleanup. `examples/headless-agent/tests/keyless-smoke.e2e.ts` keeps the checked-in prepared fixture on that source contract. `apps/cli/tests/github-repository-plugin.built.e2e.ts` is the product acceptance: fresh DSH home, exact authenticated private GitHub source, actual built `dsh run`, package-owned TypeScript build, real MCP execution, code-entry transformation, mock LLM request observation, and prepared cache inspection.

View File

@@ -14,11 +14,11 @@ repository 插件的创作契约依赖 `scripts.prepare: "dsh-plugin-prepare"`
## 决策
修复后的创作格式要求元数据中精确包含 `scripts.prepack: "dsh-plugin-prepare"`,且不包含 DSH 依赖。pnpm 针对 Git 托管包的准备流程会在依赖安装步骤之后、打包清单选择 `.dsh-plugin` 子树之前显式调用 `prepack`,因此辅助程序仍可将 `../skills` 等同仓库的相邻资源复制进包内。
创作格式要求 `scripts.prepack` 非空且调用 `dsh-plugin-prepare`,使用该辅助程序无需 DSH 依赖。包可以声明自己的构建依赖与运行时依赖,并在调用辅助程序前完成编译。pnpm 针对 Git 托管包的准备流程会在依赖安装步骤之后、打包清单选择 `.dsh-plugin` 子树之前显式调用 `prepack`,因此辅助程序可以校验构建入口,并继续把 `../skills` 等同仓库的相邻资源复制进包内。
`@deepseek-ai/dsh-repository-plugin` 会生成临时的 POSIX 和 Windows 命令包装脚本,用于调用其自有的已构建 `dsh-plugin-prepare` 入口。`RepositoryCache` 接受由调用方持有的可执行文件目录,将它们解析为绝对路径,再前置到传给随附 pnpm、已清除凭据的包生命周期 `PATH`。该命令目录仅存在于安装事务期间,无论成功还是失败都会被移除。仓库仍是受信任的包管理器输入:DSH 仅提供这一条命令,其他生命周期脚本和依赖仍会按既有信任契约执行。
Node 24 消费方 CI 任务会传入从 PR(Pull Request)head 仓库和 SHA 派生的精确源。由于该仓库为私有仓库,工作流会写入一份作业作用域的 Git 配置,使用该作业的只读 token 对 GitHub HTTPS 连接进行认证,并将 pnpm 的 SSH 回退路径重写为这一已认证的传输方式。其构建入口验收会启动真实的 `apps/cli/lib/bin.js run` 命令,并通过一个仅作用于当次运行的 patch 选择 `private: true`、不含依赖的 GitHub fixture。验收要求该次运行到达 mock LLM(大语言模型),在实际模型请求中找到 repository skill 描述,并验证不可变 DSH 缓存中的生成包装层和已复制 skill。如果 CI 遗漏精确源,测试会失败,而不是静默跳过。
Node 24 消费方 CI 任务会传入从 PR(Pull Request)head 仓库和 SHA 派生的精确源。由于该仓库为私有仓库,工作流会写入一份作业作用域的 Git 配置,使用该作业的只读 token 对 GitHub HTTPS 连接进行认证,并将 pnpm 的 SSH 回退路径重写为这一已认证的传输方式。其构建入口验收会启动真实的 `apps/cli/lib/bin.js run` 命令,并通过一个仅作用于当次运行的 patch 选择 `private: true` 的 GitHub fixture。该 fixture 安装固定版本的 NPM 依赖,在 `prepack` 中对 TypeScript Cordis 入口和 MCP server 进行类型检查与打包,调用宿主辅助程序,并通过真实模型请求和不可变缓存产物验证 skill(技能)、MCP 调用和代码入口。如果 CI 遗漏精确源,测试会失败,而不是静默跳过。
## 考虑过的替代方案
@@ -34,10 +34,10 @@ Node 24 消费方 CI 任务会传入从 PR(Pull Request)head 仓库和 SHA
- 仓库作者可以把修复后的 `.dsh-plugin/package.json` 和源资源提交到 GitHub,而无需把插件或其准备辅助程序发布到 NPM。
- 私有 GitHub 源使用宿主的标准 Git 认证。CI 使用临时的只读配置而非运行器上的持久凭据来验证该路径。
- 预发布创作格式使用 `prepack` 而不是 `prepare`。无效的生命周期元数据会在源码准备或已安装包校验阶段导致失败,而不会留下状态不明的半成品格式。
- 预发布创作格式使用 `prepack` 而不是 `prepare`。其中可以包含包自有构建步骤,但必须调用宿主辅助程序;生命周期元数据缺失或为空会在已安装包校验时失败,而不会留下状态不明的半成品格式。
- 精确源字符串仍标识不可变缓存 generation;改变 ref 或源配置会选择另一个 generation。
- 本次修复不扩大贡献范围:已准备的 repository 插件仍只贡献已声明的 skills 和通用 MCP 定义,而任意包生命周期代码仍是受信任的安装代码,不是面向模型的 Cordis 插件 API。
- 宿主只提供准备阶段可执行文件。包依赖、编译和受信任的 `dsh.entry` 贡献仍由 repository 包和[受信任代码决策](../architecture/2026-08-08-trusted-repository-package-code.md)负责。
## 测试
`packages/ui/app-boot/tests/repository-cache.spec.ts` 会用注入的命令目录通过随附 pnpm 运行本地 Git 子路径,并证明可见环境变量得以保留,而名称符合凭据模式的变量会被清除。`packages/cordis/repository-plugin/tests/repository-plugin.spec.ts` 锁定精确的 `prepack` 元数据和临时命令清理行为。`examples/headless-agent/tests/keyless-smoke.e2e.ts` 使签入仓库的已准备 fixture 继续符合该源格式契约。`apps/cli/tests/github-repository-plugin.built.e2e.ts` 是产品验收测试:全新的 DSH 主目录、精确且经过认证的私有 GitHub 源、实际构建产物的 `dsh run`、真实 headless 组合、mock LLM 请求观测,以及对已准备缓存的检查。
`packages/ui/app-boot/tests/repository-cache.spec.ts` 会用注入的命令目录通过随附 pnpm 运行本地 Git 子路径,并证明可见环境变量得以保留,而名称符合凭据模式的变量会被清除。`packages/cordis/repository-plugin/tests/repository-plugin.spec.ts` 锁定包含辅助命令的 `prepack` 元数据和临时命令清理行为。`examples/headless-agent/tests/keyless-smoke.e2e.ts` 使签入仓库的已准备 fixture 继续符合该源格式契约。`apps/cli/tests/github-repository-plugin.built.e2e.ts` 是产品验收测试:全新的 DSH 主目录、精确且经过认证的私有 GitHub 源、实际构建产物的 `dsh run`、包自有 TypeScript 构建、真实 MCP 执行、代码入口转换、mock LLM(大语言模型)请求观测,以及对已准备缓存的检查。