@agent-network-protocol/dsh-anp-identity 0.1.0-dsh-test.20260831.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.
package/BOUNDARY.md ADDED
@@ -0,0 +1,47 @@
1
+ # Security and ownership boundary
2
+
3
+ The DSH package is a policy and lifecycle layer around ANP Identity. It does not replace the native custody boundary.
4
+
5
+ ## Trust zones
6
+
7
+ - ANP Identity Rust and its Node binding hold Store Root Keys, managed private keys, and decrypted signing material.
8
+ - The DSH Host process is trusted to load the native Provider and configure consumer policy.
9
+ - Ordinary `IdentityClientLease` consumers receive public identity data, signatures, verification outcomes, high-level document sessions, and complete HTTP responses.
10
+ - `HostProviderLease` consumers are explicitly listed in `allowProviderConsumers`. They may use sealed secret handoffs and exact HTTP Header patches for a native bridge. They must never forward those values to Browser, Remote, tools, or model APIs.
11
+
12
+ Consumer identifiers are soft same-process identities. The allowlists prevent accidental cross-plugin use and provide an auditable policy, but JavaScript in the same process is not a sandbox.
13
+
14
+ ## Secret rules
15
+
16
+ - The default client surface has no raw ECDH, private-key import, Root Key export, sealed envelope, or Header patch method.
17
+ - ECDH shared secrets, Root Keys, and imported identity material cross the JavaScript bridge only as `anp-sealed-secret/1` envelopes on the Host Provider surface.
18
+ - Injected Store Root Keys are a Host bootstrap exception. Supply them only programmatically; never serialize them into Loader configuration. The Provider copies each 32-byte input for one native call and clears that copy afterward.
19
+ - Payloads and HTTP bodies may be application-sensitive even though they are not key material. The plugin does not log them or place them in errors.
20
+ - The Node binding owns native temporary zeroization. JavaScript Buffers cannot be promised equivalent zeroization because the runtime may copy them.
21
+
22
+ ## Catalog rules
23
+
24
+ `catalog-v1` contains no cryptographic secrets. It records labels, handles, consumer grants, and Store identity references. The native Store is always identity truth.
25
+
26
+ - A create intent is durable before native creation. A separate cross-process create lock makes the Store delta recoverable without holding the catalog lock across a native await.
27
+ - A deletion tombstone blocks new grants, handles, and client signing before native deletion starts.
28
+ - Catalog writes use a generation check, an exclusive cross-process lock, a same-directory temporary file, `fsync`, atomic rename, and directory `fsync`.
29
+ - Corruption never falls back to guessed grants. Explicit rebuild produces only `Unclaimed` identities.
30
+ - Deleting an identity with another consumer grant is rejected.
31
+
32
+ ## HTTP dispatcher
33
+
34
+ The default client API exposes only `dispatch(Request, transport)`:
35
+
36
+ - exact HTTPS origins must be authorized by Host configuration and requested by the lease;
37
+ - caller-supplied `Authorization`, `Signature-Input`, `Signature`, and `Content-Digest` are rejected;
38
+ - replayable request bytes are buffered up to 4 MiB;
39
+ - the authenticated Request uses `redirect: 'manual'`;
40
+ - only `Content-Digest`, `Signature-Input`, and `Signature` may be applied from the native patch;
41
+ - transport failures propagate unchanged, while provider failures use stable codes without request or path detail.
42
+
43
+ AWiki's Bearer Token cache, challenge processing, and retry policy remain in `dsh-awiki` and AWiki IM Core. This package signs one exact request and does not duplicate that authentication state.
44
+
45
+ ## Out of scope
46
+
47
+ This package does not provide OS sandboxing, malicious-plugin isolation, DID resolution or publication, remote backup, Store rekey, Root Key rotation, or an end-user approval UI. Root Transfer user-presence confirmation remains an AWiki workflow above the Host Provider lease.
package/LICENSE ADDED
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright [yyyy] [name of copyright owner]
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,170 @@
1
+ # ANP Identity for DeepSeek Harness
2
+
3
+ `@agent-network-protocol/dsh-anp-identity` gives DSH applications one shared, multi-DID identity store without making each application implement key custody, DID document lifecycle, crash recovery, or request signing.
4
+
5
+ Applications use a small TypeScript facade through `ctx.anpIdentity`. The plugin delegates private-key operations to the ANP Identity native module, keeps private keys encrypted at rest, and stores only non-secret DSH metadata—labels, handles, and consumer grants—in its catalog.
6
+
7
+ ## What problem it solves
8
+
9
+ A DSH installation may host several plugins and several independent DIDs. Those plugins need consistent answers to the same questions:
10
+
11
+ - Where are DID private keys stored, and which key is valid for a purpose?
12
+ - How can a DID document update survive process and network failures?
13
+ - How can two plugins share an identity without either plugin owning its private key?
14
+ - How can a request be authenticated without exposing a reusable signature header patch?
15
+ - How can a Store contain several DIDs while handles and deletion grants remain consistent?
16
+
17
+ This package supplies that coordination layer. ANP Identity remains the source of truth for identities and encrypted keys. A transactional `catalog-v1` adds DSH-specific ownership metadata. Creation uses a recoverable intent; deletion writes a tombstone before touching the native Store; cross-process mutations use a file lock, generation checks, and atomic rename.
18
+
19
+ ## What it provides
20
+
21
+ - Multi-DID create, list, open, delete, and recovery operations.
22
+ - Purpose-based Ed25519 signing and verification.
23
+ - Origin Proof signing.
24
+ - Transactional DID document change sessions.
25
+ - Consumer-scoped leases, grants, labels, and unique handles.
26
+ - Bounded authenticated HTTP dispatch with exact HTTPS-origin allowlists, a 4 MiB body limit, managed-header rejection, and manual redirects.
27
+ - A separate Host Provider lease for AWiki IM Core and similar trusted native consumers. Host-only operations include sealed ECDH, sealed import/export, enrollment, Root Transfer, and exact HTTP header patches.
28
+
29
+ ## What it does not provide
30
+
31
+ - It is not a DID registry, resolver, publication server, backup system, or wallet UI.
32
+ - It does not implement AWiki messaging, Bearer Token state, challenge retries, or P5 Root Transfer. `dsh-awiki` and AWiki IM Core own those workflows.
33
+ - It does not expose raw ECDH shared secrets, Root Keys, imported private keys, or general signing tools to Browser, Remote, agents, or models.
34
+ - Consumer names are a same-process policy and diagnostics boundary. They prevent accidental misuse; they do not sandbox malicious code running in the same Node.js process.
35
+
36
+ See [BOUNDARY.md](./BOUNDARY.md) for the complete trust model.
37
+
38
+ ## Installation
39
+
40
+ Install the DSH plugin:
41
+
42
+ ```bash
43
+ pnpm add @agent-network-protocol/dsh-anp-identity
44
+ ```
45
+
46
+ The package installs the exact compatible ANP Identity wrapper. That wrapper
47
+ selects the prebuilt native package for the current platform; users do not need
48
+ Rust or a source checkout.
49
+
50
+ Load the Service before its Provider. The included `cordis.patch.yml` is a starting point:
51
+
52
+ The shipping DSH layer grants `@awiki/dsh-plugin` client and Host Provider
53
+ access by default so the documented two-plugin AWiki installation works without
54
+ an extra local patch. Set `DSH_ANP_IDENTITY_ALLOW_CONSUMERS` and
55
+ `DSH_ANP_IDENTITY_ALLOW_PROVIDER_CONSUMERS` to explicit JSON arrays to replace
56
+ those defaults for a different deployment.
57
+
58
+ ```yaml
59
+ - insert:
60
+ - id: anp-identity
61
+ name: '@agent-network-protocol/dsh-anp-identity'
62
+ config:
63
+ stateRoot: /var/lib/dsh/anp-identity
64
+ allowConsumers: ['example/identity-client', '@awiki/dsh-plugin']
65
+ allowProviderConsumers: ['@awiki/dsh-plugin']
66
+ httpAllowedOrigins:
67
+ example/identity-client: ['https://api.example.com']
68
+
69
+ - id: anp-identity-provider
70
+ name: '@agent-network-protocol/dsh-anp-identity/provider'
71
+ config:
72
+ stateRoot: /var/lib/dsh/anp-identity
73
+ rootKeyProvider: keyring
74
+ rootKeyProviderId: anp-identity/dsh
75
+ ```
76
+
77
+ `rootKeyProviderId` is `service/account` for keyring, the environment variable name for `env`, and the key id for programmatic `injected` setup. `local-file` must be selected explicitly; copying both the Store and its local Root Key file permits offline decryption.
78
+
79
+ ## Use it from another DSH plugin
80
+
81
+ Declare the Cordis dependency, acquire only the capabilities you need, and dispose the lease with the calling plugin's fiber:
82
+
83
+ ```ts
84
+ import type { Context } from '@deepseek-ai/cordis'
85
+ import type {} from '@agent-network-protocol/dsh-anp-identity'
86
+
87
+ export const inject = ['anpIdentity']
88
+
89
+ export async function apply(ctx: Context): Promise<void> {
90
+ const lease = await ctx.anpIdentity.acquireClient({
91
+ consumer: 'example/identity-client',
92
+ capabilities: ['identity:read', 'identity:create', 'identity:sign'],
93
+ })
94
+ ctx.effect(() => () => lease.dispose(), 'example: ANP Identity client lease')
95
+
96
+ const identities = await lease.list()
97
+ const identity = identities.length === 0
98
+ ? await lease.create({
99
+ label: 'Example agent',
100
+ identity: {
101
+ profile: 'e1',
102
+ domain: 'agents.example.com',
103
+ pathSegments: ['agents', 'example'],
104
+ managedKeys: [
105
+ { fragment: 'root', role: 'root_control' },
106
+ { fragment: 'request', role: 'request_signing' },
107
+ ],
108
+ },
109
+ })
110
+ : await lease.get(identities[0]!.reference)
111
+
112
+ const snapshot = await identity.publicIdentity()
113
+ await identity.sign({
114
+ purpose: 'authentication',
115
+ kid: `${snapshot.reference.did}#request`,
116
+ payload: Buffer.from('canonical application bytes'),
117
+ })
118
+ }
119
+ ```
120
+
121
+ For HTTP authentication, request `identity:http-auth`, configure an exact origin for that consumer, and call `identity.authenticatedHttp.dispatch(request, transport)`. The caller never receives the signature header patch.
122
+
123
+ ## Modules and cooperation
124
+
125
+ | Module | Responsibility |
126
+ | --- | --- |
127
+ | `ctx.anpIdentity` | Public multi-DID facade, client leases, catalog, grants, handles, and HTTP dispatch |
128
+ | `./provider` | Opens the native Store and registers exactly one native Provider with Cordis lifecycle ownership |
129
+ | `./provider-api` | Versioned Host-only contract used by an externally bridged native consumer such as AWiki IM Core |
130
+ | `@agent-network-protocol/anp-identity` | Encrypted key custody, DID documents, signing, recovery, and sealed secret handoffs |
131
+ | `dsh-awiki` | AWiki account, messaging, Bearer Token/challenge state, and application workflows |
132
+
133
+ Mobile applications do not need this DSH package. They can link the ANP Identity Rust crate directly through their native integration while using the same Facade and Host SPI semantics.
134
+
135
+ ## Recovery behavior
136
+
137
+ The native Store is always the identity truth. On startup:
138
+
139
+ - a Store identity absent from catalog and journals becomes `Unclaimed` with no grants;
140
+ - a catalog entry absent from the Store is removed;
141
+ - a pending create intent is completed when its Store identity can be identified;
142
+ - a deletion tombstone rolls forward;
143
+ - a corrupt catalog blocks grants and handles. Explicit `recover()` rebuilds entries as `Unclaimed` and never invents authorization.
144
+
145
+ `recover()` is an exclusive, Store-wide operation. Do not use it as a polling API.
146
+
147
+ ## Development
148
+
149
+ ```bash
150
+ npm install --legacy-peer-deps
151
+ npm run verify
152
+ ```
153
+
154
+ The test suite uses the real native binding for multi-DID, restart, signing, HTTP dispatch, corruption recovery, and tombstone recovery, plus real child processes for catalog locking.
155
+
156
+ The functional HTTP-signing E2E additionally requires the `dsh` CLI, Node
157
+ `^22.19.0` or `>=24.0.0`, `pnpm`, `uv`, OpenSSL, and the sibling ANP checkout
158
+ expected by the workspace:
159
+
160
+ ```bash
161
+ npm run test:functional
162
+ ```
163
+
164
+ It builds the debug native binding, packs and installs the native package and
165
+ DSH plugins into a temporary real DSH profile, then sends signed GET and POST
166
+ requests to an independent HTTPS process backed by the ANP Python verifier. A
167
+ tampered POST must be rejected. The temporary DSH profile, Store, certificate,
168
+ and tarballs are removed after the run.
169
+
170
+ Licensed under Apache-2.0.
package/README.zh.md ADDED
@@ -0,0 +1,148 @@
1
+ # 面向 DeepSeek Harness 的 ANP Identity
2
+
3
+ `@agent-network-protocol/dsh-anp-identity` 为 DSH 应用提供共享的多 DID 身份 Store。应用不需要各自实现私钥托管、DID Document 生命周期、崩溃恢复和请求签名。
4
+
5
+ 普通插件通过 `ctx.anpIdentity` 使用精简的 TypeScript Facade。私钥操作由 ANP Identity 原生模块完成;私钥在磁盘上加密保存。DSH catalog 只记录 label、handle 和 consumer grant 等非秘密元数据。
6
+
7
+ ## 它解决什么问题
8
+
9
+ 一个 DSH 安装中可能同时存在多个插件和多个 DID。这个插件统一解决:
10
+
11
+ - DID 私钥由谁保管,以及某个签名目的应该使用哪类密钥;
12
+ - DID Document 更新如何在进程崩溃或发布结果不确定时恢复;
13
+ - 多个插件如何共用身份,而不让任一普通插件取得私钥;
14
+ - HTTP 请求如何完成身份认证,同时不把可复用 Header patch 交给调用方;
15
+ - 多 DID、通用 handle、consumer grant 和删除保护如何保持一致。
16
+
17
+ ANP Identity Store 是身份与加密密钥的真值。插件增加事务化的 `catalog-v1`:创建前写 intent,删除前写 tombstone;跨进程修改使用文件锁、generation 检查和原子 rename。异常重启后流程会继续完成,未知身份只会成为无授权的 `Unclaimed`,不会猜测所有者。
18
+
19
+ ## 主要能力
20
+
21
+ - 多 DID 创建、列举、打开、删除和恢复;
22
+ - 按 purpose 约束的 Ed25519 签名与验签;
23
+ - Origin Proof 签名;
24
+ - 事务化 DID Document Change Session;
25
+ - consumer-scoped lease、grant、label 和唯一 handle;
26
+ - 有上限的 HTTP 认证 dispatcher:只允许配置的精确 HTTPS origin,body 最大 4 MiB,拒绝调用方预置认证 Header,并强制 manual redirect;
27
+ - 独立的 Host Provider lease,供 AWiki IM Core 等可信原生消费者使用。sealed ECDH、sealed 导入导出、enrollment、Root Transfer 和精确 Header patch 只在这个 Host 面存在。
28
+
29
+ ## 它不解决什么
30
+
31
+ - 它不是 DID Registry、Resolver、发布服务、备份系统或钱包 UI;
32
+ - 它不实现 AWiki 消息、Bearer Token、challenge 重试或 P5 Root Transfer;这些属于 `dsh-awiki` 与 AWiki IM Core;
33
+ - 它不向 Browser、Remote、Agent Tool 或模型暴露 raw ECDH shared secret、Root Key、导入私钥和通用签名工具;
34
+ - consumer 名称是同进程策略与诊断边界,可防误用,但不是针对同一 Node.js 进程内恶意代码的沙箱。
35
+
36
+ 完整边界见 [BOUNDARY.md](./BOUNDARY.md)。
37
+
38
+ ## 安装与配置
39
+
40
+ ```bash
41
+ pnpm add @agent-network-protocol/dsh-anp-identity
42
+ ```
43
+
44
+ 本包会安装精确兼容的 ANP Identity wrapper,由 wrapper 自动选择当前平台的预编译原生包;
45
+ 用户不需要 Rust 或源码 checkout。Cordis 中先装载 Service,再装载 Provider:
46
+
47
+ 随包发布的 DSH layer 默认向 `@awiki/dsh-plugin` 开放 client 和 Host Provider,确保文档中的
48
+ 双插件安装无需额外本地 patch。其他部署可通过
49
+ `DSH_ANP_IDENTITY_ALLOW_CONSUMERS` 与
50
+ `DSH_ANP_IDENTITY_ALLOW_PROVIDER_CONSUMERS` JSON 数组完整替换默认值。
51
+
52
+ ```yaml
53
+ - insert:
54
+ - id: anp-identity
55
+ name: '@agent-network-protocol/dsh-anp-identity'
56
+ config:
57
+ stateRoot: /var/lib/dsh/anp-identity
58
+ allowConsumers: ['example/identity-client', '@awiki/dsh-plugin']
59
+ allowProviderConsumers: ['@awiki/dsh-plugin']
60
+ httpAllowedOrigins:
61
+ example/identity-client: ['https://api.example.com']
62
+
63
+ - id: anp-identity-provider
64
+ name: '@agent-network-protocol/dsh-anp-identity/provider'
65
+ config:
66
+ stateRoot: /var/lib/dsh/anp-identity
67
+ rootKeyProvider: keyring
68
+ rootKeyProviderId: anp-identity/dsh
69
+ ```
70
+
71
+ keyring 的 `rootKeyProviderId` 格式为 `service/account`;env 模式填写环境变量名;injected 模式填写 key id,并且只能通过可信 Host 代码以 Buffer 注入,不能写入 Loader YAML。`local-file` 必须显式启用;如果 Store 与 Root Key 文件被一起复制,攻击者可以离线解密 Store。
72
+
73
+ ## 其他 DSH 插件如何使用
74
+
75
+ 调用插件声明 `inject = ['anpIdentity']`,申请最小 capability,并让 lease 随自己的 Cordis fiber 释放:
76
+
77
+ ```ts
78
+ const lease = await ctx.anpIdentity.acquireClient({
79
+ consumer: 'example/identity-client',
80
+ capabilities: ['identity:read', 'identity:create', 'identity:sign'],
81
+ })
82
+
83
+ const identity = await lease.create({
84
+ label: 'Example agent',
85
+ handle: 'example.agent',
86
+ identity: {
87
+ profile: 'e1',
88
+ domain: 'agents.example.com',
89
+ pathSegments: ['agents', 'example'],
90
+ managedKeys: [
91
+ { fragment: 'root', role: 'root_control' },
92
+ { fragment: 'request', role: 'request_signing' },
93
+ ],
94
+ },
95
+ })
96
+
97
+ const snapshot = await identity.publicIdentity()
98
+ await identity.sign({
99
+ purpose: 'authentication',
100
+ kid: `${snapshot.reference.did}#request`,
101
+ payload: Buffer.from('canonical application bytes'),
102
+ })
103
+ ```
104
+
105
+ HTTP 认证需要申请 `identity:http-auth`,由 Host 为该 consumer 配置精确 origin,然后调用 `identity.authenticatedHttp.dispatch(request, transport)`。普通 consumer 永远拿不到 Header patch。
106
+
107
+ ## 模块协作
108
+
109
+ | 模块 | 职责 |
110
+ | --- | --- |
111
+ | `ctx.anpIdentity` | 公共多 DID Facade、client lease、catalog、grant、handle 和 HTTP dispatch |
112
+ | `./provider` | 打开原生 Store,并按 Cordis 生命周期注册唯一 Provider |
113
+ | `./provider-api` | 提供给 AWiki IM Core 等外部原生消费者的版本化 Host-only 契约 |
114
+ | `@agent-network-protocol/anp-identity` | 加密密钥托管、DID Document、签名、恢复和 sealed secret handoff |
115
+ | `dsh-awiki` | AWiki 账户、消息、Bearer Token/challenge 状态和应用工作流 |
116
+
117
+ 移动端不依赖这个 DSH 包,可直接链接 ANP Identity Rust crate,同时复用相同的 Facade/Host SPI 语义。
118
+
119
+ ## 恢复语义
120
+
121
+ - Store 有身份、catalog/journal 没有记录:重建为无 grant 的 `Unclaimed`;
122
+ - catalog 有记录、Store 没有身份:删除 dangling 条目;
123
+ - create intent 未完成:在能够唯一识别 Store 身份时继续提交;
124
+ - deletion tombstone 未完成:继续删除;
125
+ - catalog 损坏:grant 与 handle fail closed。显式执行 `recover()` 后,按 Store 重建为 `Unclaimed`,不会伪造授权。
126
+
127
+ `recover()` 会获取 Store 级独占锁并执行全量恢复,不应作为轮询 API。
128
+
129
+ ## 开发验证
130
+
131
+ ```bash
132
+ npm install --legacy-peer-deps
133
+ npm run verify
134
+ ```
135
+
136
+ HTTP 签名功能 E2E 还需要 `dsh` CLI、Node `^22.19.0` 或 `>=24.0.0`、
137
+ `pnpm`、`uv`、OpenSSL,以及工作区约定的相邻 ANP checkout:
138
+
139
+ ```bash
140
+ npm run test:functional
141
+ ```
142
+
143
+ 该命令会构建 debug native binding,将 native package、DSH 插件和测试
144
+ consumer 打包并安装到临时的真实 DSH profile,再向使用 ANP Python verifier
145
+ 的独立 HTTPS 进程发送签名 GET 和 POST;篡改后的 POST 必须被拒绝。运行结束
146
+ 后会删除临时 DSH profile、Store、证书和 tarball。
147
+
148
+ 许可证:Apache-2.0。
@@ -0,0 +1,21 @@
1
+ # Host-only ANP Identity service and its native Provider. Apply after the DSH
2
+ # base profile. Keep the Provider after the Service so Cordis injection owns
3
+ # shutdown ordering.
4
+
5
+ - insert:
6
+ - id: anp-identity
7
+ name: '@agent-network-protocol/dsh-anp-identity'
8
+ config:
9
+ stateRoot: !!js process.env.DSH_ANP_IDENTITY_STATE_ROOT
10
+ allowConsumers: !!js JSON.parse(process.env.DSH_ANP_IDENTITY_ALLOW_CONSUMERS ?? '["@awiki/dsh-plugin"]')
11
+ allowProviderConsumers: !!js JSON.parse(process.env.DSH_ANP_IDENTITY_ALLOW_PROVIDER_CONSUMERS ?? '["@awiki/dsh-plugin"]')
12
+ httpAllowedOrigins: !!js JSON.parse(process.env.DSH_ANP_IDENTITY_HTTP_ALLOWED_ORIGINS ?? '{}')
13
+ recoveryOnOpen: true
14
+
15
+ - id: anp-identity-provider
16
+ name: '@agent-network-protocol/dsh-anp-identity/provider'
17
+ config:
18
+ stateRoot: !!js process.env.DSH_ANP_IDENTITY_STATE_ROOT
19
+ rootKeyProvider: !!js process.env.DSH_ANP_IDENTITY_ROOT_KEY_PROVIDER ?? 'keyring'
20
+ rootKeyProviderId: !!js process.env.DSH_ANP_IDENTITY_ROOT_KEY_PROVIDER_ID ?? 'anp-identity/dsh'
21
+ keyringFallbackToLocalFile: false
@@ -0,0 +1,32 @@
1
+ import type { Context } from '@deepseek-ai/cordis'
2
+ import type {} from '@agent-network-protocol/dsh-anp-identity'
3
+
4
+ export const name = 'anp-identity-third-party-example'
5
+ export const inject = ['anpIdentity']
6
+
7
+ export async function apply(ctx: Context): Promise<void> {
8
+ const lease = await ctx.anpIdentity.acquireClient({
9
+ consumer: 'example/identity-client',
10
+ capabilities: ['identity:read', 'identity:create', 'identity:sign', 'identity:handle'],
11
+ })
12
+ ctx.effect(() => () => lease.dispose(), 'example: ANP Identity client lease')
13
+ const identity = await lease.create({
14
+ label: 'Example agent',
15
+ handle: 'example.agent',
16
+ identity: {
17
+ profile: 'e1',
18
+ domain: 'agents.example.com',
19
+ pathSegments: ['agents', 'example'],
20
+ managedKeys: [
21
+ { fragment: 'root', role: 'root_control' },
22
+ { fragment: 'request', role: 'request_signing' },
23
+ ],
24
+ },
25
+ })
26
+ const publicIdentity = await identity.publicIdentity()
27
+ await identity.sign({
28
+ purpose: 'authentication',
29
+ kid: `${publicIdentity.reference.did}#request`,
30
+ payload: Buffer.from('application-defined canonical bytes'),
31
+ })
32
+ }