@agentunion/fastaun 0.5.28 → 0.5.29
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/CHANGELOG.md +19 -0
- package/_packed_docs/CHANGELOG.md +19 -0
- package/_packed_docs/INDEX.md +9 -4
- package/_packed_docs/KITE_DOCS_GUIDE.md +4 -3
- package/_packed_docs/cli//345/207/255/350/257/201/344/270/216/347/273/204/347/273/207/346/234/215/345/212/241CLI/345/274/200/345/217/221/344/270/216/344/275/277/347/224/250/346/214/207/345/215/227.md +869 -0
- package/_packed_docs/sdk/0.5.27-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +408 -0
- package/_packed_docs/sdk/0.5.27-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +410 -0
- package/_packed_docs/sdk/0.5.28-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +228 -0
- package/_packed_docs/sdk/0.5.28-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +146 -0
- package/_packed_docs/sdk/0.5.29-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +180 -0
- package/_packed_docs/sdk/0.5.29-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +164 -0
- package/_packed_docs/sdk/09-/347/273/204/347/273/207/346/234/215/345/212/241RPC/346/211/213/345/206/214.md +90 -90
- package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +5 -3
- package/_packed_docs/sdk/INDEX.md +12 -4
- package/_packed_docs/sdk//345/207/255/350/257/201/344/270/216/347/273/204/347/273/207/346/234/215/345/212/241SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +1 -1
- package/_packed_docs/sdk//345/207/255/350/257/201/344/270/216/347/273/204/347/273/207/346/234/215/345/212/241SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +1 -1
- package/_packed_docs//346/216/247/345/210/266/346/266/210/346/201/257/344/270/216/350/256/276/345/244/207/350/203/275/345/212/233/345/215/217/345/225/206/346/226/271/346/241/210.md +426 -0
- package/_packed_docs//346/266/210/346/201/257/345/220/214/346/255/245/344/270/216/345/216/206/345/217/262/346/213/211/345/217/226/344/273/243/347/240/201/345/256/241/346/237/245/351/227/256/351/242/230/346/270/205/345/215/225.md +279 -229
- package/_packed_docs//351/243/216/346/216/247/345/223/215/345/272/224/344/270/216SDK/345/215/217/345/220/214/346/226/271/346/241/210.md +381 -0
- package/dist/agent-md-changes.d.ts +2 -14
- package/dist/agent-md-changes.js +41 -212
- package/dist/agent-md-changes.js.map +1 -1
- package/dist/agent-md-schema.js +2 -2
- package/dist/agent-md-schema.js.map +1 -1
- package/dist/agent-md.d.ts +4 -6
- package/dist/agent-md.js +53 -53
- package/dist/agent-md.js.map +1 -1
- package/dist/aid-store.d.ts +3 -1
- package/dist/aid-store.js +61 -40
- package/dist/aid-store.js.map +1 -1
- package/dist/client/control-messages.js +28 -6
- package/dist/client/control-messages.js.map +1 -1
- package/dist/client/delivery.js +2 -1
- package/dist/client/delivery.js.map +1 -1
- package/dist/client/group-state.js +2 -3
- package/dist/client/group-state.js.map +1 -1
- package/dist/client/lifecycle.js +0 -2
- package/dist/client/lifecycle.js.map +1 -1
- package/dist/client/v2-e2ee.js +8 -4
- package/dist/client/v2-e2ee.js.map +1 -1
- package/dist/client.d.ts +2 -2
- package/dist/client.js +96 -46
- package/dist/client.js.map +1 -1
- package/dist/discovery.js +2 -1
- package/dist/discovery.js.map +1 -1
- package/dist/ownership-v21.d.ts +2 -1
- package/dist/ownership-v21.js +17 -3
- package/dist/ownership-v21.js.map +1 -1
- package/dist/ownership-workflow.js +9 -5
- package/dist/ownership-workflow.js.map +1 -1
- package/dist/semantic-facade.js +4 -2
- package/dist/semantic-facade.js.map +1 -1
- package/dist/semantic-protocol.js +2 -0
- package/dist/semantic-protocol.js.map +1 -1
- package/dist/tools/cross-sdk-agent.d.ts +1 -1
- package/dist/tools/cross-sdk-agent.js +16 -34
- package/dist/tools/cross-sdk-agent.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +8 -8
|
@@ -0,0 +1,869 @@
|
|
|
1
|
+
# 凭证与组织服务 CLI 开发与使用指南
|
|
2
|
+
|
|
3
|
+
以当前仓库的 AUN CLI 为基准,示例统一使用 Node TS。CLI 实现位于 Python SDK;各节 CLI 与直接 SDK 示例是两种接入方式,选择其中一种执行。安装与 profile 配置见 [CLI 手册](CLI手册.md)。
|
|
4
|
+
|
|
5
|
+
| 凭证模式 | 版本与验收 |
|
|
6
|
+
| --- | --- |
|
|
7
|
+
| 原结构化 | `aun-cap/1`;非空 cap,按能力与 constraints 确定性验收 |
|
|
8
|
+
| 纯语义 | `aun-cap/semantic-1`;cap=[],正文、确认元数据与业务复核 |
|
|
9
|
+
| 混合 | `aun-cap/semantic-1`;非空 cap+授权正文,两部分限制取交集 |
|
|
10
|
+
|
|
11
|
+
三种模式保留各自原件与验证流程;普通结构化接入见 §4.1,语义接入见 §4.2—§7。
|
|
12
|
+
|
|
13
|
+
## 1. 调用入口与材料
|
|
14
|
+
|
|
15
|
+
```mermaid
|
|
16
|
+
flowchart LR
|
|
17
|
+
A[TS 运行器:参数数组与材料文件] --> B[AUN CLI:profile、输入、输出]
|
|
18
|
+
B --> C[SDK:签名、请求准备、验真与持久恢复]
|
|
19
|
+
C --> D[Gateway service-plane]
|
|
20
|
+
D --> E[Credential/Org 服务]
|
|
21
|
+
F[直接集成的 TS 应用] --> G[TS SDK 的相同业务流程]
|
|
22
|
+
G --> D
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
| 准备项 | 本文约定 |
|
|
26
|
+
| --- | --- |
|
|
27
|
+
| 环境 | CN;服务为 `credential.agentid.cn`、`org.agentid.cn` |
|
|
28
|
+
| 身份 | `cn-issuer` 签发,`cn-delegate` 受托签发,`cn-confirmer` 确认,`cn-owner` 管理组织,`cn-member` 入组,`cn-target` 接受转让;`cn` 为日常管理 profile |
|
|
29
|
+
| 材料目录 | 每次流程使用独立工作目录,先保存输入,再调用;已保存输入用于原请求续跑 |
|
|
30
|
+
| 可信输入 | authority、固定版本 policy、证书与根证书;验收端另从认证收件通道取得 authenticated 和业务事实 |
|
|
31
|
+
| SDK 示例 | client/ownerClient/memberClient/targetClient 为对应角色已连接客户端;signer、持久 store 与业务端口由应用提供 |
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
import { execFile } from 'node:child_process';
|
|
35
|
+
import { promisify } from 'node:util';
|
|
36
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
37
|
+
import { randomBytes, randomUUID, X509Certificate } from 'node:crypto';
|
|
38
|
+
import { semanticProtocol as sp } from '@agentunion/fastaun';
|
|
39
|
+
const execFileAsync = promisify(execFile);
|
|
40
|
+
const executable = process.platform === 'win32' ? 'aun.exe' : 'aun';
|
|
41
|
+
const profile = 'cn';
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
async function aun<T = unknown>(args: string[], selectedProfile = profile): Promise<T> {
|
|
46
|
+
const { stdout } = await execFileAsync(executable,
|
|
47
|
+
['--profile', selectedProfile, '--json', ...args],
|
|
48
|
+
{ encoding: 'utf8', shell: false, env: { ...process.env, PYTHONUTF8: '1' } });
|
|
49
|
+
return JSON.parse(stdout) as T;
|
|
50
|
+
}
|
|
51
|
+
async function saveJson(path: string, value: unknown): Promise<void> {
|
|
52
|
+
await writeFile(path, JSON.stringify(value), { encoding: 'utf8', flag: 'wx' });
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Windows 使用安装后的 `aun.exe`,Linux/macOS 使用 `aun`;也可将 executable 指向实际安装位置。帮助输出为文本,按文本读取。
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
const identity = await aun(['whoami']);
|
|
60
|
+
const help = await execFileAsync(executable, ['credential', '--help'], { encoding: 'utf8' });
|
|
61
|
+
console.log(help.stdout);
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## 2. 参数、输出与原字节
|
|
65
|
+
|
|
66
|
+
```mermaid
|
|
67
|
+
flowchart LR
|
|
68
|
+
A[TS 对象] --> B[UTF-8 JSON 输入文件]
|
|
69
|
+
B --> C[params/context 使用 @文件]
|
|
70
|
+
C --> D{CLI 结果}
|
|
71
|
+
D -->|退出 0| E[stdout:原始结果 JSON]
|
|
72
|
+
D -->|非 0| F[stderr:结构化错误 JSON]
|
|
73
|
+
E --> G[保存结果与本阶段进度]
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
| 入口 | 参数规则 |
|
|
77
|
+
| --- | --- |
|
|
78
|
+
| `credential` | `--params` 可放命令组或具体命令后,内容为严格 JSON 对象 |
|
|
79
|
+
| `credential --target <service-aid>` | 选择语义管理权威;放具体命令前,转交 SDK 的 target |
|
|
80
|
+
| `credential … --context` | 验真上下文;支持 JSON 或 `@UTF-8文件` |
|
|
81
|
+
| `org --params <JSON/@文件> …` | 放具体子命令前;用于完整业务材料、credentials 或已准备请求 |
|
|
82
|
+
| `org --params` 含 request_binding/client_signature/signature | 按完整请求透传;必填命令行位置参数仍须填写,并与材料一致 |
|
|
83
|
+
| `credential … --output <新文件>` | 独占创建;SignedJsonBytes 保存解码后的签名 JSON 原字节,其他结果保存 canonical JSON |
|
|
84
|
+
|
|
85
|
+
stdout 中的签名结果仍是 `{bytes_base64}`。从签名原件文件恢复该包装:
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
const savedOriginal: sp.SignedJsonBytes = {
|
|
89
|
+
bytes_base64: (await readFile('original.json')).toString('base64'),
|
|
90
|
+
};
|
|
91
|
+
await saveJson('saved-original-wrapper.json', savedOriginal);
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
登记的 original/metadata 使用原字节包装;lineage 的 credential/metadata 使用解码后的对象。原件文件按原字节读取,后续摘要使用 SDK canonical 规则。
|
|
95
|
+
|
|
96
|
+
## 3. 凭证命令地图
|
|
97
|
+
|
|
98
|
+
以下 23 个命令均位于根级 `credential`;组织成员凭证管理位于 `org credential`。
|
|
99
|
+
|
|
100
|
+
| 场景 | CLI 命令 | 对应 SDK 能力 |
|
|
101
|
+
| --- | --- | --- |
|
|
102
|
+
| 普通 CAP | `create`、`current` | 创建已签 CAP;读取本地管理记录及续期 successor |
|
|
103
|
+
| 登记与状态 | `register`、`get`、`status`、`revoke` | 普通/语义按 SDK 字段分流;get 为语义修订读取 |
|
|
104
|
+
| 修订与 CRL | `revise`、`revocations`、`revocation-list` | 语义 CAS/签名分页;revocation-list 同时保留普通列表入口 |
|
|
105
|
+
| UsageRef 协调 | `usage-prepare`、`usage-commit`、`usage-abort` | prepareUsage/commitUsage/abortUsage |
|
|
106
|
+
| 语义签名 | `sign`、`metadata-sign`、`allocation-sign`、`usage-record-sign` | signCredential/signMetadata/signAllocation/signUsageRecord |
|
|
107
|
+
| 验真 | `verify` | 普通 structured 完整验收;语义原件、metadata、回执、状态、包或配套对象验真 |
|
|
108
|
+
| 出示与验收 | `package`、`request`、`request-verify`、`decision-input` | 构包、业务请求、请求验真、模型输入 |
|
|
109
|
+
| 消息证据 | `evidence-export`、`evidence-verify` | 原字节生成 EvidenceRef;从凭证验真正文 |
|
|
110
|
+
|
|
111
|
+
| `verify --kind` | 参数补充 |
|
|
112
|
+
| --- | --- |
|
|
113
|
+
| `structured` | 普通 CAP+实际请求 context;CLI 经 SDK 获取各层当前状态与可信证书,调用完整 Verify |
|
|
114
|
+
| `original`/`metadata`/`receipt`/`status`/`package` | 对应语义对象与可信 context |
|
|
115
|
+
| `allocation`/`allocation-status` | 对应签名域验真;业务消费另验分配关系、查询绑定与在线状态 |
|
|
116
|
+
| `usage-record` | 另传 `--domain` |
|
|
117
|
+
|
|
118
|
+
`usage-record-sign --kind` 与 `verify --kind usage-record --domain` 使用这些域:`usage-allocation`、`allocation-status`、`semantic-crl`、`usage-transition`、`usage-checkpoint`、`usage-acceptance`、`ledger-abort`。
|
|
119
|
+
|
|
120
|
+
签名命令加载所选 profile 的真实私钥;非 online 的语义 verify 在 certificates+trusted_roots 齐备时可免认证连接。structured Verify、create/current 及 package/request/evidence-export 使用 CLI 的认证会话。
|
|
121
|
+
|
|
122
|
+
## 4. 凭证签发、登记与出示
|
|
123
|
+
|
|
124
|
+
### 4.1 普通结构化凭证
|
|
125
|
+
|
|
126
|
+
```mermaid
|
|
127
|
+
flowchart LR
|
|
128
|
+
A[issuer 创建根 CAP 与非空约束] --> B[受托方签子 CAP,逐层收窄]
|
|
129
|
+
B --> C[register:完整原件与请求绑定]
|
|
130
|
+
C --> D[核对登记回执,交付 holder]
|
|
131
|
+
D --> E[真实业务请求与认证 actor]
|
|
132
|
+
E --> F[verify structured:强状态、签名、父链、能力与请求]
|
|
133
|
+
F --> G[幂等执行业务]
|
|
134
|
+
G --> H[撤销、CRL 同步与 current 恢复]
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
#### 4.1.1 根凭证、约束与委托收窄
|
|
138
|
+
|
|
139
|
+
```ts
|
|
140
|
+
const ordinaryServiceAid = 'credential.agentid.cn';
|
|
141
|
+
await saveJson('cap-input.json', { sub: delegateAid, aud: [businessAid], delegate: true,
|
|
142
|
+
key_version: issuerSigner.certFingerprint, cap: [{ ns: 'files', action: 'read',
|
|
143
|
+
resource: '/reports', constraints: [{ type: 'max_value', field: 'rows', value: 100 }] }] });
|
|
144
|
+
const cap = await aun<sp.StructuredCredential>(['credential', 'create', '--params', '@cap-input.json'], 'cn-issuer');
|
|
145
|
+
await saveJson('cap.json', cap);
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
根凭证 sub 为受托签发者;子凭证由该身份签署,行数上限从 100 收窄为 10:
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
const childExpiry = Math.min(cap.exp,
|
|
152
|
+
Math.trunc(new Date(new X509Certificate(delegateSigner.certPem).validTo).getTime() / 1000));
|
|
153
|
+
await saveJson('child-input.json', { sub: holderAid, aud: [businessAid],
|
|
154
|
+
parent: cap.cid, proof_chain: [cap], delegation_depth: 1, delegate: false,
|
|
155
|
+
nbf: Math.max(cap.nbf, Math.trunc(Date.now() / 1000)), exp: childExpiry,
|
|
156
|
+
key_version: delegateSigner.certFingerprint, cap: [{ ns: 'files', action: 'read',
|
|
157
|
+
resource: '/reports', constraints: [{ type: 'max_value', field: 'rows', value: 10 }] }] });
|
|
158
|
+
const child = await aun<sp.StructuredCredential>([
|
|
159
|
+
'credential', 'create', '--params', '@child-input.json'], 'cn-delegate');
|
|
160
|
+
await saveJson('child.json', child);
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
每层保持签发者=父 holder,受众、期限、能力和约束逐层收窄,最大深度 8。成员角色 CAP 使用组织流程生成。
|
|
164
|
+
|
|
165
|
+
#### 4.1.2 普通请求绑定、登记与回执
|
|
166
|
+
|
|
167
|
+
以下使用仓库的真实绑定 helper;npm 应用可按 [SDK 移植指南 §5.4](../sdk/凭证与组织服务SDK开发与移植指南.md#54-credential-request-binding) 实现相同适配:
|
|
168
|
+
|
|
169
|
+
```ts
|
|
170
|
+
import { buildRequestBinding } from '../../ts/src/org-protocol.js';
|
|
171
|
+
function ordinaryInput(method: string, target: string, credentialCid: string,
|
|
172
|
+
fields: Record<string, unknown>) {
|
|
173
|
+
const now = Math.trunc(Date.now() / 1000);
|
|
174
|
+
const input = { ...fields, request_id: randomUUID(), nonce: randomBytes(32).toString('base64url') };
|
|
175
|
+
return { ...input, request_binding: buildRequestBinding(method, target, input, credentialCid,
|
|
176
|
+
input.nonce, input.request_id, now, now + 300) };
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
```ts
|
|
181
|
+
const rootRegistration = ordinaryInput('credential.register', ordinaryServiceAid, cap.cid,
|
|
182
|
+
{ registrar_aid: issuerAid, credential: cap });
|
|
183
|
+
await saveJson('cap-registration.json', rootRegistration);
|
|
184
|
+
const capRegistration = await aun<{ registrationReceipt: unknown }>([
|
|
185
|
+
'credential', 'register', '--params', '@cap-registration.json'], 'cn-issuer');
|
|
186
|
+
await saveJson('cap-registration-result.json', capRegistration);
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
```ts
|
|
190
|
+
const childRegistration = ordinaryInput('credential.register', ordinaryServiceAid, child.cid,
|
|
191
|
+
{ registrar_aid: delegateAid, credential: child, proof_chain: [cap] });
|
|
192
|
+
await saveJson('child-registration.json', childRegistration);
|
|
193
|
+
const childRegistered = await aun<{ registrationReceipt: unknown }>([
|
|
194
|
+
'credential', 'register', '--params', '@child-registration.json'], 'cn-delegate');
|
|
195
|
+
client.credential.verifyRegistrationReceipt(childRegistered.registrationReceipt, child,
|
|
196
|
+
childRegistration, resolveCertificate, ordinaryServiceAid);
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
resolveCertificate 来自已验信任的证书缓存。转交登记的 issuer 签名授权构造见 [SDK 应用指南 §3](../sdk/凭证与组织服务SDK应用集成指南.md#3-结构化凭证接入)。普通接口字段见 [RPC 手册](../sdk/09-凭证服务RPC手册.md#credentialregister)。
|
|
200
|
+
|
|
201
|
+
#### 4.1.3 状态查询与完整 Verify
|
|
202
|
+
|
|
203
|
+
```mermaid
|
|
204
|
+
sequenceDiagram
|
|
205
|
+
participant B as 业务验收端/CLI
|
|
206
|
+
participant C as Credential 权威
|
|
207
|
+
participant V as SDK 完整 Verify
|
|
208
|
+
B->>C: 每层新 status 请求:CID、独立 ID/nonce 与绑定
|
|
209
|
+
C-->>B: 签名 proof:全文 hash、状态、原查询及时间窗
|
|
210
|
+
B->>B: 验服务信任、签名、响应 target=查询者 AID
|
|
211
|
+
B->>V: 强 proof 缓存+真实业务请求与 actor
|
|
212
|
+
V-->>B: 签名、父链、约束与请求全部通过
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
单独查询并保存普通 proof:
|
|
216
|
+
|
|
217
|
+
```ts
|
|
218
|
+
const ordinaryStatusInput = ordinaryInput('credential.status', ordinaryServiceAid, child.cid,
|
|
219
|
+
{ credential_cid: child.cid, include_chain: true });
|
|
220
|
+
await saveJson('ordinary-status-input.json', ordinaryStatusInput);
|
|
221
|
+
const ordinaryProof = await aun(['credential', 'status', '--params', '@ordinary-status-input.json']);
|
|
222
|
+
await saveJson('ordinary-status-proof.json', ordinaryProof);
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
业务验收端从实际认证请求生成 context;rows=5 满足子凭证上限 10:
|
|
226
|
+
|
|
227
|
+
```ts
|
|
228
|
+
const operation = ordinaryInput('files.read', businessAid, child.cid, { report: reportId, rows: 5 });
|
|
229
|
+
await saveJson('ordinary-operation.json', operation);
|
|
230
|
+
const structuredContext = { audience: businessAid, subject: holderAid, root_issuer: issuerAid,
|
|
231
|
+
actor: authentication.actor, ns: 'files', action: 'read', resource: '/reports',
|
|
232
|
+
method: 'files.read', target: businessAid, params: operation, request_id: operation.request_id,
|
|
233
|
+
nonce: operation.nonce, request_binding: operation.request_binding,
|
|
234
|
+
credential_services: { [cap.cid]: ordinaryServiceAid, [child.cid]: ordinaryServiceAid } };
|
|
235
|
+
await saveJson('structured-context.json', structuredContext);
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
```ts
|
|
239
|
+
const structuredReport = await aun(['credential', 'verify', '--kind', 'structured',
|
|
240
|
+
'--params', '@child.json', '--context', '@structured-context.json']);
|
|
241
|
+
await saveJson('structured-verification-result.json', structuredReport);
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
`verify --kind structured` 使用认证会话,经 SDK 为每层重新获取当前强 proof 和可信历史证书,再同步执行普通完整 Verify。context 传普通 snake_case 字段,业务 actor 取认证通道;服务映射取本地可信配置。
|
|
245
|
+
|
|
246
|
+
CLI 提供通用 CAP/委托链完整验真;成员当前状态、Ownership/actor 状态及 rate_limit 事务通过应用的 SDK 端口接入。完整 Verify 按所需端口校验。普通 proof 的签验和同步 resolver 适配见 [SDK 移植指南 §6](../sdk/凭证与组织服务SDK开发与移植指南.md#6-facade-和-rpc-映射)。
|
|
247
|
+
|
|
248
|
+
#### 4.1.4 撤销、分页与持久进度
|
|
249
|
+
|
|
250
|
+
```mermaid
|
|
251
|
+
flowchart LR
|
|
252
|
+
A[issuer 按原 CID 与绑定 revoke] --> B[确认 revoked 与原请求结果]
|
|
253
|
+
B --> C[revocation-list:沿保存 cursor/since_event_seq]
|
|
254
|
+
C --> D[验权威签名、原查询与窗口]
|
|
255
|
+
D --> E[原子合并事件与进度]
|
|
256
|
+
E -->|next_cursor 非空| C
|
|
257
|
+
E -->|next_cursor 为空| F[保存连续事件水位]
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
```ts
|
|
261
|
+
const ordinaryRevokeInput = ordinaryInput('credential.revoke', ordinaryServiceAid, child.cid,
|
|
262
|
+
{ registrar_aid: delegateAid, credential_cid: child.cid, reason_code: 'grant_withdrawn' });
|
|
263
|
+
await saveJson('ordinary-revoke-input.json', ordinaryRevokeInput);
|
|
264
|
+
const ordinaryRevoked = await aun(['credential', 'revoke', '--params', '@ordinary-revoke-input.json'], 'cn-delegate');
|
|
265
|
+
await saveJson('ordinary-revoke-result.json', ordinaryRevoked);
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
app.verifyOrdinaryCrl/commitOrdinaryCrl 按移植指南 §6 实现验签及原子合并;分页前恢复上次进度:
|
|
269
|
+
|
|
270
|
+
```ts
|
|
271
|
+
type OrdinaryCrlPage = { events: Array<{ event_seq: number; cid: string }>; next_cursor: string };
|
|
272
|
+
let ordinaryCursor = restoredCrlCursor || String(ordinarySince);
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
```ts
|
|
276
|
+
do {
|
|
277
|
+
const pageInput = ordinaryInput('credential.revocationList', ordinaryServiceAid, '',
|
|
278
|
+
{ issuer_aid: delegateAid, since_event_seq: ordinarySince, cursor: ordinaryCursor, limit: 100 });
|
|
279
|
+
const inputFile = 'ordinary-crl-' + pageInput.request_id + '.json';
|
|
280
|
+
await saveJson(inputFile, pageInput);
|
|
281
|
+
const rawPage = await aun<OrdinaryCrlPage>(['credential', 'revocation-list', '--params', '@' + inputFile]);
|
|
282
|
+
const page = await app.verifyOrdinaryCrl(rawPage, pageInput, ordinaryServiceAid);
|
|
283
|
+
await app.commitOrdinaryCrl(page);
|
|
284
|
+
ordinaryCursor = page.next_cursor;
|
|
285
|
+
} while (ordinaryCursor);
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
普通 CRL 的结束游标为空字符串;语义分页使用 null。记录保存 authority、issuer、事件最大序号、cursor 与完整签名材料,事件与进度同事务提交。
|
|
289
|
+
|
|
290
|
+
#### 4.1.5 续期读取与恢复
|
|
291
|
+
|
|
292
|
+
```ts
|
|
293
|
+
await saveJson('current-input.json', { cid: cap.cid });
|
|
294
|
+
const managed = await aun(['credential', 'current', '--params', '@current-input.json'], 'cn-issuer');
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
根示例省略 exp,SDK 按签署证书截止时间签发并管理。current 在相同 profile 的持久 store 中沿 successor_cid 读取最新记录。恢复使用已保存的原输入与阶段;成员续期见 §9.3,当前状态和业务约束在使用前重新验收。
|
|
298
|
+
|
|
299
|
+
### 4.2 语义原件与确认
|
|
300
|
+
|
|
301
|
+
```mermaid
|
|
302
|
+
sequenceDiagram
|
|
303
|
+
participant A as 签发者 profile
|
|
304
|
+
participant K as 确认者 profile
|
|
305
|
+
participant R as 登记权威
|
|
306
|
+
A->>A: sign:正文与显式上限
|
|
307
|
+
A->>K: 原字节原件与确认依据
|
|
308
|
+
K->>K: metadata-sign:确定主体、受众、期限与次数
|
|
309
|
+
K->>R: register:原件、metadata、lineage_evidence、authority
|
|
310
|
+
R-->>K: audiences、revision、registration_receipt
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
原件与 metadata 字段的 TS 构造见 [SDK 应用指南 §4.2](../sdk/凭证与组织服务SDK应用集成指南.md#42-签发确认与登记e02e05e18):纯语义 cap=[],混合凭证附结构化 cap;有限次数同时提供 UsageContract。
|
|
314
|
+
|
|
315
|
+
```ts
|
|
316
|
+
await saveJson('original-input.json', textGrant);
|
|
317
|
+
const original = await aun<sp.SignedJsonBytes>(['credential', 'sign',
|
|
318
|
+
'--params', '@original-input.json', '--output', 'original.json'], 'cn-issuer');
|
|
319
|
+
await saveJson('metadata-input.json', metadataInput);
|
|
320
|
+
const metadata = await aun<sp.SignedJsonBytes>(['credential', 'metadata-sign',
|
|
321
|
+
'--params', '@metadata-input.json', '--output', 'metadata.json'], 'cn-confirmer');
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
```ts
|
|
325
|
+
const management = (credential_cid: string) => ({
|
|
326
|
+
request_id: randomUUID(), nonce: randomBytes(32).toString('base64url'),
|
|
327
|
+
credential_cid, authority,
|
|
328
|
+
});
|
|
329
|
+
await saveJson('registration.json', { ...management(cid), original,
|
|
330
|
+
metadata: [metadata], lineage_evidence: [] });
|
|
331
|
+
const registered = await aun<sp.SemanticRegisterResult>([
|
|
332
|
+
'credential', 'register', '--params', '@registration.json']);
|
|
333
|
+
await saveJson('registration-result.json', registered);
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
派生凭证的 lineage_evidence 按 root→直接 parent 保存完整材料;签发权与确认权使用各自固定依据。
|
|
337
|
+
|
|
338
|
+
### 4.3 当前修订、状态与业务请求
|
|
339
|
+
|
|
340
|
+
```mermaid
|
|
341
|
+
flowchart LR
|
|
342
|
+
A[get 当前 head 与修订] --> B[status:bounded 初始快照]
|
|
343
|
+
B --> C[package:root 到 leaf]
|
|
344
|
+
C --> D[request:固定业务 hash]
|
|
345
|
+
D --> E[认证通道交付业务方]
|
|
346
|
+
E --> F[验收端刷新 online 状态]
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
```ts
|
|
350
|
+
await saveJson('get-input.json', { ...management(cid), audience: businessAid });
|
|
351
|
+
const current = await aun<sp.SemanticGetResult>(['credential', 'get', '--params', '@get-input.json']);
|
|
352
|
+
if (current.kind !== 'revision' || current.head.state !== 'current') throw new Error('需要当前修订');
|
|
353
|
+
await saveJson('status-input.json', { ...management(cid), audience: businessAid,
|
|
354
|
+
expected_revision: current.revision, policy: { mode: 'bounded', max_staleness_seconds: 60 } });
|
|
355
|
+
const status = await aun<sp.CredentialStatusProof>(['credential', 'status', '--params', '@status-input.json']);
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
```ts
|
|
359
|
+
const lineage: sp.CredentialLineageEntry[] = [{
|
|
360
|
+
credential: sp.decodeSignedJson(current.original) as sp.SemanticCredential,
|
|
361
|
+
metadata: sp.decodeSignedJson(current.metadata) as sp.RegistrationMetadata,
|
|
362
|
+
registration_receipt: current.registration_receipt, status,
|
|
363
|
+
}];
|
|
364
|
+
await saveJson('package-input.json', { lineage });
|
|
365
|
+
const grant = await aun<sp.CredentialPackage>(['credential', 'package', '--params', '@package-input.json']);
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
```ts
|
|
369
|
+
await saveJson('request-input.json', { request_id: randomUUID(),
|
|
370
|
+
nonce: randomBytes(32).toString('base64url'), actor: holderAid, sub: holderAid,
|
|
371
|
+
target: businessAid, aud: businessAid, ns: 'files', action: 'read',
|
|
372
|
+
resource: '/reports', params: { report: reportId },
|
|
373
|
+
expires_at: Math.trunc(Date.now() / 1000) + 300, grant });
|
|
374
|
+
const request = await aun<sp.AuthorizationRequest>(['credential', 'request', '--params', '@request-input.json']);
|
|
375
|
+
await saveJson('business-request.json', request);
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
多跳逐层取材料。旧根使用普通凭证完整验证及原权威强状态;代表出示中 actor 为实际发送者,sub 为叶 holder。
|
|
379
|
+
|
|
380
|
+
## 5. 验真、online 与业务验收
|
|
381
|
+
|
|
382
|
+
### 5.1 CLI context
|
|
383
|
+
|
|
384
|
+
```mermaid
|
|
385
|
+
flowchart TD
|
|
386
|
+
A[真实认证收件与可信配置] --> B[构造 context]
|
|
387
|
+
B --> C[request-verify]
|
|
388
|
+
C --> D[CLI 生成 query nonce 与单调起点]
|
|
389
|
+
D --> E[按各 CID 权威刷新 online status]
|
|
390
|
+
E --> F[验包、请求绑定与显式 cap]
|
|
391
|
+
F --> G[正文验真与 decision-input]
|
|
392
|
+
G --> H[业务三态决策、后置复核、额度与幂等执行]
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
| CLI context 字段 | 来源与键 |
|
|
396
|
+
| --- | --- |
|
|
397
|
+
| `authenticated` | `{actor,service_aid,authentication_ref}`,取真实收件认证结果 |
|
|
398
|
+
| `credential_signers` | 完整原件 `digest(original)` → 原签署者 AID |
|
|
399
|
+
| `credential_services` | CID → 可信登记服务 AID |
|
|
400
|
+
| `certificates` | `signature.cert_fingerprint` → PEM,含各层历史签名者 |
|
|
401
|
+
| `trusted_roots` | 本地信任根 PEM 数组 |
|
|
402
|
+
| `audience`/`authority` | 业务受众及可信状态查询管理依据 |
|
|
403
|
+
| `policy` | online,或 bounded+max_staleness_seconds |
|
|
404
|
+
|
|
405
|
+
以下为单层 context;多跳补齐全部签名者与服务映射:
|
|
406
|
+
|
|
407
|
+
```ts
|
|
408
|
+
const cliContext = { authenticated: authentication, audience: businessAid,
|
|
409
|
+
credential_signers: { [sp.digest(sp.decodeSignedJson(original))]: issuerAid },
|
|
410
|
+
credential_services: { [cid]: 'credential.agentid.cn' },
|
|
411
|
+
certificates, trusted_roots: trustedRoots, authority, policy: { mode: 'online' } };
|
|
412
|
+
await saveJson('verification-context.json', cliContext);
|
|
413
|
+
const requestReport = await aun(['credential', 'request-verify',
|
|
414
|
+
'--params', '@business-request.json', '--context', '@verification-context.json']);
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
online 的 query 与单调时间由当前 CLI 进程生成,状态绑定同一业务 request_hash。状态刷新保留同修订的业务 hash;绝对窗口及最大已观察 state_seq 仍需校验。bounded 使用 1—300 秒 TTL,跨进程恢复后重新取状态。
|
|
418
|
+
|
|
419
|
+
```ts
|
|
420
|
+
await saveJson('body-input.json', { credential: original, context: cliMessageContext });
|
|
421
|
+
const body = await aun<sp.VerifiedBody>(['credential', 'evidence-verify', '--params', '@body-input.json']);
|
|
422
|
+
const { credential_hash, body_hash, text, evidence_hashes, payload_hash } = body;
|
|
423
|
+
await saveJson('decision-input.json', { request,
|
|
424
|
+
bodies: [{ credential_hash, body_hash, text, evidence_hashes, payload_hash }], facts, policy });
|
|
425
|
+
const decisionInput = await aun<sp.DecisionInput>(['credential', 'decision-input',
|
|
426
|
+
'--params', '@decision-input.json', '--context', '@verification-context.json']);
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
多跳收集全部适用正文。cliMessageContext 为 Python CLI 的 JSON 上下文;message_ref 使用原收件 profile 及 SDK 已持久化的解密材料。远程证据 resolver 等应用回调通过 SDK 接入。
|
|
430
|
+
|
|
431
|
+
### 5.2 TS 开发时的完整调用顺序
|
|
432
|
+
|
|
433
|
+
```mermaid
|
|
434
|
+
flowchart LR
|
|
435
|
+
A[verifyPackage] --> B[verifyRequest]
|
|
436
|
+
B --> C[逐层 verifyMessageBody]
|
|
437
|
+
C --> D[buildDecisionInput]
|
|
438
|
+
D --> E[模型 allow/deny/indeterminate]
|
|
439
|
+
E -->|allow| F[后置复核与新鲜状态]
|
|
440
|
+
F --> G[事务预留、幂等执行、持久结果]
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
直接 SDK 路径在本进程刷新状态,并保留查询计时;packageContext.serviceFor 提供每层可信权威:
|
|
444
|
+
|
|
445
|
+
```ts
|
|
446
|
+
const sdkRequest = structuredClone(request);
|
|
447
|
+
const query = { request_hash: sdkRequest.request_binding.request_hash,
|
|
448
|
+
nonce: randomBytes(32).toString('base64url') };
|
|
449
|
+
const queryStarted = performance.now();
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
```ts
|
|
453
|
+
for (const entry of sdkRequest.grant.lineage) {
|
|
454
|
+
if (!('metadata' in entry)) continue;
|
|
455
|
+
const expectedRevision = { cid: entry.credential.cid, original_hash: entry.metadata.original_hash,
|
|
456
|
+
metadata_hash: sp.digest(entry.metadata), metadata_version: entry.metadata.version };
|
|
457
|
+
entry.status = await client.credential.status({ ...management(entry.credential.cid),
|
|
458
|
+
audience: sdkRequest.aud, expected_revision: expectedRevision, policy: { mode: 'online' }, query,
|
|
459
|
+
}, { serviceAid: await packageContext.serviceFor!(entry.credential.cid), verificationContext: trust });
|
|
460
|
+
}
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
```ts
|
|
464
|
+
await client.credential.verifyPackage(sdkRequest.grant, { ...packageContext,
|
|
465
|
+
statePolicy: { mode: 'online' }, elapsedSeconds: (performance.now() - queryStarted) / 1000,
|
|
466
|
+
queries: Object.fromEntries(sdkRequest.grant.lineage.map(entry => [entry.credential.cid, query])) });
|
|
467
|
+
await client.credential.verifyRequest(sdkRequest, authentication, {
|
|
468
|
+
representedActor: app.verifyRepresentation,
|
|
469
|
+
});
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
```ts
|
|
473
|
+
const bodies: sp.VerifiedBody[] = [];
|
|
474
|
+
for (const entry of sdkRequest.grant.lineage) {
|
|
475
|
+
if ('metadata' in entry) bodies.push(await client.credential.verifyMessageBody(
|
|
476
|
+
entry.credential, await app.messageContext(entry)));
|
|
477
|
+
}
|
|
478
|
+
const input = await client.credential.buildDecisionInput(sdkRequest, bodies, facts, policy);
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
TS verifyRequest 返回的 required 仍含包验真与业务接受职责;Python CLI request-verify 已组合包验真,decision-input 还会重新验请求及正文。应用完成签发/确认权、结构化范围、可信事实、模型三态、后置条件和额度账本检查,见 [SDK 应用指南 §4.6—§4.8](../sdk/凭证与组织服务SDK应用集成指南.md#46-业务验收与模型三态e16e18e23e25e34)。
|
|
482
|
+
|
|
483
|
+
## 6. 消息证据与分配证明
|
|
484
|
+
|
|
485
|
+
```mermaid
|
|
486
|
+
flowchart LR
|
|
487
|
+
A[认证收件的原始 envelope 与 received] --> B[SDK archiveMessage 保存原字节]
|
|
488
|
+
B --> C[evidence-export 生成 inline/aun_ref]
|
|
489
|
+
C --> D[签署引用该证据的凭证]
|
|
490
|
+
D --> E[evidence-verify 取得 VerifiedBody]
|
|
491
|
+
E --> F[全部适用正文进入 DecisionInput]
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
```ts
|
|
495
|
+
const archive = await client.credential.archiveMessage(rawEnvelope, received);
|
|
496
|
+
await writeFile('envelope.bin', archive.envelope_bytes, { flag: 'wx' });
|
|
497
|
+
await app.archive.put(archiveLocator, archive.envelope_bytes);
|
|
498
|
+
await saveJson('evidence-input.json', { bytes_base64: (await readFile('envelope.bin')).toString('base64'),
|
|
499
|
+
profile: 'aun-e2ee-v2-envelope-raw/1', locator: archiveLocator });
|
|
500
|
+
const evidence = await aun<sp.EvidenceRef>(['credential', 'evidence-export', '--params', '@evidence-input.json']);
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
locator 指向已保存的对象版本与 ACL;省略 locator 生成 inline。evidence-verify 输入凭证或 `{credential,context}`,输出正文验真结果。P2P、群收件集合/Merkle 证明、上下文及附件材料见 [SDK 消息流程](../sdk/凭证与组织服务SDK应用集成指南.md#43-消息正文与证据e06e11e15e32)。
|
|
504
|
+
|
|
505
|
+
```ts
|
|
506
|
+
await saveJson('allocation-input.json', unsignedAllocation);
|
|
507
|
+
const signedAllocation = await aun<sp.SignedJsonBytes>(['credential', 'allocation-sign',
|
|
508
|
+
'--params', '@allocation-input.json'], 'cn-issuer');
|
|
509
|
+
const allocation = sp.decodeSignedJson(signedAllocation) as sp.UsageAllocation;
|
|
510
|
+
await client.credential.verifyAllocation(allocation, allocationContext);
|
|
511
|
+
await client.credential.verifyAllocationStatus(allocationProof, allocationStatusContext);
|
|
512
|
+
if (allocationProof.state === 'active') await app.reserveAllocatedUsage(request);
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
跨权威预留同时要求分配关系成立、在线查询绑定有效且 allocation 为 active;draining 结清在途,closed 返还容量。具体账本事务见 [SDK 额度流程](../sdk/凭证与组织服务SDK应用集成指南.md#48-额度分配与执行结果e27e30)。
|
|
516
|
+
|
|
517
|
+
## 7. 修订、撤销与 UsageRef 续跑
|
|
518
|
+
|
|
519
|
+
```mermaid
|
|
520
|
+
flowchart TD
|
|
521
|
+
A[get 当前 head/transition] --> B{操作}
|
|
522
|
+
B -->|metadata| C[revise:逐受众 CAS]
|
|
523
|
+
B -->|整个 CID| D[revoke]
|
|
524
|
+
B -->|UsageRef| E[usage-prepare:固定 candidate 与 fence]
|
|
525
|
+
E --> F[账本冻结、结清 Unknown 与分配、签 checkpoint/acceptance]
|
|
526
|
+
F --> G{提交或取消}
|
|
527
|
+
G -->|提交| H[usage-commit]
|
|
528
|
+
G -->|取消| I[usage-abort,收集 ledger-abort]
|
|
529
|
+
C --> J[保存回执和进度]
|
|
530
|
+
D --> J
|
|
531
|
+
H --> J
|
|
532
|
+
I --> J
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
revisionInput/prepareInput/commitInput/abortInput 在调用前保存;字段构造见 [SDK 修订及协调示例](../sdk/凭证与组织服务SDK应用集成指南.md#47-受众修订历史读取与撤销e17e18e21e22)。
|
|
536
|
+
|
|
537
|
+
```ts
|
|
538
|
+
await saveJson('revision-input.json', revisionInput);
|
|
539
|
+
const revised = await aun(['credential', 'revise', '--params', '@revision-input.json']);
|
|
540
|
+
await saveJson('revoke-input.json', { ...management(cid), reason_code: 'grant_withdrawn' });
|
|
541
|
+
const revoked = await aun(['credential', 'revoke', '--params', '@revoke-input.json']);
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
| 受众变更 | change 中的材料 |
|
|
545
|
+
| --- | --- |
|
|
546
|
+
| 替换/批量替换 | expected+metadata |
|
|
547
|
+
| 新增 | expected_absent+metadata |
|
|
548
|
+
| 撤下 | expected+withdraw |
|
|
549
|
+
| 重加 | expected_withdrawn 的 last_revision/state_seq+metadata |
|
|
550
|
+
|
|
551
|
+
```ts
|
|
552
|
+
await saveJson('usage-prepare-input.json', prepareInput);
|
|
553
|
+
const prepared = await aun(['credential', 'usage-prepare', '--params', '@usage-prepare-input.json']);
|
|
554
|
+
await saveJson('usage-transition.json', prepared);
|
|
555
|
+
await saveJson('usage-commit-input.json', commitInput);
|
|
556
|
+
const committed = await aun(['credential', 'usage-commit', '--params', '@usage-commit-input.json']);
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
取消分支单独调用;保留 prepared 的同一 transition_id/fence/from_usage:
|
|
560
|
+
|
|
561
|
+
```ts
|
|
562
|
+
await saveJson('usage-abort-input.json', abortInput);
|
|
563
|
+
const aborted = await aun(['credential', 'usage-abort', '--params', '@usage-abort-input.json']);
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
账本配套对象由对应权威 profile 签署:
|
|
567
|
+
|
|
568
|
+
```ts
|
|
569
|
+
await saveJson('checkpoint-input.json', checkpointInput);
|
|
570
|
+
const checkpoint = await aun(['credential', 'usage-record-sign', '--kind', 'usage-checkpoint',
|
|
571
|
+
'--params', '@checkpoint-input.json'], 'cn-issuer');
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
```ts
|
|
575
|
+
await saveJson('crl-input.json', { ...management(''), scope: { audiences: [businessAid] },
|
|
576
|
+
after_event_seq: afterEventSeq, cursor: savedCursor, limit: 100 });
|
|
577
|
+
const page = await aun<sp.SemanticRevocationPage>(['credential', 'revocations', '--params', '@crl-input.json']);
|
|
578
|
+
await saveJson('crl-page.json', page);
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
CRL 按 authority+scope 保存进度,续页使用 next_cursor;next_cursor=null 才推进 upper_event_seq。丢响应后用原 transition_id 查询 get,按 prepared/committed/aborted 恢复;Unknown 保留预留并查询原执行器。
|
|
582
|
+
|
|
583
|
+
跨域管理显式指定语义权威;包验真通过 credential_services 逐 CID 选择服务:
|
|
584
|
+
|
|
585
|
+
```ts
|
|
586
|
+
const remote = await aun(['credential', '--target', 'credential.aid.com',
|
|
587
|
+
'get', '--params', '@remote-get-input.json']);
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
remote-get-input 的 authority 使用该域的可信管理依据。普通列表使用 `credential revocation-list`,输入字段见 [普通 RPC](../sdk/09-凭证服务RPC手册.md#credentialrevocationlist)。
|
|
591
|
+
|
|
592
|
+
## 8. 组织命令地图与创建
|
|
593
|
+
|
|
594
|
+
| 场景 | CLI 命令 |
|
|
595
|
+
| --- | --- |
|
|
596
|
+
| 诊断 | `org health`、`org status` |
|
|
597
|
+
| 生命周期 | `org create`、`list`、`info`、`update`、`suspend`、`resume`、`dissolve` |
|
|
598
|
+
| 所有权 | `org transfer`、`transfer-accept` |
|
|
599
|
+
| 申请/邀请 | `org join`、`join-approve`、`join-reject`、`invite`、`invite-accept`、`invite-reject` |
|
|
600
|
+
| 成员与收尾 | `org members`、`member`、`leave`、`kick`、`freeze`、`unfreeze`、`ban`、`unban`、`offboard-status`、`offboard-confirm`、`offboard-cancel` |
|
|
601
|
+
| 成员凭证 | `org credential info`、`renew`、`revocation-list` |
|
|
602
|
+
| 审计 | `org audit query` |
|
|
603
|
+
| 预留,返回 NOT_IMPLEMENTED | `org join-requests`/`invites`/`role`/`roles`;`org credential list`/`held`/`surrender`/`delegate`/`pending` |
|
|
604
|
+
|
|
605
|
+
```mermaid
|
|
606
|
+
flowchart LR
|
|
607
|
+
A[owner profile 与持久 AIDStore] --> B[org create:保存实体身份]
|
|
608
|
+
B --> C[SDK 准备 owner binding/CAP/登记授权]
|
|
609
|
+
C --> D[Org 验回执并创建组织]
|
|
610
|
+
D --> E[实体主签、owner token 上传名片]
|
|
611
|
+
E --> F[info/list 查询生命周期]
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
```ts
|
|
615
|
+
const orgAid = 'team.agentid.cn';
|
|
616
|
+
const orgServiceAid = 'org.agentid.cn';
|
|
617
|
+
const creationInput = { org_id: orgAid, name: '协作组织', request_id: randomUUID(),
|
|
618
|
+
nonce: randomBytes(32).toString('base64url') };
|
|
619
|
+
await saveJson('org-create-input.json', creationInput);
|
|
620
|
+
const created = await aun(['org', '--params', '@org-create-input.json', 'create',
|
|
621
|
+
'--name', creationInput.name, '--org-id', orgAid], 'cn-owner');
|
|
622
|
+
await saveJson('org-created.json', created);
|
|
623
|
+
const info = await aun(['org', 'info', orgAid], 'cn-owner');
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
对应 TS 高层入口:
|
|
627
|
+
|
|
628
|
+
```ts
|
|
629
|
+
const sdkCreated = await ownerClient.createOrg({ org_id: orgAid, name: '协作组织' },
|
|
630
|
+
{ aidStore: ownerStore });
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
org.update 的 patch/expected_version、暂停/恢复等授权材料可通过组级 `--params` 传入。health/status 用于诊断,成员资格使用签名成员状态。
|
|
634
|
+
|
|
635
|
+
## 9. 入组、邀请与成员凭证
|
|
636
|
+
|
|
637
|
+
### 9.1 申请与审批
|
|
638
|
+
|
|
639
|
+
```mermaid
|
|
640
|
+
sequenceDiagram
|
|
641
|
+
participant M as 成员 profile
|
|
642
|
+
participant O as owner/审批者 profile
|
|
643
|
+
participant G as Org 服务
|
|
644
|
+
M->>G: join:成员签 binding
|
|
645
|
+
G-->>M: join_request_id、application
|
|
646
|
+
M->>O: 完整 application 与条款
|
|
647
|
+
O->>G: join-approve --application:原 binding/terms+当前审批资格
|
|
648
|
+
G->>G: 登记 CAP、验回执、最终化成员
|
|
649
|
+
G-->>M: active 与完整成员包
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
```ts
|
|
653
|
+
await saveJson('terms.json', terms);
|
|
654
|
+
const joined = await aun<{ join_request_id: string; application: unknown }>(['org', 'join',
|
|
655
|
+
orgAid, '--member-type', 'human', '--terms', '@terms.json'], 'cn-member');
|
|
656
|
+
await saveJson('application.json', joined.application);
|
|
657
|
+
await saveJson('owner-auth.json', { credentials: ownerCredentials });
|
|
658
|
+
const approved = await aun(['org', '--params', '@owner-auth.json', 'join-approve', orgAid,
|
|
659
|
+
joined.join_request_id, '--application', '@application.json'], 'cn-owner');
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
审批者 signer 签 binding 的组织侧;本地组织实体 signer 签 CAP 和登记授权。CLI 自动取实体私钥时需相应 profile 的持久 AIDStore。
|
|
663
|
+
|
|
664
|
+
```ts
|
|
665
|
+
const binding = ownerClient.org.member.signBinding(applicationBinding, ownerSigner, 'org');
|
|
666
|
+
const approval = ownerClient.org.prepareRequest('org.member.approveJoin', {
|
|
667
|
+
org_id: orgAid, join_request_id: joinRequestId, terms,
|
|
668
|
+
membership_binding: binding, credentials: ownerCredentials,
|
|
669
|
+
}, orgServiceAid, ownerSigner, { orgSigner });
|
|
670
|
+
await ownerClient.org.member.approveJoin(approval);
|
|
671
|
+
```
|
|
672
|
+
|
|
673
|
+
### 9.2 邀请、接受与拒绝
|
|
674
|
+
|
|
675
|
+
```mermaid
|
|
676
|
+
flowchart TD
|
|
677
|
+
A[owner invite:每个目标独立材料] --> B[保存 invites 中本目标条目及原 terms]
|
|
678
|
+
B --> C{目标成员选择}
|
|
679
|
+
C -->|接受| D[invite-accept --invitation:原 binding/CAP/登记授权]
|
|
680
|
+
D --> E[成员补签,登记并最终化]
|
|
681
|
+
C -->|拒绝| F[invite-reject --invitation:原组织签名 binding]
|
|
682
|
+
F --> G[独立操作 ID/nonce 签拒绝请求]
|
|
683
|
+
```
|
|
684
|
+
|
|
685
|
+
```ts
|
|
686
|
+
const invitations = await aun<{ invites: sp.JsonObject[] }>(['org', '--params', '@owner-auth.json',
|
|
687
|
+
'invite', orgAid, '--targets', holderAid, '--terms', '@terms.json'], 'cn-owner');
|
|
688
|
+
const invitation = invitations.invites.find(item => item.target_aid === holderAid)!;
|
|
689
|
+
await saveJson('invitation.json', invitation);
|
|
690
|
+
const accepted = await aun(['org', 'invite-accept', orgAid, String(invitation.invite_id),
|
|
691
|
+
'--invitation', '@invitation.json'], 'cn-member');
|
|
692
|
+
```
|
|
693
|
+
|
|
694
|
+
拒绝是另一条分支,使用对应原邀请:
|
|
695
|
+
|
|
696
|
+
```ts
|
|
697
|
+
const rejected = await aun(['org', 'invite-reject', orgAid, rejectedInviteId,
|
|
698
|
+
'--invitation', '@rejected-invitation.json', '--reason', '暂不加入'], 'cn-member');
|
|
699
|
+
```
|
|
700
|
+
|
|
701
|
+
邀请返回条目包含 membership_binding/credential_template/registration_authorization,条款原文由发起方保留。CLI 从 `--invitation` 读取已取得的原条目;首次 admission 固定 membership_id,由目标成员签名。代表操作使用 `--for` 与真实 representation proof,SDK 验当前代表依据。
|
|
702
|
+
|
|
703
|
+
### 9.3 受保护读取、续期与收尾
|
|
704
|
+
|
|
705
|
+
```mermaid
|
|
706
|
+
flowchart LR
|
|
707
|
+
A[当前 credentials:binding 与 member/approval CAP] --> B[准备受保护读取/成员操作]
|
|
708
|
+
B --> C[member/members/credential info/revocation-list]
|
|
709
|
+
B --> D[renew:同关系、新 binding/CAP/登记授权、旧 CID+版本 CAS]
|
|
710
|
+
D --> E[保存完整新包,current 读取本地最新记录]
|
|
711
|
+
B --> F[leave/kick,进入 offboarding]
|
|
712
|
+
F --> G[offboard-confirm,ended 与有权 CAP 撤销]
|
|
713
|
+
```
|
|
714
|
+
|
|
715
|
+
```ts
|
|
716
|
+
await saveJson('member-auth.json', { credentials: memberCredentials });
|
|
717
|
+
const member = await aun(['org', '--params', '@member-auth.json', 'member', orgAid, holderAid], 'cn-member');
|
|
718
|
+
const orgCrl = await aun(['org', '--params', '@member-auth.json', 'credential',
|
|
719
|
+
'revocation-list', orgAid, '--since-event-seq', String(orgAfterEventSeq), '--limit', '100'], 'cn-member');
|
|
720
|
+
```
|
|
721
|
+
|
|
722
|
+
renewalMaterial 保留同一 membership_id,含双签 replacement binding、terms、新 CAP/登记授权及当前调用资格:
|
|
723
|
+
|
|
724
|
+
```ts
|
|
725
|
+
await saveJson('renewal.json', renewalMaterial);
|
|
726
|
+
const renewed = await aun(['org', '--params', '@renewal.json', 'credential', 'renew',
|
|
727
|
+
oldCid, '--org-id', orgAid, '--expected-version', String(memberVersion)], 'cn-member');
|
|
728
|
+
await saveJson('renewal-result.json', renewed);
|
|
729
|
+
```
|
|
730
|
+
|
|
731
|
+
freeze/unfreeze、ban/unban 与 kick 通过当前授权材料调用,并按 expected_version 处理冲突。签名 membership_status 决定当前成员状态;离职流程按 operation_id 和阶段结果续跑。
|
|
732
|
+
|
|
733
|
+
## 10. 转让、换钥与解散
|
|
734
|
+
|
|
735
|
+
```mermaid
|
|
736
|
+
sequenceDiagram
|
|
737
|
+
participant O as 原 owner profile
|
|
738
|
+
participant N as 目标 owner profile
|
|
739
|
+
participant G as Org/CA
|
|
740
|
+
O->>G: transfer:目标成员与期限
|
|
741
|
+
G-->>O: transfer_id、原签名 proposal
|
|
742
|
+
O->>N: proposal 与双方替换材料
|
|
743
|
+
N->>N: SDK 验提案、保存新实体私钥与 checkpoint
|
|
744
|
+
N->>G: transfer-accept --proposal:rekey
|
|
745
|
+
G-->>N: pending_finalization 与新证书
|
|
746
|
+
N->>G: SDK 重签双方材料,finalize
|
|
747
|
+
G-->>N: 新 owner 与完整成员包
|
|
748
|
+
N->>N: 保存身份,上传新名片
|
|
749
|
+
```
|
|
750
|
+
|
|
751
|
+
```ts
|
|
752
|
+
const transferInput = { org_id: orgAid, target_member_aid: targetOwnerAid,
|
|
753
|
+
expires_at: Math.trunc(Date.now() / 1000) + 300, credentials: ownerCredentials,
|
|
754
|
+
request_id: randomUUID(), nonce: randomBytes(32).toString('base64url') };
|
|
755
|
+
await saveJson('transfer-input.json', transferInput);
|
|
756
|
+
const transfer = await aun<{ transfer_id: string; proposal: unknown }>(['org',
|
|
757
|
+
'--params', '@transfer-input.json', 'transfer', orgAid, targetOwnerAid,
|
|
758
|
+
'--expires-at', String(transferInput.expires_at)], 'cn-owner');
|
|
759
|
+
```
|
|
760
|
+
|
|
761
|
+
```ts
|
|
762
|
+
await saveJson('proposal.json', transfer.proposal);
|
|
763
|
+
await saveJson('transfer-material.json', transferMaterial);
|
|
764
|
+
const transferred = await aun(['org', '--params', '@transfer-material.json', 'transfer-accept',
|
|
765
|
+
orgAid, transfer.transfer_id, '--proposal', '@proposal.json'], 'cn-target');
|
|
766
|
+
```
|
|
767
|
+
|
|
768
|
+
`--proposal` 进入 SDK 完整 rekey→finalize 编排,自动生成并持久保存新实体密钥。transferMaterial 保存双方原关系及替换 binding/CAP/登记授权和当前资格。恢复沿用原 transfer、接受签名、阶段请求与私钥。
|
|
769
|
+
|
|
770
|
+
```ts
|
|
771
|
+
const acceptance = targetClient.org.lifecycle.signTransferAcceptance(proposal, targetSigner);
|
|
772
|
+
const sdkTransferred = await targetClient.completeOrgTransfer({ ...transferMaterial, proposal,
|
|
773
|
+
org_id: orgAid, transfer_id: transfer.transfer_id, ...acceptance }, { aidStore: targetStore });
|
|
774
|
+
```
|
|
775
|
+
|
|
776
|
+
```mermaid
|
|
777
|
+
flowchart LR
|
|
778
|
+
A[当前 owner 资格] --> B[dissolve]
|
|
779
|
+
B --> C{返回阶段}
|
|
780
|
+
C -->|dissolving| D[保存 operation_id,续查进度]
|
|
781
|
+
C -->|dissolved| E[SDK 失效本地实体身份并清恢复状态]
|
|
782
|
+
E --> F[保留归档与磁盘私钥]
|
|
783
|
+
```
|
|
784
|
+
|
|
785
|
+
解散使用当前 owner 的最新成员包;以下承接转让后的 cn-target,newOwnerCredentials 取已验真的新 owner 成员材料:
|
|
786
|
+
|
|
787
|
+
```ts
|
|
788
|
+
await saveJson('new-owner-auth.json', { credentials: newOwnerCredentials });
|
|
789
|
+
const dissolved = await aun(['org', '--params', '@new-owner-auth.json', 'dissolve', orgAid], 'cn-target');
|
|
790
|
+
```
|
|
791
|
+
|
|
792
|
+
直接 TS SDK 入口:
|
|
793
|
+
|
|
794
|
+
```ts
|
|
795
|
+
const sdkDissolved = await targetClient.dissolveOrg({ org_id: orgAid, credentials: newOwnerCredentials },
|
|
796
|
+
{ aidStore: targetStore });
|
|
797
|
+
```
|
|
798
|
+
|
|
799
|
+
## 11. CLI 开发、错误与验证
|
|
800
|
+
|
|
801
|
+
### 11.1 胶水层职责
|
|
802
|
+
|
|
803
|
+
```mermaid
|
|
804
|
+
flowchart LR
|
|
805
|
+
A[Typer 命令与参数] --> B[严格 JSON/UTF-8 文件]
|
|
806
|
+
B --> C[CLISession 加载 profile 与身份]
|
|
807
|
+
C --> D[SDK facade/高层编排]
|
|
808
|
+
D --> E[原样 JSON、原字节文件、退出码]
|
|
809
|
+
```
|
|
810
|
+
|
|
811
|
+
| 代码位置 | 维护内容 |
|
|
812
|
+
| --- | --- |
|
|
813
|
+
| [main.py](../../python/src/aun_cli/main.py) | credential/org 命令注册、全局 profile/JSON/超时 |
|
|
814
|
+
| [credential.py](../../python/src/aun_cli/commands/credential.py) | 参数映射、profile signer、语义 target、online 查询生命周期 |
|
|
815
|
+
| [org.py](../../python/src/aun_cli/commands/org.py) | 原申请/邀请材料衔接、受保护读取准备、组织命令映射 |
|
|
816
|
+
| [adapter.py](../../python/src/aun_cli/adapter.py)/[output.py](../../python/src/aun_cli/output.py) | 会话、配置、stdout/stderr 与错误退出 |
|
|
817
|
+
| [org_facades.py](../../python/src/aun_core/org_facades.py)/[semantic_facades.py](../../python/src/aun_core/semantic_facades.py) | SDK 的普通/语义分流、签名验真、组织编排与持久状态 |
|
|
818
|
+
| [TS facades](../../ts/src/facades.ts)/[semantic-facade.ts](../../ts/src/semantic-facade.ts) | TS 对照;位置参数、回调及异步约定 |
|
|
819
|
+
|
|
820
|
+
| CLI JSON/材料 | TS SDK 对应形式 |
|
|
821
|
+
| --- | --- |
|
|
822
|
+
| verify structured 的实际请求 context | `credential.verify(cap,context)`;查询/信任校验先 await,可信 resolver 同步返回已验材料 |
|
|
823
|
+
| package `{lineage}` | `buildPackage(lineage)` |
|
|
824
|
+
| request 完整业务字段 | `buildRequest(input)`,显式 ID/nonce/expires_at |
|
|
825
|
+
| request-verify 的 context.authenticated | `verifyRequest(request, authentication, options)`,另做包验真及业务检查 |
|
|
826
|
+
| decision-input `{request,bodies,facts,policy}` | `buildDecisionInput(request,bodies,facts,policy)`,先验真正文 |
|
|
827
|
+
| evidence-export `{bytes_base64,profile,locator?}` | `createEvidenceRef(bytes,profile,locator?)` |
|
|
828
|
+
| credential_signers/credential_services 映射 | packageContext.originalSigner/serviceFor 回调 |
|
|
829
|
+
| org 原业务材料+credentials | `prepareRequest(method,params,target,signer,options)`,再调用 facade |
|
|
830
|
+
|
|
831
|
+
### 11.2 错误与断点续跑
|
|
832
|
+
|
|
833
|
+
| 退出码 | 含义 |
|
|
834
|
+
| --- | --- |
|
|
835
|
+
| 0 | 成功 |
|
|
836
|
+
| 1 | 通用业务错误 |
|
|
837
|
+
| 2 | 参数/格式/绑定 |
|
|
838
|
+
| 3 | 认证/签名/身份 |
|
|
839
|
+
| 4/5 | 连接/超时 |
|
|
840
|
+
| 6/7 | 权限/不存在 |
|
|
841
|
+
|
|
842
|
+
```ts
|
|
843
|
+
try {
|
|
844
|
+
await aun(['credential', 'register', '--params', '@registration.json']);
|
|
845
|
+
} catch (error) {
|
|
846
|
+
const failure = error as Error & { code: number; stderr: string };
|
|
847
|
+
if (!failure.stderr?.trim()) throw error;
|
|
848
|
+
const line = failure.stderr.trim().split(/\r?\n/).at(-1)!;
|
|
849
|
+
const detail = JSON.parse(line) as { message: string; error_code?: string; retryable?: boolean };
|
|
850
|
+
console.error(failure.code, detail.error_code, detail.message, detail.retryable);
|
|
851
|
+
}
|
|
852
|
+
```
|
|
853
|
+
|
|
854
|
+
错误 JSON 保留 code、rpc_code、data、error_code 与 retryable。恢复使用保存的原输入;CAS 冲突先取当前 head,转让/UsageRef 先查原阶段,业务 Unknown 查询原执行结果。证书、签名与权限问题按具体错误修正材料。
|
|
855
|
+
|
|
856
|
+
### 11.3 用例与 E2E 对照
|
|
857
|
+
|
|
858
|
+
| 场景 | 本指南入口 | 进一步覆盖 |
|
|
859
|
+
| --- | --- | --- |
|
|
860
|
+
| E01 普通兼容 | §4.1 create/register/status/verify structured/revoke/revocation-list/current | 约束、委托收窄、请求绑定、强状态、回执与恢复 |
|
|
861
|
+
| E02—E05、E18 签发/补确认 | §4.2 sign/metadata-sign/register | 确认权、UsageContract、补材料 |
|
|
862
|
+
| E06—E11、E15、E32 消息证据 | §6 evidence-export/evidence-verify | 原收件、群证明、附件、归档 resolver |
|
|
863
|
+
| E12—E16、E19—E26 出示与验收 | §4.3—§5 package/request/request-verify/decision-input | 多跳、代表、三态、状态与重传 |
|
|
864
|
+
| E17、E21—E22 修订/撤销 | §7 revise/revoke/revocations | 多受众 CAS、历史版本、CRL 单调性 |
|
|
865
|
+
| E27—E31、E33 额度/恢复 | §6—§7 allocation/usage-* | 账本事务、Unknown、切换及冷恢复 |
|
|
866
|
+
| E34—E36 历史证书/双域/公开入口 | §5—§7 context/target | 跨域权威、历史信任、四 SDK 与浏览器 |
|
|
867
|
+
| 组织业务 | §8—§10 | 创建、双签入组、邀请拒绝、受保护读取、续期、收尾、转让与解散 |
|
|
868
|
+
|
|
869
|
+
CLI 本地用例:[test_cli_credential.py](../../python/tests/unit/test_cli_credential.py)、[test_cli_org.py](../../python/tests/unit/test_cli_org.py)。场景定义与真实运行入口:[scenarios.json](../../examples/semantic-credential/scenarios.json)、[CLI 场景运行器](../../examples/semantic-credential/cli/scenario.py)、[cross-SDK E2E runner](../../tests/cross-sdk/runner/run_cross_sdk_e2e.py)。实际环境证据范围见 [示例使用指南 §5](../../examples/semantic-credential/示例使用指南.md#5-本轮验证记录与边界)。
|