@eduwork/dsh-oidc 0.2.3 → 0.3.0-dev.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/CHANGELOG.en.md +6 -38
  2. package/CHANGELOG.md +7 -39
  3. package/CODE_OF_CONDUCT.en.md +1 -1
  4. package/CODE_OF_CONDUCT.md +1 -1
  5. package/CONTRIBUTING.en.md +1 -1
  6. package/CONTRIBUTING.md +1 -1
  7. package/README.md +21 -130
  8. package/README_EN.md +36 -0
  9. package/SECURITY.en.md +1 -1
  10. package/SECURITY.md +1 -1
  11. package/SUPPORT.en.md +1 -1
  12. package/SUPPORT.md +1 -1
  13. package/docs/EDUWORK-MIGRATION.en.md +3 -31
  14. package/docs/EDUWORK-MIGRATION.md +3 -31
  15. package/docs/account-extensions.en.md +6 -6
  16. package/docs/account-extensions.md +3 -3
  17. package/docs/architecture.en.md +12 -117
  18. package/docs/architecture.md +12 -118
  19. package/docs/compatibility.en.md +6 -62
  20. package/docs/compatibility.md +6 -62
  21. package/docs/decisions/0001-one-plugin-composition-boundary.en.md +2 -2
  22. package/docs/decisions/0001-one-plugin-composition-boundary.md +2 -2
  23. package/docs/desktop-host.en.md +54 -55
  24. package/docs/desktop-host.md +63 -64
  25. package/docs/development.en.md +44 -44
  26. package/docs/development.md +6 -6
  27. package/docs/dsh-integration.en.md +13 -48
  28. package/docs/dsh-integration.md +14 -49
  29. package/docs/ecnu-reference.en.md +4 -61
  30. package/docs/ecnu-reference.md +4 -61
  31. package/docs/enterprise-profile.en.md +10 -31
  32. package/docs/enterprise-profile.md +11 -32
  33. package/docs/gateway-auth/README.md +168 -0
  34. package/docs/gateway-auth/README_EN.md +70 -0
  35. package/docs/gateway-auth/experimental-oidc-llm.en.md +53 -0
  36. package/docs/gateway-auth/experimental-oidc-llm.md +53 -0
  37. package/docs/gateway-auth/litellm-setup.en.md +114 -0
  38. package/docs/gateway-auth/litellm-setup.md +114 -0
  39. package/docs/gateway-auth/oidc-llm-draft.en.md +141 -0
  40. package/docs/gateway-auth/oidc-llm-draft.md +141 -0
  41. package/docs/getting-started.en.md +17 -122
  42. package/docs/getting-started.md +16 -225
  43. package/docs/key-binding-protocol.en.md +10 -220
  44. package/docs/key-binding-protocol.md +10 -220
  45. package/docs/oidc-interoperability.en.md +1 -1
  46. package/docs/oidc-interoperability.md +1 -1
  47. package/docs/open-integration.en.md +11 -0
  48. package/docs/open-integration.md +11 -0
  49. package/docs/public-resource-protocol.en.md +8 -44
  50. package/docs/public-resource-protocol.md +8 -43
  51. package/docs/release-checklist.en.md +7 -61
  52. package/docs/release-checklist.md +7 -61
  53. package/docs/security-model.en.md +10 -132
  54. package/docs/security-model.md +10 -132
  55. package/docs/server-integration-contract.en.md +12 -811
  56. package/docs/server-integration-contract.md +12 -823
  57. package/examples/ecnu.enterprise-profile.example.json +14 -19
  58. package/examples/enterprise-profile.example.json +73 -78
  59. package/examples/identity-only.example.json +1 -1
  60. package/examples/litellm.enterprise-profile.example.json +9 -0
  61. package/examples/oidc-llm.enterprise-profile.example.json +12 -0
  62. package/examples/resources-discovery.example.json +6 -9
  63. package/lib/callback-page.js +5 -5
  64. package/lib/client.js +31 -48
  65. package/lib/desktop-oidc.js +7 -11
  66. package/lib/gateway-backend.js +443 -0
  67. package/lib/gateway-protocol.js +6 -0
  68. package/lib/index.js +14 -15
  69. package/lib/litellm-protocol.js +117 -0
  70. package/lib/model-resource-transport.js +19 -0
  71. package/lib/oidc-llm-protocol.js +88 -0
  72. package/lib/oidc.js +37 -323
  73. package/lib/profile.js +34 -40
  74. package/lib/provider/authorization-scope.js +46 -0
  75. package/lib/provider/index.js +11 -2
  76. package/lib/provider/transforms.js +0 -1
  77. package/lib/typert-schemas.js +1 -1
  78. package/lib/typert.host.js +38 -38
  79. package/lib/typert.remote-client.js +37 -37
  80. package/package.json +7 -6
  81. package/protocol/openapi.yaml +33 -240
  82. package/protocol/resources.openapi.yaml +8 -9
  83. package/schema/enterprise-profile.v1alpha1.schema.json +595 -193
  84. package/README.en.md +0 -186
@@ -2,124 +2,19 @@
2
2
 
3
3
  [简体中文](architecture.md) | **English**
4
4
 
5
- ## Goals
5
+ One Host account service composes identity, token lifecycle and the DSH model Provider. Servers own authorization; clients consume explicit contracts.
6
6
 
7
- `dsh-oidc` lets an organization integrate identity, entitlement, model credentials, Provider metadata, and bounded branding into an ordinary DSH host without forking DSH or requiring a desktop shell.
7
+ | Layer | Responsibility |
8
+ | --- | --- |
9
+ | Profile | Trusted public settings, full discovery URL, protocol opt-in and branding |
10
+ | oidc.js / desktop-oidc.js | Shared identity validation, session writes, browser and loopback callback |
11
+ | gateway-backend.js | Token resources, single-flight refresh, authorization isolation, logout and catalogs |
12
+ | litellm-protocol.js / oidc-llm-protocol.js | Protocol-specific discovery, registration and response validation |
13
+ | DSH Provider | Shared requests, JSON/SSE, attachments and reasoning |
14
+ | Institution extensions | Optional own-account quota through shared Host transport |
8
15
 
9
- The design follows five rules:
16
+ OIDC mode reuses the strict ID Token verifier. LiteLLM native validates its separate identity contract. Both model integrations use Access Tokens without a Key Binding fallback. Plain oidc configuration is identity-only.
10
17
 
11
- 1. **DSH owns the runtime.** The plugin uses official DSH services and `PiAiAdapter`; it does not implement a parallel conversation or model transport stack.
12
- 2. **Standards own identity.** Authentication uses OIDC Discovery, Authorization Code + PKCE, ID Tokens, UserInfo, refresh, and optional revocation.
13
- 3. **The institutional service is one complete delivery boundary.** Managed models require one accountable owner to jointly deliver OIDC, fixed Key Binding and the model gateway; identity-only mode requires only OIDC. a Profile declares only their public endpoints and facts.
14
- 4. **Configuration is data, not code.** A profile cannot select executable adapters, arbitrary endpoint paths, scripts, stylesheets, tools, or skills.
15
- 5. **Product-specific capabilities compose around the core.** The common enterprise-model settings surface belongs to `dsh-oidc`; desktop shells, quota views, model transforms, or institutional pages remain separate plugins/services.
18
+ After browser Code + PKCE, the Host saves the authorization session and loads its catalog. Requests resolve the current Access Token and share refresh near expiry. Logout, reauthorization or account changes invalidate old calls. Secrets stay in Host credential storage, outside renderer configuration.
16
19
 
17
- ## Runtime components
18
-
19
- | Component | Responsibility | Trust level |
20
- | --- | --- | --- |
21
- | DSH Host | Lifecycle, Cordis services, LLM registry, WebServer, credentials, attachments | Trusted executable host |
22
- | `dsh-oidc` Host face | Profile validation, OIDC client, Key Binding client, local Provider registration | Trusted local plugin |
23
- | `dsh-oidc` Client face | Account/onboarding surfaces, shared enterprise-model settings, and bounded branding | Trusted local plugin |
24
- | Enterprise Profile | Declarative integration facts | Trusted configuration, still validated fail-closed |
25
- | Institutional enterprise-model integration service | Joint OIDC identity, Key Binding authorization/credential lifecycle, and OpenAI-compatible model gateway | Remote identity, authorization, and data-processing authority |
26
- | Capability plugin | Optional request-bound transform such as image-to-text fallback | Separately trusted local plugin |
27
-
28
- ## Control flow
29
-
30
- ```mermaid
31
- sequenceDiagram
32
- participant B as Browser/UI
33
- participant D as dsh-oidc
34
- participant O as OIDC Provider
35
- participant K as Key Binding service
36
- participant C as DSH Credential Provider
37
- participant L as DSH LLM/PiAiAdapter
38
- participant M as Model gateway
39
-
40
- B->>D: begin(profileID)
41
- D->>O: Discovery
42
- D-->>B: Authorization URL (state, nonce, PKCE)
43
- B->>O: User authentication and consent
44
- O-->>D: http://127.0.0.1:port/oauth/callback?code&state
45
- D->>O: Token request + code_verifier
46
- D->>O: JWKS and UserInfo
47
- D->>D: Verify ID Token and sub equality
48
- D->>C: Store OIDC session
49
- D->>K: GET /bootstrap with Bearer access token
50
- B->>D: User confirms provisioning
51
- D->>K: POST /runtime-credential/provision
52
- K-->>D: api_key
53
- D->>C: Store API key under the Profile credential reference
54
- B->>L: Start model request
55
- L->>C: Resolve runtime API key
56
- L->>M: OpenAI-compatible streaming request
57
- ```
58
-
59
- The OIDC Provider, Key Binding, and model gateway in the diagram are three interface groups in one [server API specification](server-integration-contract.en.md). They may route to different internal systems or origins, managed-model mode needs all three groups, while identity-only mode omits the two model-resource groups. The Web callback always returns to local `127.0.0.1`, not a public institutional DSH address.
60
-
61
- ## Code layout
62
-
63
- - `src/host/index.js`: DSH service entry and Typert remote methods.
64
- - `src/host/oidc.js`: Shared Web/desktop OIDC implementation and the legacy native adapter.
65
- - `src/host/profile.js`: validation, imports, public projection, Provider projection.
66
- - `src/host/provider/`: local DSH/PiAi Provider adapter and transform seam.
67
- - `src/client/`: DSH browser bundle, account surfaces, and remote descriptors.
68
- - `schema/`: machine-readable Enterprise Profile contract.
69
- - `protocol/openapi.yaml`: machine-readable Key Binding contract.
70
- - `docs/`: normative prose, threat model, and integration guidance.
71
-
72
- Host files remain readable native ESM and are copied to `lib/` during build. Client code is bundled into DSH's module-loader closure format. Published packages include built artifacts and the two machine-readable contracts.
73
-
74
- ## Identity boundary
75
-
76
- OIDC is the only authentication and identity source in the Web backend, which starts only when the DSH WebServer listens exactly on `127.0.0.1`. The plugin binds three values:
77
-
78
- - configured issuer;
79
- - configured public client ID;
80
- - authenticated `sub` shared by the ID Token and UserInfo response.
81
-
82
- `userinfo.name` is display-only and falls back to `userinfo.sub`. Key Binding `bootstrap.subject`, if present, is informational and cannot overwrite identity. This prevents a private management API from silently becoming a second, incompatible identity protocol.
83
-
84
- ## Credential boundary
85
-
86
- The Key Binding service returns the model API key exactly once per resolve/provision/renew response. `dsh-oidc` writes it under the normalized Enterprise Profile credential reference. The default is a single institution-neutral reference:
87
-
88
- ```text
89
- EDUWORK_API_KEY
90
- ```
91
-
92
- Legacy automatic names normalize to `EDUWORK_API_KEY`; other explicit references remain unchanged. A credential fingerprint is stored alongside verified identity and the complete resource binding in the Host session. Network use and logout cleanup require the current key to belong to that session. The fingerprint is never projected into RPC, logs or conversation text. See the [Profile specification](enterprise-profile.en.md) for migration boundaries.
93
-
94
- The Provider adapter resolves that reference at request time. It never reads an ambient pi-ai credential store and never places the key in the Enterprise Profile, UI payload, logs, or DSH transcript. Web and native backends follow the same Profile rule. Native `enterpriseAccounts` is only a host capability adapter; it does not own credential naming, and a conflicting reference is rejected.
95
-
96
- Credential storage security is delegated to the active DSH Credential Provider. That is an explicit host contract, not proof that every DSH deployment is multi-user safe.
97
-
98
- ## Provider ownership and extension
99
-
100
- Each profile declares one Provider ID and one or more models. `dsh-oidc` owns those routes through DSH's official `PiAiAdapter` and `@earendil-works/pi-ai` OpenAI Completions implementation.
101
-
102
- Optional feature plugins register a transform through the Cordis service `enterpriseTransforms`. A transform may:
103
-
104
- - advertise an aggregate modality for a specific Provider/model;
105
- - rewrite the provider-bound request;
106
- - inspect the model's native modalities.
107
-
108
- It must not mutate the durable transcript or register a competing adapter for the same route. Native multimodal routes can therefore bypass a text-only image-understanding fallback, while text-only routes can opt into it.
109
-
110
- ## Desktop and legacy native boundary
111
-
112
- New desktop products use `backend: desktop`: a temporary loopback callback and official browser service share the OIDC/Key/model implementation across Wails and Electron. The host supplies credential storage. Legacy `backend: native` delegates to `enterpriseAccounts` only for existing bridges; see [desktop integration](desktop-host.en.md).
113
-
114
- The shared UI uses official `settings.models.footer`, onboarding, sidebar and general-settings slots. Institution configuration is read-only trusted data. Legacy bridge mutation methods are compatibility APIs, not a requirement or default UI for new institutions. `models-only` mounts the shared model-settings surface; `external` disables plugin UI. Quota and heartbeat remain in explicitly installed institution extensions.
115
-
116
- ## Deliberate exclusions
117
-
118
- - arbitrary userinfo endpoint or claim-path mapping;
119
- - arbitrary Key Binding paths/fields;
120
- - remote modules, CSS, tools, or skills;
121
- - model quota and institution directory schemas;
122
- - server-side web sessions for a shared multi-user DSH host;
123
- - dynamic Provider adapter selection.
124
-
125
- These exclusions reduce protocol ambiguity and keep executable trust local and reviewable.
20
+ See [security](security-model.en.md), [Host integration](dsh-integration.en.md) and [gateway contracts](gateway-auth/README_EN.md).
@@ -2,125 +2,19 @@
2
2
 
3
3
  **简体中文** | [English](architecture.en.md)
4
4
 
5
- ## 目标
5
+ 客户端以一个 Host 账户服务组合身份、Token 生命周期和 DSH 模型 Provider。服务端负责授权,客户端只消费明确声明的协议。
6
6
 
7
- `dsh-oidc` 让机构无需 fork DSH,也无需依赖桌面外壳,就能把身份、授权、模型凭据、Provider 元数据和有边界的品牌能力接入普通 DSH Host。
7
+ | 层次 | 职责 |
8
+ | --- | --- |
9
+ | Profile | 可信公开配置、完整发现地址、协议开关及品牌数据 |
10
+ | oidc.js / desktop-oidc.js | 共用身份验证、会话写入、浏览器和本机回调 |
11
+ | gateway-backend.js | Token 资源、并发刷新、授权隔离、退出及模型目录 |
12
+ | litellm-protocol.js / oidc-llm-protocol.js | 各协议的发现、注册与响应校验 |
13
+ | DSH Provider | 共用模型请求、JSON/SSE、附件和推理参数 |
14
+ | 机构扩展 | 通过共享 Host 传输处理本人配额等可选能力 |
8
15
 
9
- 设计遵循五条规则:
16
+ OIDC 模式沿用严格 ID Token 验证器;LiteLLM native 的身份契约独立校验。两种模型接入均使用 Access Token,不存在 Key Binding 备用分支。oidc 配置只用于纯身份模式。
10
17
 
11
- 1. **DSH 负责运行时。** 插件使用 DSH 官方服务和 `PiAiAdapter`,不另建对话或模型传输栈。
12
- 2. **身份遵循标准。** 认证使用 OIDC Discovery、Authorization Code + PKCE、ID Token、UserInfo、刷新和可选撤销。
13
- 3. **机构服务是一个完整交付边界。** 托管模型模式要求服务所有者共同交付 OIDC、固定 Key Binding 和模型网关;纯身份模式只需 OIDC。Profile 只能声明这些协议表面的公开地址与事实。
14
- 4. **配置是数据,不是代码。** Profile 不能选择可执行 adapter、任意接口路径、脚本、样式表、工具或 Skill。
15
- 5. **产品特有能力围绕核心组合。** 通用企业模型设置界面属于 `dsh-oidc`;桌面外壳、配额视图、模型转换或机构业务页面仍由独立插件或服务承担。
18
+ 浏览器完成 Code + PKCE 后,Host 保存授权会话并加载获授权目录。调用前解析有效 Access Token;临近到期合并刷新。退出、重新授权或账户切换使旧调用失效。秘密由 Host 凭据服务保存,不进入 renderer 配置。
16
19
 
17
- ## 运行时组件
18
-
19
- | 组件 | 职责 | 信任级别 |
20
- | --- | --- | --- |
21
- | DSH Host | 生命周期、Cordis 服务、LLM 注册、WebServer、凭据和附件 | 受信任的可执行宿主 |
22
- | `dsh-oidc` Host 端 | Profile 校验、OIDC 客户端、Key Binding 客户端、本地 Provider 注册 | 受信任的本地插件 |
23
- | `dsh-oidc` Client 端 | 账号/引导界面、共用企业模型设置和有边界的品牌替换 | 受信任的本地插件 |
24
- | Enterprise Profile | 声明式集成事实 | 受信任配置,但仍以失败关闭方式校验 |
25
- | 机构企业模型集成服务 | 联合提供 OIDC 身份、Key Binding 授权/凭据生命周期和 OpenAI-compatible 模型网关 | 远程安全、授权和数据处理权威 |
26
- | 能力插件 | 可选的请求级转换,例如图像转文本回退 | 单独受信任的本地插件 |
27
-
28
- ## 控制流
29
-
30
- ```mermaid
31
- sequenceDiagram
32
- participant B as 浏览器/UI
33
- participant D as dsh-oidc
34
- participant O as OIDC Provider
35
- participant K as Key Binding 服务
36
- participant C as DSH Credential Provider
37
- participant L as DSH LLM/PiAiAdapter
38
- participant M as 模型网关
39
-
40
- B->>D: begin(profileID)
41
- D->>O: Discovery
42
- D-->>B: Authorization URL(state、nonce、PKCE)
43
- B->>O: 用户认证与授权
44
- O-->>D: http://127.0.0.1:port/oauth/callback?code&state
45
- D->>O: Token 请求 + code_verifier
46
- D->>O: JWKS 和 UserInfo
47
- D->>D: 校验 ID Token 和 sub 一致性
48
- D->>C: 保存 OIDC 会话
49
- D->>K: 携带 Bearer access token 调用 GET /bootstrap
50
- B->>D: 用户确认创建凭据
51
- D->>K: POST /runtime-credential/provision
52
- K-->>D: api_key
53
- D->>C: 按 Profile 凭据引用保存 API Key
54
- B->>L: 发起模型请求
55
- L->>C: 解析运行时 API Key
56
- L->>M: OpenAI-compatible 流式请求
57
- ```
58
-
59
- 图中 OIDC Provider、Key Binding 和模型网关是同一份[服务端接口规范](server-integration-contract.md)的三个接口组。它们可以在机构内部拆成不同系统或域名,托管模型模式需要三组完整服务;纯身份模式可以省略两个模型资源组。Web 回调始终返回本机 `127.0.0.1`,不经过机构公网 DSH 地址。
60
-
61
- ## 代码布局
62
-
63
- - `src/host/index.js`:DSH 服务入口和 Typert 远程方法。
64
- - `src/host/oidc.js`:Web/desktop 共用 OIDC 实现及旧 native adapter。
65
- - `src/host/desktop-oidc.js`:临时 loopback 登录与取消。
66
- - `src/host/profile.js`:校验、导入、公共投影和 Provider 投影。
67
- - `src/host/provider/`:本地 DSH/PiAi Provider adapter 和转换扩展点。
68
- - `src/client/`:DSH 浏览器 bundle、账号界面和远程描述符。
69
- - `schema/`:机器可读的 Enterprise Profile 契约。
70
- - `protocol/openapi.yaml`:机器可读的 Key Binding 契约。
71
- - `docs/`:规范正文、威胁模型和集成指南。
72
-
73
- Host 端文件保持为可读的原生 ESM,并在构建时复制到 `lib/`。Client 端代码被打包为 DSH module-loader 的闭包格式。发布包同时包含构建产物和两份机器可读契约。
74
-
75
- ## 身份边界
76
-
77
- Web 后端只以 OIDC 作为认证和身份来源,并只在 DSH WebServer 精确监听 `127.0.0.1` 时启动。插件绑定三个值:
78
-
79
- - 配置的 issuer;
80
- - 配置的 public client ID;
81
- - 经认证且在 ID Token 与 UserInfo 中一致的 `sub`。
82
-
83
- `userinfo.name` 只用于显示,缺失时降级到 `userinfo.sub`。Key Binding `bootstrap.subject` 即使存在也只是信息字段,不能覆盖身份。这样可防止私有管理 API 悄悄变成第二套不兼容的身份协议。
84
-
85
- ## 凭据边界
86
-
87
- Key Binding 服务在每次 resolve/provision/renew 响应中返回模型 API Key。`dsh-oidc` 将其写入 Enterprise Profile 解析后的 DSH 凭据引用。默认值统一为机构无关的公共引用:
88
-
89
- ```text
90
- EDUWORK_API_KEY
91
- ```
92
-
93
- 旧自动引用按 Profile 规则兼容到 `EDUWORK_API_KEY`,其他显式引用保持不变。模型 Key 指纹与已验证身份及完整资源绑定一起保存在 Host 会话中;任何网络使用和登出清理都要求当前值仍归属于该会话。指纹不通过 RPC、日志或对话输出。迁移范围见 [Profile 规范](enterprise-profile.md)。
94
-
95
- Provider adapter 在请求时解析该引用。它不会读取环境中的 pi-ai 凭据存储,也不会把密钥放入 Enterprise Profile、UI payload、日志或 DSH 对话记录。Web 后端和 native 后端使用同一 Profile 规则;native `enterpriseAccounts` 只是宿主能力适配器,不拥有凭据命名策略,若返回不一致的引用会被拒绝。
96
-
97
- 凭据存储安全性委托给当前 DSH Credential Provider。这是一项明确的宿主契约,并不意味着任意 DSH 部署都天然具备多用户安全性。
98
-
99
- ## Provider 所有权与扩展
100
-
101
- 托管资源 Profile 声明 Provider ID,以及本地模型或发现模式;纯身份 Profile 不声明 Provider。`dsh-oidc` 通过 DSH 官方 `PiAiAdapter` 和 `@earendil-works/pi-ai` 的 OpenAI Completions 实现拥有这些路由。
102
-
103
- 可选功能插件可通过 Cordis 服务 `enterpriseTransforms` 注册转换。转换可以:
104
-
105
- - 为指定 Provider/模型声明聚合后的输入模态;
106
- - 重写即将发送给 Provider 的请求;
107
- - 检查模型的原生模态。
108
-
109
- 转换不得修改持久对话记录,也不得为同一路由注册竞争 adapter。因此,原生多模态路由可绕过仅面向文本模型的图像理解回退,而纯文本路由可以选择接入该能力。
110
-
111
- ## Desktop 与旧 native 边界
112
-
113
- 新桌面使用 `backend: desktop`:临时 loopback 回调和官方浏览器服务在 Wails/Electron 间共享 OIDC/Key/模型实现,凭据存储仍由宿主提供。旧 `backend: native` 仅为已有桥接委托 `enterpriseAccounts`。见[桌面集成](desktop-host.md)。
114
-
115
- 共用 UI 使用官方 `settings.models.footer`、onboarding、侧栏和通用设置插槽。机构配置是只读可信数据;旧桥的可变管理方法只是兼容 API,不是新机构的默认 UI 或必需接口。`models-only` 只挂共用模型设置,`external` 关闭插件 UI。配额和心跳由显式安装的机构扩展提供。
116
-
117
- ## 明确排除
118
-
119
- - 任意 UserInfo endpoint 或 claim 路径映射;
120
- - 任意 Key Binding 路径或字段;
121
- - 远程模块、CSS、工具或 Skill;
122
- - 模型配额和机构目录协议;
123
- - 共享多用户 DSH Host 的服务端 Web 会话;
124
- - 动态 Provider adapter 选择。
125
-
126
- 这些排除项减少协议歧义,并让可执行信任边界保持在本地、可审查范围内。
20
+ 详情:[安全模型](security-model.md)、[Host 集成](dsh-integration.md)、[网关协议](gateway-auth/README.md)。
@@ -2,70 +2,14 @@
2
2
 
3
3
  [简体中文](compatibility.md) | **English**
4
4
 
5
- ## Tested matrix
5
+ Runtime and DSH compatibility follow package.json, dependency locks and measured results. Source tests are not a complete packaged desktop acceptance.
6
6
 
7
- | dsh-oidc | Node.js | DSH | pi-ai | Status |
8
- | --- | --- | --- | --- | --- |
9
- | `0.2.0` stable-version freeze | Windows 24 | registry `0.1.5-rc.1` | `0.85.1` | `npm ci`, complete checks, 93 tests and 6 compiled-browser regressions pass; audit reports 0 vulnerabilities. Runtime sources match dev.7. Consult the registry for publication status; Linux/Node 22 and macOS acceptance are recorded separately. |
10
- | dev.7 source preparation (historical validation) | Windows 24 | registry `0.1.5-rc.1` | `0.85.1` | Clean `npm ci` from the committed 61-package DSH test closure; 93 tests. This is separate from historical full-product closures; Linux/Node 22 matrix pending. |
11
- | Frozen `0.2.0-dev.20260910.7` (unpublished) | 24 | `0.1.5-rc.1` / `183f08e9…` | `0.85.1` | 265-package product closure, 93 tests including 15 credential ownership/migration regressions and 6 tarball Host tests. Frozen artifact unchanged. |
12
- | `0.2.0-dev.20260910.6` (unpublished) | 24 | `0.1.5-rc.1` / `183f08e9…` | `0.85.1` | 264 coherent DSH packages; 78 tests and 6 compiled-browser checks. Public identity/key/models with no quota HTTP/schema/UI. Host-only account extension transport, official child slot and logout/read races. |
13
- | `0.2.0-dev.20260910.5` (unpublished) | 24 | `0.1.5-rc.1` / `183f08e9…` | `0.85.1` | 264 coherent DSH packages; 75 tests and 7 compiled-browser checks. Real HTTP PKCE/key/model streams, future-session default, avatar quota/keyboard/logout races, and branded callbacks. Adapts PiAi `modelErrors`; existing APIs/events/model selection remain compatible. |
14
- | `0.2.0-dev.20260909.1` (unpublished) | 24 | `0.1.5-alpha.1` / `5dda764e…` | `0.85.1` | 257 coherent packages; 40 tests including real Host + HTTP OIDC callback, managed-key model discovery, quota, LLM SSE, host-only authorized requests and account events. Browser UI acceptance belongs to the integrating product. |
15
- | `0.1.0-dev.20260908.1` (local candidate only) | 24 | `0.1.2-rc.1` / `0.1.3-alpha.1` / `0.1.3-alpha.2` | `^0.84.2` | All three isolated dependency trees pass the complete check and 33 tests, including 19 real PiAi HTTP requests verifying thinking-only behavior without a wire effort. Unpublished. |
16
- | `0.1.0-dev.20260907.3` (local candidate only) | 24 | `0.1.3-alpha.2` / `82a5fd61…` | `^0.84.2` | Real module resolution across 250 coherent DSH packages; TypeScript, 32 plugin tests, Host/Provider/Client contracts, all 13 Typert Remote markers, and real pi-ai reasoning HTTP regression pass. Unpublished. |
17
- | `0.1.0-dev.20260907.1` (local candidate only) | 24 | `0.1.3-alpha.1` / `d347e703…` | `^0.84.2` | Real module resolution across 247 coherent DSH packages; TypeScript, 29 plugin tests, Host/Provider/Client contracts, and 13 Typert Remote markers pass. Unpublished. |
18
- | `0.1.0` | 22, 24 | `0.1.2-rc.1` / `a66e4702…` | `^0.84.2` (locked at `0.84.4`) | Exact peer closure, Host/Client contract checks, clean npm installation, and isolated Web/RPC acceptance. |
19
- | `0.1.0-alpha.11` | 22, 24 | Declared baseline remains `0.1.2-alpha.2`; separate mainline `0.1.2-rc.1` configuration RPC probe | `^0.84.2` | npm scope migration with persistent contracts retained; the rc.1 probe is not full compatibility acceptance. |
20
- | `0.1.0-alpha.10` | 22, 24 | `0.1.2-alpha.2` / `0a53fb55…` | `^0.84.2` (`0.84.4` in npm/source Runtimes) | Migrated to `SettingsProvider.installSection()`; full checks pass through both npm and source release-pack paths. |
21
- | `0.1.0-alpha.9` | 22, 24 | `0.1.2-alpha.1` / `cd5ef814…` | `^0.84.2` (`0.84.4` in the reviewed source Runtime) | Web and native consume only standard Enterprise Profiles; product institution-catalog conversion is completely outside the plugin. |
22
- | `0.1.0-alpha.8` | 22, 24 | `0.1.2-alpha.1` / `cd5ef814…` | `^0.84.2` (`0.84.4` in the reviewed source Runtime) | Shared Web/native Profile credential-reference rule, production/test local-key isolation, and fail-closed native mismatch handling. |
23
- | `0.1.0-alpha.7` | 22, 24 | `0.1.2-alpha.1` / `cd5ef814…` | `^0.84.2` (`0.84.4` in the reviewed source Runtime) | An exact network HTTP origin may be allowed for development; production remains HTTPS-only. |
24
- | `0.1.0-alpha.6` | 22, 24 | `0.1.2-alpha.1` / `cd5ef814…` | `^0.84.2` (`0.84.4` in the reviewed source Runtime) | Uses the upstream Models page and official `settings.models.footer`; validate through a source release-pack until matching npm packages are published. |
25
- | `0.1.0-alpha.5` | 22, 24 (development) | `0.1.1-rc.2` / `b150a551…` | `0.82.1` | Local-checkout-first installation documentation; runtime behavior is unchanged from alpha.4. |
26
- | `0.1.0-alpha.4` | 22, 24 (development) | `0.1.1-rc.2` / `b150a551…` | `0.82.1` | Direct DSH Web Bundle installation and complete third-party deployment documentation; product/Web acceptance completed in the ECNU reference composition. |
27
- | `0.1.0-alpha.3` | 22, 24 (development) | `0.1.1-rc.2` / `b150a551…` | `0.82.1` | Shared Web/native enterprise-model settings and native capability adapter; end-to-end product acceptance pending. |
28
- | `0.1.0-alpha.2` | 22, 24 (development) | `0.1.1-rc.2` / `b150a551…` | `0.82.1` | Standard UserInfo name presentation unified across Web and native adapters; real deployment acceptance pending. |
29
- | `0.1.0-alpha.1` | 22, 24 (development) | `0.1.1-rc.2` / `b150a551…` | `0.82.1` | Unit/build/package baseline; real deployment acceptance still required. |
7
+ The current source supports LiteLLM native contract 1, explicitly enabled experimental oidc-llm 0.1 and standard identity-only OIDC. oidc-llm remains a draft and is disabled by default.
30
8
 
31
- Historical stable `0.1.0` targets exact DSH `0.1.2-rc.1`. Current `0.2.0` keeps dev.7 runtime sources and pins DSH `0.1.5-rc.1` throughout the required development/CI closure. Its version is independent of the product version. Historical rows record their original evidence; they do not imply all old runtimes were retested in the current pass or that quota remains in the public API. See [development preparation](development.en.md).
9
+ This branch removes Key Binding model flows and backend: native account bridging; old profiles fail explicitly. New clients use Tokens while servers may retain legacy endpoints for released clients. This breaking change is unpublished. Choose an appropriate new package version and reviewed product locks before publication; never overwrite an existing npm version.
32
10
 
33
- ## Contract versions
11
+ ## Validation
34
12
 
35
- - Enterprise Profile: `dsh-oidc/v1alpha1`
36
- - Key Binding Profile selector: `worker-user-center-v1` or `eduwork-resources-v1`; accepted Bootstrap wire aliases: `worker.user-center.v1`, `worker-user-center/v1`, `eduwork-resources/v1`
37
- - Typert package/namespace: `@eduwork/dsh-oidc` / `oidcAccounts`
38
- - Browser management projection: `dsh-oidc/management/v1alpha1`
39
- - Callback path: `/oauth/callback`
40
- - Provider transform service: `enterpriseTransforms`
41
- - Legacy-compatible Provider settings namespace: `provider-enterprise`
13
+ Package checks cover types, builds, shared identity/gateway regressions, schemas, documentation, secrets and packaging. Real OIDC/LiteLLM, desktop encryption, restart and UI require separately identified acceptance evidence.
42
14
 
43
- Changing any item above requires compatibility analysis and, where wire-visible, a new contract version.
44
-
45
- ## Project semver
46
-
47
- Before `1.0.0`, minor versions may contain incompatible alpha contract changes, but release notes and migration instructions are required. Patch versions must be backward compatible within the same documented contract version.
48
-
49
- After `1.0.0`:
50
-
51
- - additive optional profile fields and error codes may be minor releases;
52
- - removing/renaming fields, changing fixed paths, callback path, default credential derivation, or identity rules requires a major release or a separately versioned contract;
53
- - security hardening that rejects previously accepted unsafe input may ship in a minor or patch release with prominent notice.
54
-
55
- ## Release gates
56
-
57
- No public tag/npm publish until all of the following pass:
58
-
59
- - `npm ci` from a clean checkout;
60
- - `npm run check` on Windows and Linux;
61
- - CodeQL or equivalent static analysis;
62
- - dependency/license and install-script review;
63
- - secret/production-endpoint scan;
64
- - npm tarball content review;
65
- - plain Web end-to-end acceptance;
66
- - native desktop no-regression acceptance;
67
- - OIDC negative tests and Key Binding authorization tests;
68
- - documentation/version/changelog update;
69
- - independent technical review, CI/focused regression evidence, and a recorded maintainer decision for authentication, credential, build, or release workflow changes; add independent human approval after a second maintainer joins.
70
-
71
- See [the public release checklist](release-checklist.en.md) for the operator checklist.
15
+ See [migration](key-binding-protocol.en.md) and [development](development.en.md). Source changes, npm publication, application assembly and production deployment remain separate operations.
@@ -2,70 +2,14 @@
2
2
 
3
3
  **简体中文** | [English](compatibility.en.md)
4
4
 
5
- ## 已测试矩阵
5
+ 运行环境和 DSH 兼容范围以 package.json、依赖锁及对应实测为准,不能把源码测试等同于整包发行验收。
6
6
 
7
- | dsh-oidc | Node.js | DSH | pi-ai | 状态 |
8
- | --- | --- | --- | --- | --- |
9
- | `0.2.0` 稳定版本冻结 | Windows 24 | registry `0.1.5-rc.1` | `0.85.1` | `npm ci`、完整检查、93 项测试、6 项编译浏览器回归通过,audit 为 0。运行源码与 dev.7 相同;发布状态以 registry 为准,Linux/Node 22 与 macOS 验收单独记录。 |
10
- | dev.7 源码准备(历史验证) | Windows 24 | registry `0.1.5-rc.1` | `0.85.1` | 已提交锁的 61 包 DSH 测试闭包,干净 `npm ci`、93 项测试;与历史完整产品闭包分别记录,Linux/Node 22 矩阵待执行。 |
11
- | 已冻结 `0.2.0-dev.20260910.7`(未发布) | 24 | `0.1.5-rc.1` / `183f08e9…` | `0.85.1` | 265 包产品闭包、93 项测试(含 15 项凭据迁移/归属回归)与 6 项 tarball Host 验证;冻结产物未替换。 |
12
- | `0.2.0-dev.20260910.6`(未发布) | 24 | `0.1.5-rc.1` / `183f08e9…` | `0.85.1` | 264 个一致 DSH 包;78 项测试及 6 项编译浏览器检查。公版身份/Key/模型不含配额请求/类型/UI;Host 专属扩展运输、官方子插槽与注销读取竞态。 |
13
- | `0.2.0-dev.20260910.5`(未发布) | 24 | `0.1.5-rc.1` / `183f08e9…` | `0.85.1` | 264 个一致 DSH 包;75 项测试及 7 项编译浏览器检查。覆盖真实 HTTP PKCE/Key/模型流、无会话默认值、头像菜单/配额/键盘/注销竞态与品牌回调;本轮适配 PiAi `modelErrors`,原有 API/事件/选模契约保持兼容。 |
14
- | `0.2.0-dev.20260909.1`(未发布) | 24 | `0.1.5-alpha.1` / `5dda764e…` | `0.85.1` | 257 个一致包;40 项测试含官方 Host+HTTP 登录回调、托管 Key 自动模型目录/配额、LLM SSE、Host 专属授权请求与账号事件。产品浏览器 UI 由主线联合验收。 |
15
- | `0.1.0-dev.20260908.1`(仅本地候选) | 24 | `0.1.2-rc.1` / `0.1.3-alpha.1` / `0.1.3-alpha.2` | `^0.84.2` | 三套隔离依赖树均通过完整检查及 33 项测试。新增 thinking-only 的 19 次真实 PiAi HTTP 请求回归,保留 thinking 且不发送 effort。未发布。 |
16
- | `0.1.0-dev.20260907.3`(仅本地候选) | 24 | `0.1.3-alpha.2` / `82a5fd61…` | `^0.84.2` | 250 个一致的 DSH 包通过真实模块解析;TypeScript、32 个插件测试、Host/Provider/Client 契约、13 个 Typert Remote 标记和真实 pi-ai reasoning HTTP 回归通过。未发布。 |
17
- | `0.1.0-dev.20260907.1`(仅本地候选) | 24 | `0.1.3-alpha.1` / `d347e703…` | `^0.84.2` | 247 个一致的 DSH 包通过真实模块解析;TypeScript、29 个插件测试、Host/Provider/Client 契约和 13 个 Typert Remote 标记通过。未发布。 |
18
- | `0.1.0` | 22、24 | `0.1.2-rc.1` / `a66e4702…` | `^0.84.2`(锁定为 `0.84.4`) | 精确 peer 闭包、Host/Client 契约检查、干净 npm 安装和隔离 Web/RPC 验收。 |
19
- | `0.1.0-alpha.11` | 22、24 | 声明基线仍为 `0.1.2-alpha.2`;另有主线 `0.1.2-rc.1` 隔离配置 RPC 探针 | `^0.84.2` | npm 作用域迁移;保留数据协议;不将 rc.1 探针视为完整版本兼容验收。 |
20
- | `0.1.0-alpha.10` | 22、24 | `0.1.2-alpha.2` / `0a53fb55…` | `^0.84.2`(npm/源码 Runtime 中为 `0.84.4`) | 迁移到 `SettingsProvider.installSection()`;npm 与源码 release-pack 双路径通过完整检查。 |
21
- | `0.1.0-alpha.9` | 22、24 | `0.1.2-alpha.1` / `cd5ef814…` | `^0.84.2`(已审查源码 Runtime 中为 `0.84.4`) | Web/native 只消费标准 Enterprise Profile;产品机构目录转换彻底移出插件。 |
22
- | `0.1.0-alpha.8` | 22、24 | `0.1.2-alpha.1` / `cd5ef814…` | `^0.84.2`(已审查源码 Runtime 中为 `0.84.4`) | Web/native 共用 Profile 凭据引用规则;支持生产/测试本地 Key 隔离,并对 native 引用错配失败关闭。 |
23
- | `0.1.0-alpha.7` | 22、24 | `0.1.2-alpha.1` / `cd5ef814…` | `^0.84.2`(已审查源码 Runtime 中为 `0.84.4`) | 开发环境可显式允许一个精确的网络 HTTP origin;生产仍强制 HTTPS。 |
24
- | `0.1.0-alpha.6` | 22、24 | `0.1.2-alpha.1` / `cd5ef814…` | `^0.84.2`(已审查源码 Runtime 中为 `0.84.4`) | 使用上游“模型”页面和官方 `settings.models.footer`;匹配的 npm 包发布前,应通过源码 release-pack 验证。 |
25
- | `0.1.0-alpha.5` | 22、24(开发) | `0.1.1-rc.2` / `b150a551…` | `0.82.1` | 文档改为优先从本地 checkout 安装;运行行为与 alpha.4 相同。 |
26
- | `0.1.0-alpha.4` | 22、24(开发) | `0.1.1-rc.2` / `b150a551…` | `0.82.1` | 支持直接安装 DSH Web Bundle,并提供完整第三方部署文档;ECNU 参考组合已完成产品/Web 验收。 |
27
- | `0.1.0-alpha.3` | 22、24(开发) | `0.1.1-rc.2` / `b150a551…` | `0.82.1` | Web/native 共用企业模型设置和 native 能力 adapter;尚待端到端产品验收。 |
28
- | `0.1.0-alpha.2` | 22、24(开发) | `0.1.1-rc.2` / `b150a551…` | `0.82.1` | Web 与 native adapter 统一使用标准 UserInfo 姓名显示;尚待真实部署验收。 |
29
- | `0.1.0-alpha.1` | 22、24(开发) | `0.1.1-rc.2` / `b150a551…` | `0.82.1` | 单元测试、构建和打包基线;仍需真实部署验收。 |
7
+ 当前源码支持 LiteLLM native contract 1、显式启用的 oidc-llm 0.1 实验模型接入,以及不附带模型资源的标准 OIDC 身份登录。oidc-llm 尚未定稿,默认关闭。
30
8
 
31
- 历史稳定版 `0.1.0` 对应精确 DSH `0.1.2-rc.1`。当前 `0.2.0` 冻结保持 dev.7 运行源码,开发/CI 基线在所需测试闭包内统一锁定 `0.1.5-rc.1`,不跟随产品号。表中旧行是当时的验收事实,不表示本轮重测全部旧 Runtime,也不表示公版仍含配额。见[开发准备](development.md)。
9
+ 本分支已删除旧 Key Binding 模型流程和 backend: native 账户桥,旧配置会报错。新客户端使用 Token;服务端可保留旧接口兼容已经发布的老客户端。此次破坏性变更尚未发布,发布前需选择合适的新包版本并同步已审查的产品锁,不能覆盖旧 npm 版本。
32
10
 
33
- ## 契约版本
11
+ ## 验证要求
34
12
 
35
- - Enterprise Profile:`dsh-oidc/v1alpha1`
36
- - Key Binding Profile 配置名称:`worker-user-center-v1` 或 `eduwork-resources-v1`;Bootstrap wire 兼容名称:`worker.user-center.v1`、`worker-user-center/v1`、`eduwork-resources/v1`
37
- - Typert 包/命名空间:`@eduwork/dsh-oidc` / `oidcAccounts`
38
- - 浏览器管理投影:`dsh-oidc/management/v1alpha1`
39
- - 回调路径:`/oauth/callback`
40
- - Provider 转换服务:`enterpriseTransforms`
41
- - 兼容旧版的 Provider 设置命名空间:`provider-enterprise`
13
+ 包级检查包含类型、构建、共享身份与网关回归、Schema、文档、秘密扫描和打包。真实 OIDC/LiteLLM、桌面加密存储、重启和界面分别验收,报告必须区分实际覆盖。
42
14
 
43
- 修改上述任一项都必须进行兼容性分析;涉及网络可见契约时,必须发布新的契约版本。
44
-
45
- ## 项目语义化版本
46
-
47
- 在 `1.0.0` 之前,minor 版本可以包含不兼容的 alpha 契约变更,但必须提供发布说明和迁移指引。同一已记录契约版本中的 patch 版本必须向后兼容。
48
-
49
- 在 `1.0.0` 之后:
50
-
51
- - 新增可选 Profile 字段和错误码可以作为 minor 版本发布;
52
- - 删除或重命名字段、修改固定路径、回调路径、默认凭据派生或身份规则,需要 major 版本或单独版本化的契约;
53
- - 因安全加固而拒绝此前接受的不安全输入,可以在醒目说明后作为 minor 或 patch 版本发布。
54
-
55
- ## 发布门槛
56
-
57
- 以下项目全部通过前,不得创建公开 tag 或发布 npm 包:
58
-
59
- - 在干净 checkout 中执行 `npm ci`;
60
- - Windows 和 Linux 上执行 `npm run check`;
61
- - CodeQL 或等效静态分析;
62
- - 依赖、许可证和安装脚本审查;
63
- - 密钥与生产地址扫描;
64
- - npm tarball 内容审查;
65
- - 纯 Web 端到端验收;
66
- - native 桌面无回退验收;
67
- - OIDC 反向测试和 Key Binding 授权测试;
68
- - 文档、版本和变更日志更新;
69
- - 对认证、凭据、构建或发布流程变更完成独立技术复核、CI/专项回归并记录维护者决定;增加第二位维护者后再加入独立人工批准。
70
-
71
- 操作检查项见[公开发布检查表](release-checklist.md)。
15
+ 迁移见[旧方案说明](key-binding-protocol.md),构建见[开发指南](development.md)。源码、npm 发布、客户端装配和生产部署分别执行。
@@ -14,7 +14,7 @@ The original product implementation coupled OIDC account behavior, institution c
14
14
  Publish one project/package named `dsh-oidc` containing:
15
15
 
16
16
  - standard OIDC Web client and a host-neutral native adapter contract;
17
- - the fixed Key Binding client;
17
+ - shared token authorization and lifecycle;
18
18
  - one local audited OpenAI-compatible DSH Provider adapter;
19
19
  - declarative Provider/model and bounded brand configuration;
20
20
  - standard account UI and one capability-aware enterprise-model settings surface shared by Web/native hosts;
@@ -23,7 +23,7 @@ Publish one project/package named `dsh-oidc` containing:
23
23
 
24
24
  Keep desktop shells, quotas, institutional business APIs, search, vision implementations, skills, packaging, and updates outside this repository.
25
25
 
26
- Enterprise Profiles are data and cannot select executable adapters or customize Key Binding wire fields.
26
+ Enterprise Profiles are data and cannot select executable adapters or override discovered authorization boundaries.
27
27
 
28
28
  ## Consequences
29
29
 
@@ -14,7 +14,7 @@
14
14
  发布一个名为 `dsh-oidc` 的项目和软件包,包含:
15
15
 
16
16
  - 标准 OIDC Web 客户端和宿主中立的 native adapter 契约;
17
- - 固定 Key Binding 客户端;
17
+ - 共享 Token 授权和生命周期;
18
18
  - 一个本地、经过审查的 OpenAI-compatible DSH Provider adapter;
19
19
  - 声明式 Provider/模型配置和有边界的品牌配置;
20
20
  - 标准账号 UI,以及 Web/native 宿主共用、可感知宿主能力的企业模型设置界面;
@@ -23,7 +23,7 @@
23
23
 
24
24
  桌面外壳、配额、机构业务 API、搜索、图像理解实现、Skill、打包和更新继续留在本仓库之外。
25
25
 
26
- Enterprise Profile 只是数据,不能选择可执行 adapter,也不能自定义 Key Binding 网络字段。
26
+ Enterprise Profile 只是数据,不能选择可执行 adapter,也不能改写已发现的授权边界。
27
27
 
28
28
  ## 影响
29
29
 
@@ -1,60 +1,59 @@
1
- # Desktop hosts without a persistent Web server
2
-
3
- [简体中文](desktop-host.md)
4
-
5
- Local candidate `0.2.0-dev.20260910.1` adds `backend: desktop`. OIDC validation, host credentials, Key Binding, model discovery and `authorizedFetch()` reuse the Web implementation; existing `web` and legacy native bridge modes remain supported.
6
-
7
- ```yaml
8
- - id: enterprise-oidc
9
- name: '@eduwork/dsh-oidc'
10
- config:
11
- backend: desktop
12
- allowEmptyProfiles: true
13
- profilePathEnv: EDUWORK_OIDC_PROFILE
14
- desktop:
15
- callbackPort: 0
16
- flowTimeoutMs: 600000
17
- ```
18
-
19
- The host supplies a Cordis `desktopServices` service with `openExternal(url: string): Promise<void>`. OIDC builds the authorization URL from reviewed Profile discovery; the renderer cannot submit an arbitrary URL. The shell opens the system browser, rejects non-HTTP(S) and userinfo URLs, and never logs authorization query parameters. The plugin does not execute shell commands or import Electron/Wails. The service can arrive later; removing it cancels pending sign-ins.
20
-
21
- When the distribution provides `configFile: {path, examplesPath}`, organization settings stay read-only and are loaded again on restart. The optional Host method `openConfiguration(target: 'config' | 'examples'): Promise<void>` enables configuration-file and example-folder buttons. The RPC accepts these two fixed targets only; the host resolves its own paths, and the renderer cannot send a path or command. `configuration().configFile.canOpen` reports availability. Web hosts without this capability show the configuration-file location instead. Personal models and configured organization sign-in remain available.
22
-
23
- Resource binding accepts the original `worker.user-center.v1`, the transitional `worker-user-center/v1`, and `eduwork-resources/v1`. Unknown versions and mismatched Provider IDs are rejected before creating a model credential. Completed identity sign-in is retained, with an error identifying the separate resource/configuration problem.
24
-
25
- The host must implement `credentials.resolve/set/unset`, backed by its operating-system vault. The plugin has no plaintext credential file or fallback on storage failure. OAuth tokens remain Host-only. Personal API keys remain independent of the organization's managed credential. The public `oidcAccounts.authorizedFetch()` capability remains Host-only.
26
-
27
- Only an explicit sign-in starts an IPv4 `127.0.0.1` listener. The callback is `http://127.0.0.1:<port>/oauth/callback`, using a random port by default. Register a public PKCE client supporting dynamic loopback ports with the IdP. For providers requiring an exact registered URI, a trusted `callbackPort` can pin the port; a conflict fails explicitly instead of switching to an unregistered port. Other bind addresses are not configurable. Cancellation, expiry, success, a valid failed callback, service disposal and host shutdown close the listener. Invalid Host, Origin, state, method or path cannot consume the legitimate attempt.
28
-
29
- Shared Host/Client RPC additions:
30
-
31
- - `begin(profileID)` returns `{mode:'external', loginID, expiresAt}` for desktop. Existing Web `redirect` and legacy `completed` variants remain supported.
32
- - `loginStatus(loginID)` returns `{loginID, profileID, state, expiresAt, status?, errorCode?}`. State is pending/completed/cancelled/expired/failed.
33
- - `cancelLogin(loginID)` returns the same safe projection and waits for an in-flight credential write to roll back.
34
- - `openConfiguration(target)` returns `{opened:true}` in file-managed mode; the only targets are `config` and `examples`. System-opening failures produce a concise message.
35
- - `selectEnterpriseModel(profileID, {onlyIfMissing?})` returns `{changed, selection?}` on DSH 0.1.5 and persists the default through `agentDefaultModel.saveSelection()`.
36
-
37
- Sign-in, sidebar and organization settings share one account snapshot. Credential Providers should emit the official `credentials/reference-updated` event after set/unset. The client listens to that forwarded Remote event and `connection/reset`; it does not depend on a custom account event that the official Remote transport does not forward.
38
-
39
- Explicit sign-in with a connected key, or confirmed key provisioning, selects the first resolvable enterprise model. A default is saved even when no session exists. For a current main session, the client also uses the official `modelDirectories.directoryFor(sessionID).select()` API; addressed subagents are left alone. Load the official `agentDefaultModel` and writable `settings` services. Older hosts without this capability show a message asking the user to choose from the model menu.
40
-
41
- Initial upgrade recovery uses `onlyIfMissing:true`: it preserves an existing resolvable default and repairs only an absent or unavailable one. A valid personal selection in the current session is also preserved. Credential events, connection checks and subsequent status refreshes never select a model. Personal credentials and unrelated settings remain unchanged.
42
-
43
- For desktop acceptance run `node scripts/serve-desktop-oidc-fixture.mjs --config <new test configuration file>`. It binds a random loopback port, serves synthetic HTTP PKCE/Key/models/quota and writes a public JSONC profile. The file must not exist; user configuration is never overwritten. Use isolated data directories for each shell and Ctrl+C to stop. No real accounts or model credits are used.
44
-
45
- The independent random login handle is not OAuth state. Results never carry an authorization URL, code, nonce, verifier or token. The client polls once per second, displays browser completion instructions and a cancel button, and cancels on unmount. Sign-in expires within ten minutes. Closing a system browser cannot reliably be detected across platforms; the app cancel action and expiry bound the listener lifetime.
46
-
47
- An empty Profile list is valid: no listener or organization login is needed. Identity-only profiles need no resource endpoints. Logout preserves personal keys. A resource outage after successful identity verification keeps the identity connected so resource access can be retried.
48
-
49
- Run `node --test test/desktop.test.js test/desktop-host.test.js`. To test a frozen installation, set `DSH_OIDC_PACKAGE_ROOT` to its package directory and `DSH_OIDC_EXPECT_DSH=0.1.5-rc.1`. The latter test uses the installed package's actual Host dependencies without WebServer, optional browser-service lifecycle and HTTP PKCE. All credentials and identities are synthetic. Shell vault, window and system-browser integration still require product acceptance.
50
-
51
- The `.20260910.6` public avatar menu provides account refresh and sign-out; quota UI requires an institution extension. A portal supports narrow sidebars; arrows, Home/End, Escape and outside click/focus are supported. Logout clears this profile's local identity, managed key and cached model metadata, serializes vault writes and rejects late writes. Personal keys remain untouched.
52
-
53
- The temporary HTTP callback page reads `brand.productName/organizationName/logoURL/mark/primaryColor` from this attempt's Profile and chooses Chinese or English from Accept-Language. It has no external fonts, scripts or raw error reflection and directs the user back to the app. Ordinary Web validation still redirects into its local app; model keys never enter the browser.
54
-
1
+ # Desktop hosts without a persistent Web server
2
+
3
+ [简体中文](desktop-host.md)
4
+
5
+ `backend: desktop` uses a temporary loopback callback for desktop sign-in. OIDC validation, host credentials, token refresh, model discovery and authorizedFetch reuse shared code. Web and desktop are supported; the legacy native account bridge is removed.
6
+
7
+ ```yaml
8
+ - id: enterprise-oidc
9
+ name: '@eduwork/dsh-oidc'
10
+ config:
11
+ backend: desktop
12
+ allowEmptyProfiles: true
13
+ profilePathEnv: EDUWORK_OIDC_PROFILE
14
+ desktop:
15
+ callbackPort: 0
16
+ flowTimeoutMs: 600000
17
+ ```
18
+
19
+ The host supplies a Cordis `desktopServices` service with `openExternal(url: string): Promise<void>`. OIDC builds the authorization URL from reviewed Profile discovery; the renderer cannot submit an arbitrary URL. The shell opens the system browser, rejects non-HTTP(S) and userinfo URLs, and never logs authorization query parameters. The plugin does not execute shell commands or import Electron/Wails. The service can arrive later; removing it cancels pending sign-ins.
20
+
21
+ When the distribution provides `configFile: {path, examplesPath}`, organization settings stay read-only and are loaded again on restart. The optional Host method `openConfiguration(target: 'config' | 'examples'): Promise<void>` enables configuration-file and example-folder buttons. The RPC accepts these two fixed targets only; the host resolves its own paths, and the renderer cannot send a path or command. `configuration().configFile.canOpen` reports availability. Web hosts without this capability show the configuration-file location instead. Personal models and configured organization sign-in remain available.
22
+
23
+
24
+ The host must implement `credentials.resolve/set/unset`, backed by its operating-system vault. The plugin has no plaintext credential file or fallback on storage failure. OAuth tokens remain Host-only. Personal API keys remain independent of the organization's managed credential. The public `oidcAccounts.authorizedFetch()` capability remains Host-only.
25
+
26
+ Only an explicit sign-in starts an IPv4 `127.0.0.1` listener. The callback is `http://127.0.0.1:<port>/oauth/callback`, using a random port by default. Register a public PKCE client supporting dynamic loopback ports with the IdP. For providers requiring an exact registered URI, a trusted `callbackPort` can pin the port; a conflict fails explicitly instead of switching to an unregistered port. Other bind addresses are not configurable. Cancellation, expiry, success, a valid failed callback, service disposal and host shutdown close the listener. Invalid Host, Origin, state, method or path cannot consume the legitimate attempt.
27
+
28
+ Shared Host/Client RPC additions:
29
+
30
+ - `begin(profileID)` returns `{mode:'external', loginID, expiresAt}` for desktop. Existing Web `redirect` and legacy `completed` variants remain supported.
31
+ - `loginStatus(loginID)` returns `{loginID, profileID, state, expiresAt, status?, errorCode?}`. State is pending/completed/cancelled/expired/failed.
32
+ - `cancelLogin(loginID)` returns the same safe projection and waits for an in-flight credential write to roll back.
33
+ - `openConfiguration(target)` returns `{opened:true}` in file-managed mode; the only targets are `config` and `examples`. System-opening failures produce a concise message.
34
+ - `selectEnterpriseModel(profileID, {onlyIfMissing?})` returns `{changed, selection?}` on DSH 0.1.5 and persists the default through `agentDefaultModel.saveSelection()`.
35
+
36
+ Sign-in, sidebar and organization settings share one account snapshot. Credential Providers should emit the official `credentials/reference-updated` event after set/unset. The client listens to that forwarded Remote event and `connection/reset`; it does not depend on a custom account event that the official Remote transport does not forward.
37
+
38
+ Explicit sign-in with a connected model service selects the first resolvable enterprise model. A default is saved even when no session exists. For a current main session, the client also uses the official `modelDirectories.directoryFor(sessionID).select()` API; addressed subagents are left alone. Load the official `agentDefaultModel` and writable `settings` services. Older hosts without this capability show a message asking the user to choose from the model menu.
39
+
40
+ Initial upgrade recovery uses `onlyIfMissing:true`: it preserves an existing resolvable default and repairs only an absent or unavailable one. A valid personal selection in the current session is also preserved. Credential events, connection checks and subsequent status refreshes never select a model. Personal credentials and unrelated settings remain unchanged.
41
+
42
+ For desktop acceptance run `node scripts/serve-desktop-oidc-fixture.mjs --config <new test configuration file>`. It binds a random loopback port, serves synthetic HTTP PKCE/Token/models/quota and writes a public JSONC profile. The file must not exist; user configuration is never overwritten. Use isolated data directories for each shell and Ctrl+C to stop. No real accounts or model credits are used.
43
+
44
+ The independent random login handle is not OAuth state. Results never carry an authorization URL, code, nonce, verifier or token. The client polls once per second, displays browser completion instructions and a cancel button, and cancels on unmount. Sign-in expires within ten minutes. Closing a system browser cannot reliably be detected across platforms; the app cancel action and expiry bound the listener lifetime.
45
+
46
+ An empty Profile list is valid: no listener or organization login is needed. Identity-only profiles need no resource endpoints. Logout preserves personal keys. A resource outage after successful identity verification keeps the identity connected so resource access can be retried.
47
+
48
+ Run `node --test test/desktop.test.js test/desktop-host.test.js`. To test a frozen installation, set `DSH_OIDC_PACKAGE_ROOT` to its package directory and `DSH_OIDC_EXPECT_DSH=0.1.5-rc.1`. The latter test uses the installed package's actual Host dependencies without WebServer, optional browser-service lifecycle and HTTP PKCE. All credentials and identities are synthetic. Shell vault, window and system-browser integration still require product acceptance.
49
+
50
+ The `.20260910.6` public avatar menu provides account refresh and sign-out; quota UI requires an institution extension. A portal supports narrow sidebars; arrows, Home/End, Escape and outside click/focus are supported. Logout clears this profile's local identity, Tokens and cached model metadata, serializes vault writes and rejects late writes. Personal keys remain untouched.
51
+
52
+ The temporary HTTP callback page reads `brand.productName/organizationName/logoURL/mark/primaryColor` from this attempt's Profile and chooses Chinese or English from Accept-Language. It has no external fonts, scripts or raw error reflection and directs the user back to the app. Ordinary Web validation still redirects into its local app; model keys never enter the browser.
53
+
55
54
  Run `npm run check` from an isolated dependency tree coherent with the exact target DSH. Do not relabel a bundle built using old root dependencies. `npm run check:browser` additionally uses that Runtime's `playwright-core` and locally installed headless Edge (or Chrome through `DSH_OIDC_BROWSER_CHANNEL`) to load the compiled client, verify menu/shared state/logout and capture branded callback pages. It does not replace native vault/system-browser acceptance.
56
55
 
57
- ## macOS handoff acceptance
56
+ ## macOS integration requirements
58
57
 
59
58
  The OIDC npm package is platform-independent JavaScript. It bundles no Electron, Wails, Keychain or Windows credential binary; macOS consumes the same exact version and integrity. The plugin has no platform branch: the Host interfaces above own shell differences. Windows validation does not establish macOS readiness.
60
59