@m1a0rz/agent-identity 0.3.1 → 0.3.2

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 (47) hide show
  1. package/README-cn.md +19 -9
  2. package/README.md +22 -12
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +18 -17
  5. package/dist/src/actions/identity-actions.d.ts +7 -1
  6. package/dist/src/actions/identity-actions.d.ts.map +1 -1
  7. package/dist/src/actions/identity-actions.js +82 -34
  8. package/dist/src/commands/identity-commands.d.ts.map +1 -1
  9. package/dist/src/commands/identity-commands.js +9 -4
  10. package/dist/src/hooks/after-tool-call.d.ts +12 -0
  11. package/dist/src/hooks/after-tool-call.d.ts.map +1 -0
  12. package/dist/src/hooks/after-tool-call.js +31 -0
  13. package/dist/src/hooks/before-agent-start.d.ts +3 -3
  14. package/dist/src/hooks/before-agent-start.d.ts.map +1 -1
  15. package/dist/src/hooks/before-agent-start.js +6 -20
  16. package/dist/src/hooks/before-tool-call.d.ts +19 -14
  17. package/dist/src/hooks/before-tool-call.d.ts.map +1 -1
  18. package/dist/src/hooks/before-tool-call.js +192 -130
  19. package/dist/src/hooks/subagent-ended-cleanup.js +1 -1
  20. package/dist/src/risk/low-risk-tools.d.ts.map +1 -1
  21. package/dist/src/risk/low-risk-tools.js +0 -2
  22. package/dist/src/services/tip-acquisition.d.ts +0 -1
  23. package/dist/src/services/tip-acquisition.d.ts.map +1 -1
  24. package/dist/src/services/tip-acquisition.js +2 -2
  25. package/dist/src/services/tip-propagation.d.ts.map +1 -1
  26. package/dist/src/services/tip-propagation.js +1 -2
  27. package/dist/src/services/tip-with-refresh.d.ts +1 -1
  28. package/dist/src/services/tip-with-refresh.d.ts.map +1 -1
  29. package/dist/src/services/tip-with-refresh.js +3 -5
  30. package/dist/src/store/credential-env-snapshot.d.ts +38 -0
  31. package/dist/src/store/credential-env-snapshot.d.ts.map +1 -0
  32. package/dist/src/store/credential-env-snapshot.js +101 -0
  33. package/dist/src/store/encryption.d.ts +30 -0
  34. package/dist/src/store/encryption.d.ts.map +1 -0
  35. package/dist/src/store/encryption.js +147 -0
  36. package/dist/src/store/session-store.d.ts.map +1 -1
  37. package/dist/src/store/session-store.js +91 -8
  38. package/dist/src/store/tip-store.d.ts +11 -6
  39. package/dist/src/store/tip-store.d.ts.map +1 -1
  40. package/dist/src/store/tip-store.js +23 -54
  41. package/dist/src/tools/identity-fetch.d.ts.map +1 -1
  42. package/dist/src/tools/identity-fetch.js +1 -0
  43. package/dist/src/tools/identity-list-credentials.d.ts +2 -0
  44. package/dist/src/tools/identity-list-credentials.d.ts.map +1 -1
  45. package/dist/src/tools/identity-list-credentials.js +6 -3
  46. package/package.json +1 -1
  47. package/skills/SKILL.md +75 -150
package/README-cn.md CHANGED
@@ -11,7 +11,9 @@ UserPool OIDC 登录、TIP (Trusted Identity Provider) 令牌(通过 Identity
11
11
  - **OIDC 登录**:`/identity login` 返回 IdP 授权 URL。用户打开 URL 后,IdP 重定向到 `/identity/oauth/callback`。
12
12
  - **TIP 令牌**:当会话中有已登录用户时,`before_agent_start` 钩子会获取 TIP 令牌。
13
13
  - **凭据 3LO**:`/identity fetch <provider>` 返回授权 URL。IdP 重定向到 Identity 提供的回调地址(控制台配置)。
14
- - **凭据绑定**:`/identity set <provider> <envVar>` 将存储的凭据绑定到环境变量。工具运行时在 `before_agent_start` 中注入到 `process.env`。
14
+ - **凭据绑定**:`/identity set <provider> <envVar>` 将存储的凭据绑定到环境变量。凭据按工具调用粒度安全注入,并发多用户会话之间互相隔离。
15
+ - **加密会话存储**:`sessions.json` 使用 AES-256-GCM 加密存储在磁盘上。旧版明文文件首次加载时自动迁移。
16
+ - **内存 TIP 缓存**:TIP 令牌仅存储在内存中(不持久化到磁盘)。TIP 是短效令牌,可随时从用户 session token 重新获取。
15
17
  - **动态 UserPool**:通过 `userPoolName` + `clientName` 解析 OIDC 配置(无需手动配置 clientId)。
16
18
  - **凭证加载**:从环境变量、文件或 STS AssumeRole 加载 AK/SK(veadk 风格)。
17
19
 
@@ -251,16 +253,24 @@ TIP token 通过 `GetWorkloadAccessTokenForJWT` 获取。工作负载行为:
251
253
 
252
254
  ## 钩子
253
255
 
254
- - **before_agent_start** - 获取 TIP token;按 credential-env-bindings(按 session)将凭据注入到 `process.env`
255
- - **subagent_spawned** - 在子 agent 创建时将 TIP 传播到子会话
256
- - **before_tool_call** - authz.toolCheck、authz.skillReadCheck 或 authz.requireRiskApproval 时可选 AuthZTIP + CheckPermission 工具/skill;高风险工具需审批。评估命令/路径风险(规则 + 可选 LLM via authz.enableLlmRiskCheck)。
256
+ - **before_agent_start** - 仅为主 agent 获取 TIP token
257
+ - **subagent_spawned** - 在子 agent 创建时将 TIP 传播到子会话。
258
+ - **before_tool_call** - 群组上下文注入、可选 AuthZTIP 检查、CheckPermission、风险审批)、工具调用级凭据注入。
259
+ - **after_tool_call** - 清理工具调用级凭据注入状态。
257
260
 
258
261
  ## 数据存储
259
262
 
260
263
  插件数据位于 `~/.openclaw/plugins/identity/`:
261
264
 
262
- - `sessions.json` - sessionKey → userToken 映射(加载/保存时清理过期)
263
- - `tip-tokens.json` - sessionKey → TIP token 缓存(加载/保存时清理过期)
264
- - Credentials - 仅内存,按 session(api_key、oauth2);gateway 重启后丢失;logout 时清除
265
- - `credential-env-bindings.json` - 按 session:`{ [sessionKey]: { [provider]: envVar } }`
266
- - OIDC state - 仅内存(临时,5 分钟 TTL)
265
+ | 文件 | 描述 |
266
+ |------|------|
267
+ | `sessions.json` | 加密存储的 sessionKey userToken 映射。加载/保存时清理过期条目。 |
268
+ | `credential-env-bindings.json` | 按 session:`{ [sessionKey]: { [provider]: envVar } }` |
269
+
270
+ **仅内存存储(不持久化到磁盘):**
271
+
272
+ | 数据 | 描述 |
273
+ |------|------|
274
+ | TIP 令牌 | sessionKey → TIP token 缓存。短效,按需从 session token 重新获取。 |
275
+ | 凭据 | 按 session(api_key、oauth2)。gateway 重启后丢失;logout 时清除。 |
276
+ | OIDC state | 临时数据,5 分钟 TTL。 |
package/README.md CHANGED
@@ -9,11 +9,13 @@ Integrates with [Volcengine Agent Identity and Permission Management](https://ww
9
9
  ## Features
10
10
 
11
11
  - **OIDC Login**: `/identity login` returns IdP auth URL (no HTTP start endpoint). User opens URL, IdP redirects to `/identity/oauth/callback`.
12
- - **TIP Token**: `before_agent_start` hook fetches TIP token when session has a logged-in user
12
+ - **TIP Token**: `before_agent_start` hook fetches TIP token when session has a logged-in user.
13
13
  - **Credential 3LO**: `/identity fetch <provider>` returns auth URL. IdP redirects to Identity-provided callback (control-plane config).
14
- - **Credential Binding**: `/identity set <provider> <envVar>` binds stored credential to env var. Credentials are injected into `process.env` in `before_agent_start` when tools run.
15
- - **Dynamic UserPool**: Resolve OIDC config by `userPoolName` + `clientName` (no manual clientId)
16
- - **Credentials**: Load AK/SK from env, file, or STS AssumeRole (veadk-style)
14
+ - **Credential Binding**: `/identity set <provider> <envVar>` binds stored credential to env var. Credentials are securely injected per-tool-call, isolated between concurrent multi-user sessions.
15
+ - **Encrypted Session Storage**: `sessions.json` is encrypted at rest (AES-256-GCM). Plaintext sessions from older versions are auto-migrated on first load.
16
+ - **In-memory TIP Cache**: TIP tokens are stored only in memory (no disk persistence). They are short-lived and re-obtained from the user's session token on demand.
17
+ - **Dynamic UserPool**: Resolve OIDC config by `userPoolName` + `clientName` (no manual clientId).
18
+ - **Credentials**: Load AK/SK from env, file, or STS AssumeRole (veadk-style).
17
19
 
18
20
  ## HTTP Endpoints
19
21
 
@@ -251,16 +253,24 @@ Follow-up messages (login success, credential fetch done) are not delivered when
251
253
 
252
254
  ## Hooks
253
255
 
254
- - **before_agent_start** - Fetch TIP token; inject credentials into `process.env` per credential-env-bindings (per-session)
255
- - **subagent_spawned** - Propagate TIP to child session on subagent spawn
256
- - **before_tool_call** - Optional AuthZ when authz.toolCheck, authz.skillReadCheck, or authz.requireRiskApproval. TIP + CheckPermission for tools/skills; risk approval for high-risk tools. Evaluates user-provided commands/paths (rules + optional LLM via authz.enableLlmRiskCheck).
256
+ - **before_agent_start** - Fetch TIP token for main agent only.
257
+ - **subagent_spawned** - Propagate TIP to child session on subagent spawn.
258
+ - **before_tool_call** - Group context injection, optional AuthZ (TIP check, CheckPermission, risk approval), and per-tool-call credential injection.
259
+ - **after_tool_call** - Clean up per-tool-call credential injection state.
257
260
 
258
261
  ## Data Storage
259
262
 
260
263
  Plugin data at `~/.openclaw/plugins/identity/`:
261
264
 
262
- - `sessions.json` - sessionKey → userToken mapping (expired pruned on load/save)
263
- - `tip-tokens.json` - sessionKey → TIP token cache (expired pruned on load/save)
264
- - Credentials - in-memory only, per-session (api_key, oauth2); lost on gateway restart; cleared on logout
265
- - `credential-env-bindings.json` - per-session: `{ [sessionKey]: { [provider]: envVar } }`
266
- - OIDC state - in-memory only (ephemeral, 5 min TTL)
265
+ | File | Description |
266
+ |------|-------------|
267
+ | `sessions.json` | Encrypted sessionKey userToken mapping. Expired entries pruned on load/save. |
268
+ | `credential-env-bindings.json` | Per-session: `{ [sessionKey]: { [provider]: envVar } }` |
269
+
270
+ **In-memory only (not persisted to disk):**
271
+
272
+ | Data | Description |
273
+ |------|-------------|
274
+ | TIP tokens | sessionKey → TIP token cache. Short-lived, re-obtained from session token on demand. |
275
+ | Credentials | Per-session (api_key, oauth2). Lost on gateway restart; cleared on logout. |
276
+ | OIDC state | Ephemeral, 5 min TTL. |
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAgBA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAmE7D,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,GAAG,EAAE,iBAAiB,QA0YtD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAgBA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAqE7D,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,GAAG,EAAE,iBAAiB,QA0YtD"}
package/dist/index.js CHANGED
@@ -22,6 +22,7 @@ import { createSubagentEndedCleanupHandler } from "./src/hooks/subagent-ended-cl
22
22
  import { setSender, clearSender } from "./src/store/group-sender-store.js";
23
23
  import { deriveSessionKey, isGroupOrChannelSessionKey, } from "./src/utils/derive-session-key.js";
24
24
  import { createBeforeToolCallHandler } from "./src/hooks/before-tool-call.js";
25
+ import { createAfterToolCallHandler } from "./src/hooks/after-tool-call.js";
25
26
  import * as skillPathStore from "./src/store/skill-path-store.js";
26
27
  import { createOIDCCallbackHandler, createOIDCCallbackHandlerLazy, } from "./src/routes/oidc-login.js";
27
28
  import { IdentityClient, resolveOIDCConfig, } from "./src/services/identity-client.js";
@@ -43,6 +44,7 @@ import { createIdentityUnsetBindingTool } from "./src/tools/identity-unset-bindi
43
44
  import { createIdentityWhoamiTool } from "./src/tools/identity-whoami.js";
44
45
  import { parseSessionKeyToDeliveryTarget, } from "./src/utils/derive-session-key.js";
45
46
  import { logInfo, logWarn } from "./src/utils/logger.js";
47
+ import { initEncryptionKey } from "./src/store/encryption.js";
46
48
  const PLUGIN_STORE_DIR = "~/.openclaw/plugins/identity";
47
49
  /**
48
50
  * Whether Identity should be enabled.
@@ -64,6 +66,7 @@ function hasAnyIdentityConfig(identity) {
64
66
  export default function register(api) {
65
67
  const pluginConfig = (api.pluginConfig ?? {});
66
68
  const storeDir = api.resolvePath(PLUGIN_STORE_DIR);
69
+ initEncryptionKey(storeDir);
67
70
  const identityCfg = pluginConfig.identity;
68
71
  const hasIdentity = hasAnyIdentityConfig(identityCfg);
69
72
  const userpool = pluginConfig.userpool;
@@ -366,10 +369,7 @@ export default function register(api) {
366
369
  logger: api.logger,
367
370
  }));
368
371
  }
369
- const toolCheck = authz?.toolCheck ?? false;
370
372
  const skillReadCheck = authz?.skillReadCheck ?? false;
371
- const requireRiskApproval = authz?.requireRiskApproval ?? false;
372
- const hasAuthz = toolCheck || skillReadCheck || requireRiskApproval;
373
373
  api.on("llm_input", createLlmInputHandler({
374
374
  enabled: skillReadCheck,
375
375
  logger: api.logger,
@@ -380,18 +380,19 @@ export default function register(api) {
380
380
  skillPathStore.clearSessionById(ctx.sessionId);
381
381
  });
382
382
  }
383
- if (hasAuthz) {
384
- api.on("before_tool_call", createBeforeToolCallHandler({
385
- storeDir,
386
- identityClient: hasIdentity ? identityClient : undefined,
387
- namespaceName: authz?.namespaceName ?? "default",
388
- logger: api.logger,
389
- sendToSession,
390
- authz,
391
- approvalTtlMs,
392
- identityService: hasIdentity ? identityService : undefined,
393
- getOidcConfigForRefresh: getOidcConfigForRefresh ?? undefined,
394
- configWorkloadName: identityCfg?.workloadName,
395
- }));
396
- }
383
+ // before_tool_call: authz, credential injection, group sender context
384
+ api.on("before_tool_call", createBeforeToolCallHandler({
385
+ storeDir,
386
+ identityClient: hasIdentity ? identityClient : undefined,
387
+ namespaceName: authz?.namespaceName ?? "default",
388
+ logger: api.logger,
389
+ sendToSession,
390
+ authz,
391
+ approvalTtlMs,
392
+ identityService: hasIdentity ? identityService : undefined,
393
+ getOidcConfigForRefresh: getOidcConfigForRefresh ?? undefined,
394
+ configWorkloadName: identityCfg?.workloadName,
395
+ }));
396
+ // Companion after_tool_call: restore env snapshot set by credential injection
397
+ api.on("after_tool_call", createAfterToolCallHandler({ logger: api.logger }));
397
398
  }
@@ -86,7 +86,11 @@ export type ListCredentialsResult = {
86
86
  hasMore: boolean;
87
87
  totalCount?: number;
88
88
  };
89
- export declare function runListCredentials(deps: IdentityActionsDeps, sessionKey: string, page?: number): Promise<ListCredentialsResult>;
89
+ export type ListCredentialsFilter = {
90
+ name?: string;
91
+ flow?: string;
92
+ };
93
+ export declare function runListCredentials(deps: IdentityActionsDeps, sessionKey: string, page?: number, filter?: ListCredentialsFilter): Promise<ListCredentialsResult>;
90
94
  export type ListTipsResult = {
91
95
  tips: Array<{
92
96
  sessionKey: string;
@@ -124,6 +128,8 @@ export declare function runFetch(deps: IdentityActionsDeps, sessionKey: string,
124
128
  scopes?: string[];
125
129
  deliveryTarget?: SessionKeyDeliveryTarget | null;
126
130
  config?: OpenClawConfig;
131
+ /** "tool" = agent tool call, "command" = slash command. Defaults to "command". */
132
+ source?: "tool" | "command";
127
133
  }): Promise<FetchResult>;
128
134
  export type SetBindingResult = {
129
135
  ok: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"identity-actions.d.ts","sourceRoot":"","sources":["../../../src/actions/identity-actions.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"identity-actions.d.ts","sourceRoot":"","sources":["../../../src/actions/identity-actions.ts"],"names":[],"mappings":"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"}
@@ -20,7 +20,7 @@ import { loadCredentialEnvBindings, loadAllCredentialEnvBindings, setCredentialE
20
20
  import { loadCredentials, setCredential, getCredential, deleteCredentialsForSession, } from "../store/credential-store.js";
21
21
  import { getSession, deleteSession } from "../store/session-store.js";
22
22
  import { createState } from "../store/oidc-state-store.js";
23
- import { loadTIPTokens, saveTIPTokens } from "../store/tip-store.js";
23
+ import { getAllTIPTokens, deleteTIPToken } from "../store/tip-store.js";
24
24
  import { extractDelegationChainFromJwt } from "../utils/auth.js";
25
25
  import { resolveAgentId, } from "../utils/derive-session-key.js";
26
26
  function inferFlowFromProvider(info) {
@@ -32,6 +32,7 @@ function inferFlowFromProvider(info) {
32
32
  }
33
33
  const OAUTH_POLL_INTERVAL_MS = 2500;
34
34
  const OAUTH_POLL_TIMEOUT_MS = 10 * 60 * 1000;
35
+ const OAUTH_QUICK_RETRY_MS = 1000;
35
36
  function sleep(ms) {
36
37
  return new Promise((r) => setTimeout(r, ms));
37
38
  }
@@ -156,30 +157,40 @@ export async function runLogout(deps, sessionKey) {
156
157
  const { storeDir, logger } = deps;
157
158
  logDebug(logger, `logout sessionKey=${sessionKey.slice(0, 24)}...`);
158
159
  await deleteSession(storeDir, sessionKey);
159
- const tokens = await loadTIPTokens(storeDir);
160
- delete tokens[sessionKey];
161
- await saveTIPTokens(storeDir, tokens);
160
+ deleteTIPToken(sessionKey);
162
161
  deleteCredentialsForSession(storeDir, sessionKey);
163
162
  return { ok: true };
164
163
  }
165
164
  const LIST_PAGE_SIZE = 10;
166
- export async function runListCredentials(deps, sessionKey, page = 1) {
167
- const { storeDir, identityClient, logger } = deps;
165
+ export async function runListCredentials(deps, sessionKey, page = 1, filter) {
166
+ const { storeDir, identityClient, identityService, logger } = deps;
168
167
  const creds = await loadCredentials(storeDir, sessionKey);
169
168
  const bindings = await loadCredentialEnvBindings(storeDir, sessionKey);
170
169
  let providers = [];
171
170
  let totalCount = 0;
172
171
  if (identityClient) {
173
- try {
174
- const result = await identityClient.listCredentialProviders({
175
- PageNumber: page,
176
- PageSize: LIST_PAGE_SIZE,
177
- });
178
- providers = result.CredentialProviders ?? result.Data ?? [];
179
- totalCount = result.TotalCount ?? 0;
172
+ const session = await getSession(storeDir, sessionKey);
173
+ if (!session || !identityService.parseUserToken(session.userToken).valid) {
174
+ logWarn(logger, `list-credentials: no valid session for key=${sessionKey.slice(0, 24)}...`);
180
175
  }
181
- catch (e) {
182
- logWarn(logger, `list-credentials API error: ${String(e)}`);
176
+ else {
177
+ try {
178
+ const apiFilter = {};
179
+ if (filter?.name)
180
+ apiFilter.Name = filter.name;
181
+ if (filter?.flow)
182
+ apiFilter.Flow = filter.flow;
183
+ const result = await identityClient.listCredentialProviders({
184
+ PageNumber: page,
185
+ PageSize: LIST_PAGE_SIZE,
186
+ ...(Object.keys(apiFilter).length > 0 ? { Filter: apiFilter } : {}),
187
+ });
188
+ providers = result.CredentialProviders ?? result.Data ?? [];
189
+ totalCount = result.TotalCount ?? 0;
190
+ }
191
+ catch (e) {
192
+ logWarn(logger, `list-credentials API error: ${String(e)}`);
193
+ }
183
194
  }
184
195
  }
185
196
  const providerNames = new Set(providers.map((p) => p.Name));
@@ -232,7 +243,7 @@ export async function runListCredentials(deps, sessionKey, page = 1) {
232
243
  }
233
244
  export async function runListTips(deps) {
234
245
  const { storeDir } = deps;
235
- const tokens = await loadTIPTokens(storeDir);
246
+ const tokens = getAllTIPTokens();
236
247
  const bindingsBySession = await loadAllCredentialEnvBindings(storeDir);
237
248
  const now = Date.now();
238
249
  const tips = [];
@@ -292,27 +303,10 @@ export async function runConfig(deps) {
292
303
  }
293
304
  export async function runFetch(deps, sessionKey, params) {
294
305
  const { identityClient, storeDir, sendCredentialMessage, logger } = deps;
295
- const { provider, flow, flowExplicit, redirectUrl, scopes, deliveryTarget, config } = params;
306
+ const { provider, flow, flowExplicit, redirectUrl, scopes, deliveryTarget, config, source = "command" } = params;
296
307
  if (!identityClient) {
297
308
  return { kind: "error", message: "Identity service not configured. Cannot add credentials." };
298
309
  }
299
- let effectiveFlow = flow;
300
- if (!flowExplicit) {
301
- try {
302
- const listResult = await identityClient.listCredentialProviders({
303
- PageNumber: 1,
304
- PageSize: 20,
305
- Filter: { Name: provider },
306
- });
307
- const list = listResult.CredentialProviders ?? listResult.Data ?? [];
308
- const info = list.find((p) => p.Name === provider);
309
- if (info)
310
- effectiveFlow = inferFlowFromProvider(info);
311
- }
312
- catch {
313
- // keep default
314
- }
315
- }
316
310
  const ctxAgentId = resolveAgentId({ sessionKey, config: config });
317
311
  const tipRefreshOptions = deps.getOidcConfigForRefresh
318
312
  ? {
@@ -330,6 +324,23 @@ export async function runFetch(deps, sessionKey, params) {
330
324
  message: "Login first with `/identity login` to establish identity before adding credentials.",
331
325
  };
332
326
  }
327
+ let effectiveFlow = flow;
328
+ if (!flowExplicit) {
329
+ try {
330
+ const listResult = await identityClient.listCredentialProviders({
331
+ PageNumber: 1,
332
+ PageSize: 20,
333
+ Filter: { Name: provider },
334
+ });
335
+ const list = listResult.CredentialProviders ?? listResult.Data ?? [];
336
+ const info = list.find((p) => p.Name === provider);
337
+ if (info)
338
+ effectiveFlow = inferFlowFromProvider(info);
339
+ }
340
+ catch {
341
+ // keep default
342
+ }
343
+ }
333
344
  try {
334
345
  if (effectiveFlow === "apikey") {
335
346
  const result = await identityClient.getResourceApiKey({
@@ -361,6 +372,43 @@ export async function runFetch(deps, sessionKey, params) {
361
372
  return { kind: "success", message: `✓ Credential for \`${provider}\` added (direct token).` };
362
373
  }
363
374
  if (oauthResult.authorizationUrl) {
375
+ // Quick retry: the server may have a cached token that wasn't ready on
376
+ // the first call (e.g. user previously authorized). A short pause then
377
+ // re-check avoids unnecessary polling / returning authUrl to the user.
378
+ await sleep(OAUTH_QUICK_RETRY_MS);
379
+ try {
380
+ const retry = await identityClient.getResourceOauth2Token({
381
+ providerName: provider,
382
+ identityToken: tip.token,
383
+ flow: oauth2Flow,
384
+ redirectUrl,
385
+ scopes: scopes?.length ? scopes : undefined,
386
+ });
387
+ if (retry.accessToken) {
388
+ await setCredential(storeDir, sessionKey, provider, {
389
+ type: "oauth2",
390
+ status: "authenticated",
391
+ accessToken: retry.accessToken,
392
+ expiresAt: Date.now() + 3600 * 1000,
393
+ });
394
+ return { kind: "success", message: `✓ Credential for \`${provider}\` added (cached token).` };
395
+ }
396
+ }
397
+ catch {
398
+ // quick retry failed — proceed with authUrl flow
399
+ }
400
+ if (source === "tool") {
401
+ // Agent tool context: return authUrl for the agent to display.
402
+ // No background polling — the agent should re-call identity_fetch
403
+ // after the user completes authorization in the browser.
404
+ logInfo(logger, `fetch returning auth URL for provider=${provider} (tool, no poll)`);
405
+ return {
406
+ kind: "auth_url",
407
+ authUrl: oauthResult.authorizationUrl,
408
+ message: `Open this URL to authorize \`${provider}\`. After you complete authorization in the browser, tell me and I will fetch the credential.`,
409
+ };
410
+ }
411
+ // Slash command context: start background polling and notify via channel message.
364
412
  logInfo(logger, `fetch returning auth URL for provider=${provider}, starting poll`);
365
413
  const target = deliveryTarget ?? sessionKey;
366
414
  pollOAuthAndNotify({
@@ -1 +1 @@
1
- {"version":3,"file":"identity-commands.d.ts","sourceRoot":"","sources":["../../../src/commands/identity-commands.ts"],"names":[],"mappings":"AAgBA;;;GAGG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAUL,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,SAAS,EACf,MAAM,gCAAgC,CAAC;AAYxC,YAAY,EAAE,oBAAoB,EAAE,SAAS,EAAE,CAAC;AAEhD,MAAM,MAAM,sBAAsB,GAAG;IACnC,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG,mBAAmB,CAAC;AAooBvD,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,oBAAoB;;;;;mBAjf3C,oBAAoB,KAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;EA0fpE;AAED,0CAA0C;AAC1C,wBAAgB,eAAe,CAAC,IAAI,EAAE,oBAAoB;;;;;mBA7frC,oBAAoB,KAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;EAsgBpE"}
1
+ {"version":3,"file":"identity-commands.d.ts","sourceRoot":"","sources":["../../../src/commands/identity-commands.ts"],"names":[],"mappings":"AAgBA;;;GAGG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAUL,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,SAAS,EACf,MAAM,gCAAgC,CAAC;AAYxC,YAAY,EAAE,oBAAoB,EAAE,SAAS,EAAE,CAAC;AAEhD,MAAM,MAAM,sBAAsB,GAAG;IACnC,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG,mBAAmB,CAAC;AAyoBvD,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,oBAAoB;;;;;mBAlf3C,oBAAoB,KAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;EA2fpE;AAED,0CAA0C;AAC1C,wBAAgB,eAAe,CAAC,IAAI,EAAE,oBAAoB;;;;;mBA9frC,oBAAoB,KAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;EAugBpE"}
@@ -88,7 +88,7 @@ function parseSubcommand(args) {
88
88
  rest: raw.slice(space + 1).trim(),
89
89
  };
90
90
  }
91
- /** Parse list args: optional page. E.g. "list", "list 2", "list --page 2". */
91
+ /** Parse list args: optional page and filters. E.g. "list", "list 2", "list --name=github --flow=M2M". */
92
92
  function parseListArgs(rest) {
93
93
  const parts = rest.split(/\s+/).filter(Boolean);
94
94
  const flags = {};
@@ -104,7 +104,11 @@ function parseListArgs(rest) {
104
104
  }
105
105
  }
106
106
  const page = flags.page ? parseInt(flags.page, 10) : positional[0];
107
- return { page: Number.isFinite(page) && page >= 1 ? page : 1 };
107
+ return {
108
+ page: Number.isFinite(page) && page >= 1 ? page : 1,
109
+ name: flags.name || undefined,
110
+ flow: flags.flow || undefined,
111
+ };
108
112
  }
109
113
  /** Parse fetch args: provider and flags (--flow, --redirectUrl, --scopes). flow can be omitted to auto-infer from provider. */
110
114
  function parseFetchArgs(rest) {
@@ -331,8 +335,9 @@ async function handleLogout(deps, sessionKey) {
331
335
  return { text: "✓ Logged out." };
332
336
  }
333
337
  async function handleListCredentials(deps, sessionKey, rest) {
334
- const { page } = parseListArgs(rest);
335
- const result = await runListCredentials(deps, sessionKey, page);
338
+ const { page, name, flow } = parseListArgs(rest);
339
+ const filter = name || flow ? { name, flow } : undefined;
340
+ const result = await runListCredentials(deps, sessionKey, page, filter);
336
341
  const lines = [];
337
342
  if (result.providers.length > 0) {
338
343
  lines.push(`**Available (page ${result.page}):**`);
@@ -0,0 +1,12 @@
1
+ import { type PluginLogger } from "../utils/logger.js";
2
+ export type AfterToolCallDeps = {
3
+ logger?: PluginLogger;
4
+ };
5
+ export declare function createAfterToolCallHandler(deps: AfterToolCallDeps): (event: {
6
+ toolName: string;
7
+ runId?: string;
8
+ toolCallId?: string;
9
+ }, _ctx: {
10
+ sessionKey?: string;
11
+ }) => void;
12
+ //# sourceMappingURL=after-tool-call.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"after-tool-call.d.ts","sourceRoot":"","sources":["../../../src/hooks/after-tool-call.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAY,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEjE,MAAM,MAAM,iBAAiB,GAAG;IAC9B,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB,CAAC;AAEF,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,iBAAiB,IAI9D,OAAO;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,EAChE,MAAM;IAAE,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,KAC5B,IAAI,CASR"}
@@ -0,0 +1,31 @@
1
+ /*
2
+ * Copyright (c) 2026 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ /**
17
+ * after_tool_call hook: restore process.env snapshot and release per-key locks
18
+ * set by before_tool_call credential injection.
19
+ */
20
+ import { hasSnapshot, restoreEnvSnapshot } from "../store/credential-env-snapshot.js";
21
+ import { logDebug } from "../utils/logger.js";
22
+ export function createAfterToolCallHandler(deps) {
23
+ const { logger } = deps;
24
+ return (event, _ctx) => {
25
+ if (!hasSnapshot(event.runId, event.toolCallId))
26
+ return;
27
+ logDebug(logger, `restoring env snapshot for tool=${event.toolName} ` +
28
+ `run=${event.runId ?? "?"} toolCallId=${event.toolCallId ?? "?"}`);
29
+ restoreEnvSnapshot(event.runId, event.toolCallId);
30
+ };
31
+ }
@@ -1,8 +1,7 @@
1
1
  /**
2
2
  * before_agent_start hook: fetch TIP token for main agent only.
3
- * 1. Inject credentials into process.env per credential-env-bindings
4
- * 2. Subagent: skip (TIP comes from sessions_send propagation)
5
- * 3. Main: getOrRefreshTIPToken (fetches TIP, refreshes userToken if expired)
3
+ * Credential env injection is handled per-tool-call in before_tool_call
4
+ * to avoid process.env race conditions between concurrent runs.
6
5
  */
7
6
  import type { IdentityService } from "../services/identity-service.js";
8
7
  import type { OIDCConfigForRefresh } from "../services/session-refresh.js";
@@ -13,6 +12,7 @@ export type BeforeAgentStartDeps = {
13
12
  getOidcConfigForRefresh?: () => Promise<OIDCConfigForRefresh>;
14
13
  logger: {
15
14
  info?: (msg: string) => void;
15
+ debug?: (msg: string) => void;
16
16
  warn?: (msg: string) => void;
17
17
  };
18
18
  };
@@ -1 +1 @@
1
- {"version":3,"file":"before-agent-start.d.ts","sourceRoot":"","sources":["../../../src/hooks/before-agent-start.ts"],"names":[],"mappings":"AAgBA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AACvE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AAQ3E,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,eAAe,CAAC;IACjC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,uBAAuB,CAAC,EAAE,MAAM,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAC9D,MAAM,EAAE;QAAE,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QAAC,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE,CAAC;CACxE,CAAC;AAEF,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,oBAAoB,IAapE,QAAQ;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAA;CAAE,EAChD,KAAK;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,KAC7C,OAAO,CAAC;IAAE,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CA8B/C"}
1
+ {"version":3,"file":"before-agent-start.d.ts","sourceRoot":"","sources":["../../../src/hooks/before-agent-start.ts"],"names":[],"mappings":"AAgBA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AACvE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AAM3E,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,eAAe,CAAC;IACjC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,uBAAuB,CAAC,EAAE,MAAM,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAC9D,MAAM,EAAE;QAAE,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QAAC,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QAAC,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE,CAAC;CACvG,CAAC;AAEF,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,oBAAoB,IAWpE,QAAQ;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAA;CAAE,EAChD,KAAK;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,KAC7C,OAAO,CAAC;IAAE,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAuB/C"}
@@ -14,15 +14,11 @@
14
14
  * limitations under the License.
15
15
  */
16
16
  import { getOrRefreshTIPToken } from "../services/tip-with-refresh.js";
17
- import { logWarn } from "../utils/logger.js";
18
- import { loadCredentialEnvBindings } from "../store/credential-env-bindings.js";
19
- import { getCredential, resolveCredentialValue } from "../store/credential-store.js";
17
+ import { logDebug, logWarn } from "../utils/logger.js";
20
18
  import { isSubagentSessionKey } from "../utils/derive-session-key.js";
21
19
  import { resolveEffectiveSessionKey } from "../store/group-sender-store.js";
22
20
  export function createBeforeAgentStartHandler(deps) {
23
21
  const { storeDir, identityService, configWorkloadName, getOidcConfigForRefresh, logger } = deps;
24
- // Always pass identityService so we can try fetch with session.userToken when TIP is missing/expired.
25
- // getOidcConfigForRefresh is only needed for refresh when userToken itself has expired.
26
22
  const tipRefreshOptions = {
27
23
  identityService,
28
24
  getOidcConfigForRefresh,
@@ -36,27 +32,17 @@ export function createBeforeAgentStartHandler(deps) {
36
32
  if (isSubagentSessionKey(sessionKey))
37
33
  return;
38
34
  const effectiveKey = resolveEffectiveSessionKey(sessionKey);
39
- try {
40
- const bindings = await loadCredentialEnvBindings(storeDir, effectiveKey);
41
- for (const [provider, envVar] of Object.entries(bindings)) {
42
- const cred = await getCredential(storeDir, effectiveKey, provider);
43
- const value = cred ? resolveCredentialValue(cred) : undefined;
44
- if (value)
45
- process.env[envVar] = value;
46
- else
47
- delete process.env[envVar];
48
- }
49
- }
50
- catch {
51
- /* best-effort */
52
- }
35
+ logDebug(logger, `before_agent_start: fetching TIP for key=${effectiveKey}`);
53
36
  try {
54
37
  const tip = await getOrRefreshTIPToken(storeDir, effectiveKey, {
55
38
  ...tipRefreshOptions,
56
39
  ctxAgentId: ctx.agentId,
57
40
  });
58
- if (!tip)
41
+ if (!tip) {
42
+ logDebug(logger, `before_agent_start: no TIP available for key=${effectiveKey}`);
59
43
  return;
44
+ }
45
+ logDebug(logger, `before_agent_start: TIP ready for key=${effectiveKey} sub=${tip.sub}`);
60
46
  }
61
47
  catch (err) {
62
48
  logWarn(logger, `failed to get TIP for ${effectiveKey}: ${String(err)}`);
@@ -1,8 +1,9 @@
1
1
  /**
2
- * before_tool_call hook: optional AuthZ check.
3
- * When enabled, blocks tool calls for sessions without valid TIP or denied by policy.
4
- * Integrates with CheckPermission when identityClient is provided (veadk-style).
5
- * Supports low-risk bypass and high-risk pending approval (Channel: poll, Webchat/TUI: retry).
2
+ * before_tool_call hook three sequential phases:
3
+ *
4
+ * 1. Group sender context injection (_enhancedContext).
5
+ * 2. Session + AuthZ gate (mandatory session check, optional CheckPermission / risk).
6
+ * 3. Per-tool-call credential injection (params + process.env snapshot).
6
7
  *
7
8
  * @see https://github.com/volcengine/veadk-python/blob/main/veadk/tools/builtin_tools/agent_authorization.py
8
9
  */
@@ -12,34 +13,38 @@ import type { OIDCConfigForRefresh } from "../services/session-refresh.js";
12
13
  import type { PluginConfig } from "../types.js";
13
14
  export type BeforeToolCallDeps = {
14
15
  storeDir: string;
15
- /** When set, call CheckPermission with principal/originalCallers from TIP token, resource=toolName. */
16
16
  identityClient?: IdentityClientInterface;
17
- /** Namespace for CheckPermission. From authz.namespaceName, default "default". */
18
17
  namespaceName?: string;
19
18
  logger: {
20
19
  debug?: (msg: string) => void;
21
20
  warn?: (msg: string) => void;
22
21
  };
23
- /** Send message to session (Channel only). For sync approval flow. */
24
22
  sendToSession?: (targetOrSessionKey: string, text: string) => Promise<void>;
25
- /** Authz config. */
26
23
  authz?: PluginConfig["authz"];
27
- approvalTtlMs: number;
28
- /** When set, attempt TIP refresh when expired (uses session refresh_token). */
24
+ approvalTtlMs?: number;
29
25
  identityService?: IdentityService;
30
26
  getOidcConfigForRefresh?: () => Promise<OIDCConfigForRefresh>;
31
27
  configWorkloadName?: string;
32
28
  };
29
+ type HookResult = {
30
+ params?: Record<string, unknown>;
31
+ block?: boolean;
32
+ blockReason?: string;
33
+ };
34
+ declare function resolveCredentials(storeDir: string, effectiveKey: string): Promise<Record<string, string>>;
33
35
  export declare function createBeforeToolCallHandler(deps: BeforeToolCallDeps): (event: {
34
36
  toolName: string;
35
37
  runId?: string;
38
+ toolCallId?: string;
36
39
  params: Record<string, unknown>;
37
40
  }, ctx: {
38
41
  agentId?: string;
39
42
  sessionKey?: string;
40
43
  toolName: string;
41
- }) => Promise<{
42
- block?: boolean;
43
- blockReason?: string;
44
- } | void>;
44
+ }) => Promise<HookResult | void>;
45
+ /** Exposed for testing. */
46
+ export declare const __testing: {
47
+ resolveCredentials: typeof resolveCredentials;
48
+ };
49
+ export {};
45
50
  //# sourceMappingURL=before-tool-call.d.ts.map