@m1a0rz/agent-identity 0.4.1 → 0.4.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 (127) hide show
  1. package/README-cn.md +4 -3
  2. package/README.md +4 -3
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +77 -6
  5. package/dist/scripts/demo-get-session.d.ts +15 -0
  6. package/dist/scripts/demo-get-session.d.ts.map +1 -0
  7. package/dist/scripts/demo-get-session.js +58 -0
  8. package/dist/src/actions/identity-actions.d.ts +74 -8
  9. package/dist/src/actions/identity-actions.d.ts.map +1 -1
  10. package/dist/src/actions/identity-actions.js +209 -83
  11. package/dist/src/commands/identity-commands.d.ts.map +1 -1
  12. package/dist/src/commands/identity-commands.js +139 -11
  13. package/dist/src/gateway/identity-session-methods.d.ts +2 -2
  14. package/dist/src/gateway/identity-session-methods.d.ts.map +1 -1
  15. package/dist/src/gateway/identity-session-methods.js +9 -5
  16. package/dist/src/hooks/after-tool-call.d.ts.map +1 -1
  17. package/dist/src/hooks/after-tool-call.js +12 -0
  18. package/dist/src/hooks/before-agent-start.d.ts +2 -0
  19. package/dist/src/hooks/before-agent-start.d.ts.map +1 -1
  20. package/dist/src/hooks/before-agent-start.js +33 -6
  21. package/dist/src/hooks/before-tool-call.d.ts +1 -0
  22. package/dist/src/hooks/before-tool-call.d.ts.map +1 -1
  23. package/dist/src/hooks/before-tool-call.js +29 -5
  24. package/dist/src/hooks/llm-input.d.ts.map +1 -1
  25. package/dist/src/hooks/llm-input.js +32 -4
  26. package/dist/src/hooks/sessions-send-propagation.d.ts.map +1 -1
  27. package/dist/src/hooks/sessions-send-propagation.js +1 -0
  28. package/dist/src/hooks/sessions-spawn-propagation.d.ts.map +1 -1
  29. package/dist/src/hooks/sessions-spawn-propagation.js +1 -0
  30. package/dist/src/hooks/tool-result-persist.d.ts +20 -0
  31. package/dist/src/hooks/tool-result-persist.d.ts.map +1 -0
  32. package/dist/src/hooks/tool-result-persist.js +50 -0
  33. package/dist/src/preflight/plugin-preflight.d.ts +55 -0
  34. package/dist/src/preflight/plugin-preflight.d.ts.map +1 -0
  35. package/dist/src/preflight/plugin-preflight.js +226 -0
  36. package/dist/src/preflight/plugin-state.d.ts +18 -0
  37. package/dist/src/preflight/plugin-state.d.ts.map +1 -0
  38. package/dist/src/preflight/plugin-state.js +19 -0
  39. package/dist/src/routes/oidc-login.js +2 -2
  40. package/dist/src/services/identity-client.d.ts +106 -1
  41. package/dist/src/services/identity-client.d.ts.map +1 -1
  42. package/dist/src/services/identity-client.js +123 -1
  43. package/dist/src/services/identity-credentials.d.ts +1 -1
  44. package/dist/src/services/identity-credentials.d.ts.map +1 -1
  45. package/dist/src/services/identity-credentials.js +32 -16
  46. package/dist/src/services/oidc-client.d.ts +12 -1
  47. package/dist/src/services/oidc-client.d.ts.map +1 -1
  48. package/dist/src/services/oidc-client.js +20 -3
  49. package/dist/src/services/session-refresh.d.ts +10 -0
  50. package/dist/src/services/session-refresh.d.ts.map +1 -1
  51. package/dist/src/services/session-refresh.js +29 -5
  52. package/dist/src/services/skill-contract-metadata.d.ts +35 -0
  53. package/dist/src/services/skill-contract-metadata.d.ts.map +1 -0
  54. package/dist/src/services/skill-contract-metadata.js +145 -0
  55. package/dist/src/services/skill-contract-renderer.d.ts +14 -0
  56. package/dist/src/services/skill-contract-renderer.d.ts.map +1 -0
  57. package/dist/src/services/skill-contract-renderer.js +120 -0
  58. package/dist/src/services/tip-propagation.d.ts +2 -0
  59. package/dist/src/services/tip-propagation.d.ts.map +1 -1
  60. package/dist/src/services/tip-propagation.js +4 -3
  61. package/dist/src/services/tip-with-refresh.d.ts +1 -1
  62. package/dist/src/services/tip-with-refresh.d.ts.map +1 -1
  63. package/dist/src/services/tip-with-refresh.js +24 -39
  64. package/dist/src/store/credential-store.d.ts +6 -1
  65. package/dist/src/store/credential-store.d.ts.map +1 -1
  66. package/dist/src/store/credential-store.js +3 -0
  67. package/dist/src/store/oidc-state-store.d.ts +3 -3
  68. package/dist/src/store/oidc-state-store.d.ts.map +1 -1
  69. package/dist/src/store/oidc-state-store.js +2 -2
  70. package/dist/src/store/sender-session-store.d.ts +8 -0
  71. package/dist/src/store/sender-session-store.d.ts.map +1 -1
  72. package/dist/src/store/sender-session-store.js +34 -1
  73. package/dist/src/store/skill-contract-store.d.ts +19 -0
  74. package/dist/src/store/skill-contract-store.d.ts.map +1 -0
  75. package/dist/src/store/skill-contract-store.js +65 -0
  76. package/dist/src/store/skill-path-store.d.ts +5 -0
  77. package/dist/src/store/skill-path-store.d.ts.map +1 -1
  78. package/dist/src/store/skill-path-store.js +13 -1
  79. package/dist/src/tools/identity-approve-tool.d.ts +2 -11
  80. package/dist/src/tools/identity-approve-tool.d.ts.map +1 -1
  81. package/dist/src/tools/identity-config-suggest.d.ts +2 -13
  82. package/dist/src/tools/identity-config-suggest.d.ts.map +1 -1
  83. package/dist/src/tools/identity-config.d.ts +2 -7
  84. package/dist/src/tools/identity-config.d.ts.map +1 -1
  85. package/dist/src/tools/identity-fetch.d.ts +2 -13
  86. package/dist/src/tools/identity-fetch.d.ts.map +1 -1
  87. package/dist/src/tools/identity-fetch.js +3 -3
  88. package/dist/src/tools/identity-get-role-credentials.d.ts +10 -0
  89. package/dist/src/tools/identity-get-role-credentials.d.ts.map +1 -0
  90. package/dist/src/tools/identity-get-role-credentials.js +56 -0
  91. package/dist/src/tools/identity-get-session-token.d.ts +8 -0
  92. package/dist/src/tools/identity-get-session-token.d.ts.map +1 -0
  93. package/dist/src/tools/identity-get-session-token.js +46 -0
  94. package/dist/src/tools/identity-get-tip-token.d.ts +8 -0
  95. package/dist/src/tools/identity-get-tip-token.d.ts.map +1 -0
  96. package/dist/src/tools/identity-get-tip-token.js +46 -0
  97. package/dist/src/tools/identity-list-credentials.d.ts +2 -11
  98. package/dist/src/tools/identity-list-credentials.d.ts.map +1 -1
  99. package/dist/src/tools/identity-list-credentials.js +4 -3
  100. package/dist/src/tools/identity-list-risk-patterns.d.ts +2 -7
  101. package/dist/src/tools/identity-list-risk-patterns.d.ts.map +1 -1
  102. package/dist/src/tools/identity-list-roles.d.ts +8 -0
  103. package/dist/src/tools/identity-list-roles.d.ts.map +1 -0
  104. package/dist/src/tools/identity-list-roles.js +43 -0
  105. package/dist/src/tools/identity-list-tips.d.ts +2 -7
  106. package/dist/src/tools/identity-list-tips.d.ts.map +1 -1
  107. package/dist/src/tools/identity-login.d.ts +2 -7
  108. package/dist/src/tools/identity-login.d.ts.map +1 -1
  109. package/dist/src/tools/identity-logout.d.ts +2 -7
  110. package/dist/src/tools/identity-logout.d.ts.map +1 -1
  111. package/dist/src/tools/identity-risk-check.d.ts +3 -17
  112. package/dist/src/tools/identity-risk-check.d.ts.map +1 -1
  113. package/dist/src/tools/identity-set-binding.d.ts +2 -10
  114. package/dist/src/tools/identity-set-binding.d.ts.map +1 -1
  115. package/dist/src/tools/identity-status.d.ts +2 -7
  116. package/dist/src/tools/identity-status.d.ts.map +1 -1
  117. package/dist/src/tools/identity-unset-binding.d.ts +2 -9
  118. package/dist/src/tools/identity-unset-binding.d.ts.map +1 -1
  119. package/dist/src/tools/identity-whoami.d.ts +2 -7
  120. package/dist/src/tools/identity-whoami.d.ts.map +1 -1
  121. package/dist/src/types.d.ts +19 -0
  122. package/dist/src/types.d.ts.map +1 -1
  123. package/dist/src/utils/derive-session-key.d.ts +1 -0
  124. package/dist/src/utils/derive-session-key.d.ts.map +1 -1
  125. package/dist/src/utils/derive-session-key.js +28 -4
  126. package/openclaw.plugin.json +13 -0
  127. package/package.json +11 -3
@@ -15,7 +15,7 @@ export type LoadCredentialsOptions = {
15
15
  };
16
16
  /**
17
17
  * Load credentials from config, env, remote metadata, or file (veadk-style).
18
- * Order: explicit > env > remote metadata (credentialsMetadataUrl + roleTrn) > file.
18
+ * Order: explicit > env > remote metadata (credentialsMetadataUrl, optional roleTrn) > file.
19
19
  * Returns resolved credentials or throws if none found.
20
20
  */
21
21
  export declare function loadIdentityCredentials(opts?: LoadCredentialsOptions): Promise<IdentityCredentials>;
@@ -1 +1 @@
1
- {"version":3,"file":"identity-credentials.d.ts","sourceRoot":"","sources":["../../../src/services/identity-credentials.ts"],"names":[],"mappings":"AAgCA,MAAM,MAAM,mBAAmB,GAAG;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AASF,MAAM,MAAM,sBAAsB,GAAG;IACnC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,kHAAkH;IAClH,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;CACrC,CAAC;AA0DF;;;;GAIG;AACH,wBAAsB,uBAAuB,CAC3C,IAAI,GAAE,sBAA2B,GAChC,OAAO,CAAC,mBAAmB,CAAC,CA0D9B"}
1
+ {"version":3,"file":"identity-credentials.d.ts","sourceRoot":"","sources":["../../../src/services/identity-credentials.ts"],"names":[],"mappings":"AAgCA,MAAM,MAAM,mBAAmB,GAAG;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AASF,MAAM,MAAM,sBAAsB,GAAG;IACnC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,kHAAkH;IAClH,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;CACrC,CAAC;AAoEF;;;;GAIG;AACH,wBAAsB,uBAAuB,CAC3C,IAAI,GAAE,sBAA2B,GAChC,OAAO,CAAC,mBAAmB,CAAC,CAgE9B"}
@@ -34,12 +34,11 @@ const DEFAULT_CRED_PATH = "/var/run/secrets/iam/credential";
34
34
  const ENV_ROLE_TRN = "RUNTIME_IAM_ROLE_TRN";
35
35
  const REMOTE_METADATA_REFRESH_BUFFER_SEC = 300;
36
36
  /**
37
- * Fetch credentials from remote metadata URL (full URL), then AssumeRole with roleTrn.
38
- * Returns null on 404 or parse failure (fall through).
39
- * Caches AssumeRole result by ExpiredTime, same as AK/SK + roleTrn flow.
37
+ * Fetch credentials from remote metadata URL (e.g. ECS instance metadata).
38
+ * Returns the raw AK/SK/Token from the response, or null on failure.
40
39
  */
41
- async function fetchRemoteMetadataThenAssumeRole(fullUrl, roleTrn) {
42
- stsDebugLog("metadata fetch", { url: fullUrl, roleTrn });
40
+ async function fetchRemoteMetadata(fullUrl) {
41
+ stsDebugLog("metadata fetch", { url: fullUrl });
43
42
  let res;
44
43
  try {
45
44
  res = await fetch(fullUrl);
@@ -62,18 +61,27 @@ async function fetchRemoteMetadataThenAssumeRole(fullUrl, roleTrn) {
62
61
  const ak = json.AccessKeyId;
63
62
  const sk = json.SecretAccessKey;
64
63
  const token = json.SessionToken;
65
- if (!ak || !sk || !token)
64
+ if (!ak || !sk)
66
65
  return null;
67
- const intermediateCreds = {
66
+ return {
68
67
  accessKeyId: ak.trim(),
69
68
  secretAccessKey: sk.trim(),
70
- sessionToken: token.trim(),
69
+ sessionToken: token ? token.trim() : undefined,
71
70
  };
71
+ }
72
+ /**
73
+ * Fetch credentials from remote metadata URL, then AssumeRole with roleTrn.
74
+ * Returns null on 404 or parse failure (fall through).
75
+ */
76
+ async function fetchRemoteMetadataThenAssumeRole(fullUrl, roleTrn) {
77
+ const creds = await fetchRemoteMetadata(fullUrl);
78
+ if (!creds)
79
+ return null;
72
80
  stsDebugLog("metadata creds ok, calling AssumeRole", { roleTrn });
73
81
  return assumeRole({
74
- accessKeyId: intermediateCreds.accessKeyId,
75
- secretAccessKey: intermediateCreds.secretAccessKey,
76
- sessionToken: intermediateCreds.sessionToken,
82
+ accessKeyId: creds.accessKeyId,
83
+ secretAccessKey: creds.secretAccessKey,
84
+ sessionToken: creds.sessionToken,
77
85
  roleTrn,
78
86
  region: "cn-beijing",
79
87
  cacheKey: `metadata:${fullUrl}:${roleTrn}`,
@@ -81,7 +89,7 @@ async function fetchRemoteMetadataThenAssumeRole(fullUrl, roleTrn) {
81
89
  }
82
90
  /**
83
91
  * Load credentials from config, env, remote metadata, or file (veadk-style).
84
- * Order: explicit > env > remote metadata (credentialsMetadataUrl + roleTrn) > file.
92
+ * Order: explicit > env > remote metadata (credentialsMetadataUrl, optional roleTrn) > file.
85
93
  * Returns resolved credentials or throws if none found.
86
94
  */
87
95
  export async function loadIdentityCredentials(opts = {}) {
@@ -111,10 +119,18 @@ export async function loadIdentityCredentials(opts = {}) {
111
119
  };
112
120
  }
113
121
  }
114
- if (opts.credentialsMetadataUrl && opts.roleTrn) {
115
- const cred = await fetchRemoteMetadataThenAssumeRole(opts.credentialsMetadataUrl, opts.roleTrn);
116
- if (cred)
117
- return cred;
122
+ if (opts.credentialsMetadataUrl) {
123
+ if (opts.roleTrn) {
124
+ const cred = await fetchRemoteMetadataThenAssumeRole(opts.credentialsMetadataUrl, opts.roleTrn);
125
+ if (cred)
126
+ return cred;
127
+ }
128
+ else {
129
+ // Use metadata credentials directly (e.g. ECS instance role already bound)
130
+ const cred = await fetchRemoteMetadata(opts.credentialsMetadataUrl);
131
+ if (cred)
132
+ return cred;
133
+ }
118
134
  }
119
135
  const credPath = opts.credentialsFile ?? process.env[ENV_CRED_FILE] ?? DEFAULT_CRED_PATH;
120
136
  const resolvedPath = resolvePath(credPath);
@@ -21,6 +21,10 @@ export declare function buildAuthorizationUrl(params: {
21
21
  codeChallenge?: string;
22
22
  codeChallengeMethod?: string;
23
23
  nonce?: string;
24
+ /** Relay URI passed as redirect_relay_uri (same value as redirectUri). */
25
+ redirectRelayUri?: string;
26
+ /** Identity provider name passed as identity_provider query param. */
27
+ identityProvider?: string;
24
28
  }): string;
25
29
  /** Generate PKCE code_verifier and code_challenge (S256). */
26
30
  export declare function generatePKCE(): Promise<{
@@ -72,5 +76,12 @@ export declare function refreshAccessToken(params: {
72
76
  refresh_token?: string;
73
77
  expires_in?: number;
74
78
  }>;
75
- export declare function generateState(): Promise<string>;
79
+ /**
80
+ * Generate an opaque OIDC state value encoded as base64url(JSON).
81
+ * The JSON payload carries a random nonce for CSRF protection and an
82
+ * optional `target` (workload name) for the IdP to route back correctly.
83
+ */
84
+ export declare function generateState(params?: {
85
+ target?: string;
86
+ }): Promise<string>;
76
87
  //# sourceMappingURL=oidc-client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"oidc-client.d.ts","sourceRoot":"","sources":["../../../src/services/oidc-client.ts"],"names":[],"mappings":"AA4BA,uFAAuF;AACvF,eAAO,MAAM,kBAAkB,wCAAwC,CAAC;AAaxE,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,sBAAsB,EAAE,MAAM,CAAC;IAC/B,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,wBAAwB,CAAC,EAAE,MAAM,EAAE,CAAC;CACrC,CAAC;AAEF,wBAAsB,kBAAkB,CACtC,YAAY,EAAE,MAAM,EACpB,SAAS,SAAS,GACjB,OAAO,CAAC,aAAa,CAAC,CAoBxB;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE;IAC5C,qBAAqB,EAAE,MAAM,CAAC;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,MAAM,CA8BT;AAED,6DAA6D;AAC7D,wBAAsB,YAAY,IAAI,OAAO,CAAC;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,CAAC,CAK7F;AAED,wBAAsB,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,CAGrD;AAED,wBAAsB,qBAAqB,CAAC,MAAM,EAAE;IAClD,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,GAAG,OAAO,CAAC;IACV,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC,CA6CD;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,yEAAyE;IACzE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF;;;;;GAKG;AACH,wBAAsB,aAAa,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CA0B7F;AAED,yDAAyD;AACzD,wBAAsB,kBAAkB,CAAC,MAAM,EAAE;IAC/C,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;CACtB,GAAG,OAAO,CAAC;IACV,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC,CAwCD;AAED,wBAAsB,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,CAGrD"}
1
+ {"version":3,"file":"oidc-client.d.ts","sourceRoot":"","sources":["../../../src/services/oidc-client.ts"],"names":[],"mappings":"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"}
@@ -57,7 +57,7 @@ export async function fetchOIDCDiscovery(discoveryUrl, timeoutMs = 10_000) {
57
57
  }
58
58
  }
59
59
  export function buildAuthorizationUrl(params) {
60
- const { authorizationEndpoint, clientId, redirectUri, scope = DEFAULT_OIDC_SCOPE, state, responseType = "code", codeChallenge, codeChallengeMethod, nonce, } = params;
60
+ const { authorizationEndpoint, clientId, redirectUri, scope = DEFAULT_OIDC_SCOPE, state, responseType = "code", codeChallenge, codeChallengeMethod, nonce, redirectRelayUri, identityProvider, } = params;
61
61
  const search = new URLSearchParams({
62
62
  response_type: responseType,
63
63
  client_id: clientId,
@@ -72,6 +72,12 @@ export function buildAuthorizationUrl(params) {
72
72
  if (nonce) {
73
73
  search.set("nonce", nonce);
74
74
  }
75
+ if (redirectRelayUri) {
76
+ search.set("redirect_relay_uri", redirectRelayUri);
77
+ }
78
+ if (identityProvider) {
79
+ search.set("identity_provider", identityProvider);
80
+ }
75
81
  const sep = authorizationEndpoint.includes("?") ? "&" : "?";
76
82
  return `${authorizationEndpoint}${sep}${search.toString()}`;
77
83
  }
@@ -192,7 +198,18 @@ export async function refreshAccessToken(params) {
192
198
  expires_in: typeof data.expires_in === "number" ? data.expires_in : undefined,
193
199
  };
194
200
  }
195
- export async function generateState() {
201
+ /**
202
+ * Generate an opaque OIDC state value encoded as base64url(JSON).
203
+ * The JSON payload carries a random nonce for CSRF protection and an
204
+ * optional `target` (workload name) for the IdP to route back correctly.
205
+ */
206
+ export async function generateState(params) {
196
207
  const { randomBytes } = await import("node:crypto");
197
- return randomBytes(32).toString("base64url");
208
+ const payload = {
209
+ nonce: randomBytes(32).toString("base64url"),
210
+ };
211
+ if (params?.target) {
212
+ payload.target = params.target;
213
+ }
214
+ return Buffer.from(JSON.stringify(payload)).toString("base64url");
198
215
  }
@@ -1,8 +1,18 @@
1
+ /**
2
+ * Session token refresh: when userToken expires, use refresh_token to get new tokens.
3
+ * Used by before_agent_start when GetWorkloadAccessTokenForJWT fails with "token has expired".
4
+ */
5
+ import type { SessionEntry } from "../store/session-store.js";
1
6
  export type OIDCConfigForRefresh = {
2
7
  discoveryUrl: string;
3
8
  clientId: string;
4
9
  clientSecret?: string;
5
10
  };
11
+ /**
12
+ * Get session, refreshing userToken proactively when it is expiring or expired and refreshToken exists.
13
+ * When getOidcConfigForRefresh is omitted, behaves like getSession.
14
+ */
15
+ export declare function getSessionWithRefresh(storeDir: string, sessionKey: string, getOidcConfigForRefresh?: () => Promise<OIDCConfigForRefresh>): Promise<SessionEntry | null>;
6
16
  /**
7
17
  * Refresh session userToken using refresh_token grant.
8
18
  * Updates session with new userToken (and rotated refresh_token if returned).
@@ -1 +1 @@
1
- {"version":3,"file":"session-refresh.d.ts","sourceRoot":"","sources":["../../../src/services/session-refresh.ts"],"names":[],"mappings":"AAwBA,MAAM,MAAM,oBAAoB,GAAG;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF;;;;GAIG;AACH,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,aAAa,EAAE,MAAM,OAAO,CAAC,oBAAoB,CAAC,GACjD,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAsCxB"}
1
+ {"version":3,"file":"session-refresh.d.ts","sourceRoot":"","sources":["../../../src/services/session-refresh.ts"],"names":[],"mappings":"AAgBA;;;GAGG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAI9D,MAAM,MAAM,oBAAoB,GAAG;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAUF;;;GAGG;AACH,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,uBAAuB,CAAC,EAAE,MAAM,OAAO,CAAC,oBAAoB,CAAC,GAC5D,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAqB9B;AAED;;;;GAIG;AACH,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,aAAa,EAAE,MAAM,OAAO,CAAC,oBAAoB,CAAC,GACjD,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA0CxB"}
@@ -13,12 +13,35 @@
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
15
15
  */
16
- /**
17
- * Session token refresh: when userToken expires, use refresh_token to get new tokens.
18
- * Used by before_agent_start when GetWorkloadAccessTokenForJWT fails with "token has expired".
19
- */
20
16
  import { getSession, setSession } from "../store/session-store.js";
21
17
  import { fetchOIDCDiscovery, refreshAccessToken, verifyIdToken } from "./oidc-client.js";
18
+ /** Default threshold: refresh when token expires within 5 minutes. */
19
+ const REFRESH_THRESHOLD_MS = 5 * 60 * 1000;
20
+ function isExpiringOrExpired(entry) {
21
+ if (!entry.expiresAt)
22
+ return false;
23
+ return entry.expiresAt - Date.now() < REFRESH_THRESHOLD_MS;
24
+ }
25
+ /**
26
+ * Get session, refreshing userToken proactively when it is expiring or expired and refreshToken exists.
27
+ * When getOidcConfigForRefresh is omitted, behaves like getSession.
28
+ */
29
+ export async function getSessionWithRefresh(storeDir, sessionKey, getOidcConfigForRefresh) {
30
+ const session = await getSession(storeDir, sessionKey);
31
+ if (!session)
32
+ return null;
33
+ if (!getOidcConfigForRefresh ||
34
+ !session.refreshToken ||
35
+ !isExpiringOrExpired(session)) {
36
+ return session;
37
+ }
38
+ const refreshed = await refreshSessionUserToken(storeDir, sessionKey, getOidcConfigForRefresh);
39
+ if (!refreshed) {
40
+ console.warn(`[agent-identity] getSessionWithRefresh: refresh failed, returning existing session for key=${sessionKey.slice(0, 36)}...`);
41
+ return session;
42
+ }
43
+ return getSession(storeDir, sessionKey);
44
+ }
22
45
  /**
23
46
  * Refresh session userToken using refresh_token grant.
24
47
  * Updates session with new userToken (and rotated refresh_token if returned).
@@ -56,7 +79,8 @@ export async function refreshSessionUserToken(storeDir, sessionKey, getOidcConfi
56
79
  });
57
80
  return userToken;
58
81
  }
59
- catch {
82
+ catch (err) {
83
+ console.warn(`[agent-identity] refreshSessionUserToken failed for key=${sessionKey.slice(0, 36)}...:`, err instanceof Error ? err.message : String(err));
60
84
  return null;
61
85
  }
62
86
  }
@@ -0,0 +1,35 @@
1
+ export type CredentialBinding = {
2
+ type: "sts";
3
+ provider: string;
4
+ useTip?: boolean;
5
+ /** [AK env, SK env, SessionToken env] */
6
+ env?: [string, string, string];
7
+ required?: boolean;
8
+ } | {
9
+ type: "apikey";
10
+ provider: string;
11
+ env: string;
12
+ required?: boolean;
13
+ } | {
14
+ type: "oauth";
15
+ provider: string;
16
+ flow?: "oauth2-user" | "oauth2-m2m";
17
+ env: string;
18
+ required?: boolean;
19
+ } | {
20
+ /** Workload TIP JWT from identity_get_tip_token. */
21
+ type: "tip";
22
+ env: string;
23
+ required?: boolean;
24
+ } | {
25
+ /** OIDC id_token (session / user token) from identity_get_session_token. */
26
+ type: "user";
27
+ env: string;
28
+ required?: boolean;
29
+ };
30
+ /**
31
+ * Parse frontmatter from SKILL.md content and extract credential bindings.
32
+ * Returns undefined if metadata is missing or identity bindings are empty.
33
+ */
34
+ export declare function parseIdentityBindingsFromSkillContent(content: string): CredentialBinding[] | undefined;
35
+ //# sourceMappingURL=skill-contract-metadata.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-contract-metadata.d.ts","sourceRoot":"","sources":["../../../src/services/skill-contract-metadata.ts"],"names":[],"mappings":"AA0BA,MAAM,MAAM,iBAAiB,GACzB;IACE,IAAI,EAAE,KAAK,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,yCAAyC;IACzC,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,GACD;IACE,IAAI,EAAE,QAAQ,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,GACD;IACE,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,aAAa,GAAG,YAAY,CAAC;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,GACD;IACE,oDAAoD;IACpD,IAAI,EAAE,KAAK,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,GACD;IACE,4EAA4E;IAC5E,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAiFN;;;GAGG;AACH,wBAAgB,qCAAqC,CACnD,OAAO,EAAE,MAAM,GACd,iBAAiB,EAAE,GAAG,SAAS,CAWjC"}
@@ -0,0 +1,145 @@
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
+ * Parse openclaw.identity from SKILL.md frontmatter metadata.
18
+ * Uses same approach as OpenClaw: extract block + YAML.parse, then resolve metadata.
19
+ * Supports metadata as JSON5 string or YAML-parsed object.
20
+ * identity can be a direct array or identity.bindings for backward compat.
21
+ */
22
+ import YAML from "yaml";
23
+ import JSON5 from "json5";
24
+ const DEFAULT_ROLE_STS_ENV = [
25
+ "VOLCENGINE_ACCESS_KEY",
26
+ "VOLCENGINE_SECRET_KEY",
27
+ "VOLCENGINE_SESSION_TOKEN",
28
+ ];
29
+ function getMetadataObject(frontmatter) {
30
+ const raw = frontmatter.metadata;
31
+ if (typeof raw === "string") {
32
+ try {
33
+ const parsed = JSON5.parse(raw);
34
+ return parsed && typeof parsed === "object" ? parsed : undefined;
35
+ }
36
+ catch {
37
+ return undefined;
38
+ }
39
+ }
40
+ if (raw && typeof raw === "object") {
41
+ return raw;
42
+ }
43
+ return undefined;
44
+ }
45
+ function extractIdentityBindings(metadataObj) {
46
+ const openclaw = metadataObj.openclaw;
47
+ if (!openclaw || typeof openclaw !== "object")
48
+ return undefined;
49
+ const identity = openclaw.identity;
50
+ if (Array.isArray(identity)) {
51
+ return identity.filter(isValidCredentialBinding);
52
+ }
53
+ if (identity && typeof identity === "object") {
54
+ const bindings = identity.bindings;
55
+ if (Array.isArray(bindings)) {
56
+ return bindings.filter(isValidCredentialBinding);
57
+ }
58
+ }
59
+ return undefined;
60
+ }
61
+ function isValidCredentialBinding(x) {
62
+ if (!x || typeof x !== "object")
63
+ return false;
64
+ const o = x;
65
+ const type = o.type;
66
+ if (type === "tip" || type === "user") {
67
+ return typeof o.env === "string" && Boolean(o.env.trim());
68
+ }
69
+ if (type !== "sts" && type !== "apikey" && type !== "oauth")
70
+ return false;
71
+ if (typeof o.provider !== "string" || !o.provider.trim())
72
+ return false;
73
+ if (type === "sts") {
74
+ if (o.env != null && !Array.isArray(o.env))
75
+ return false;
76
+ if (Array.isArray(o.env) && o.env.length !== 3)
77
+ return false;
78
+ }
79
+ else {
80
+ if (typeof o.env !== "string" || !o.env.trim())
81
+ return false;
82
+ }
83
+ return true;
84
+ }
85
+ function normalizeBinding(b) {
86
+ if (b.type === "tip" || b.type === "user") {
87
+ return { ...b, required: b.required ?? false };
88
+ }
89
+ if (b.type === "sts") {
90
+ const env = Array.isArray(b.env) && b.env.length === 3
91
+ ? b.env
92
+ : DEFAULT_ROLE_STS_ENV;
93
+ return {
94
+ type: "sts",
95
+ provider: b.provider,
96
+ useTip: b.useTip ?? true,
97
+ env,
98
+ required: b.required ?? false,
99
+ };
100
+ }
101
+ return {
102
+ ...b,
103
+ required: b.required ?? false,
104
+ };
105
+ }
106
+ /**
107
+ * Parse frontmatter from SKILL.md content and extract credential bindings.
108
+ * Returns undefined if metadata is missing or identity bindings are empty.
109
+ */
110
+ export function parseIdentityBindingsFromSkillContent(content) {
111
+ const frontmatter = parseFrontmatter(content);
112
+ if (!frontmatter)
113
+ return undefined;
114
+ const metadataObj = getMetadataObject(frontmatter);
115
+ if (!metadataObj)
116
+ return undefined;
117
+ const bindings = extractIdentityBindings(metadataObj);
118
+ if (!bindings || bindings.length === 0)
119
+ return undefined;
120
+ return bindings.map(normalizeBinding);
121
+ }
122
+ /** Extract frontmatter block between --- delimiters (same as OpenClaw markdown/frontmatter). */
123
+ function extractFrontmatterBlock(content) {
124
+ const normalized = content.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
125
+ if (!normalized.startsWith("---"))
126
+ return undefined;
127
+ const endIndex = normalized.indexOf("\n---", 3);
128
+ if (endIndex === -1)
129
+ return undefined;
130
+ return normalized.slice(4, endIndex);
131
+ }
132
+ function parseFrontmatter(content) {
133
+ const block = extractFrontmatterBlock(content);
134
+ if (!block)
135
+ return undefined;
136
+ try {
137
+ const parsed = YAML.parse(block, { schema: "core" });
138
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed)
139
+ ? parsed
140
+ : undefined;
141
+ }
142
+ catch {
143
+ return undefined;
144
+ }
145
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Render Identity Credential Runtime Contract from credential bindings,
3
+ * and patch toolResult messages with the rendered contract section.
4
+ */
5
+ import type { CredentialBinding } from "./skill-contract-metadata.js";
6
+ export declare function renderContractSection(bindings: CredentialBinding[]): string;
7
+ type AgentMessage = {
8
+ role?: string;
9
+ content?: unknown;
10
+ [k: string]: unknown;
11
+ };
12
+ export declare function patchToolResultContent(message: AgentMessage, contractText: string): AgentMessage;
13
+ export {};
14
+ //# sourceMappingURL=skill-contract-renderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-contract-renderer.d.ts","sourceRoot":"","sources":["../../../src/services/skill-contract-renderer.ts"],"names":[],"mappings":"AAgBA;;;GAGG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAMtE,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,iBAAiB,EAAE,GAAG,MAAM,CAwF3E;AAID,KAAK,YAAY,GAAG;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB,CAAC;AAEF,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,YAAY,EACrB,YAAY,EAAE,MAAM,GACnB,YAAY,CAgCd"}
@@ -0,0 +1,120 @@
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
+ const CONTRACT_MARKER = "<!-- identity-contract-injected -->";
17
+ // ─── Render contract text from bindings ──────────────────────────────
18
+ export function renderContractSection(bindings) {
19
+ if (!bindings.length)
20
+ return "";
21
+ const roleStsLines = [];
22
+ const apikeyLines = [];
23
+ const oauthLines = [];
24
+ const tipLines = [];
25
+ const userSessionLines = [];
26
+ for (const b of bindings) {
27
+ if (b.type === "sts") {
28
+ const [ak, sk, st] = b.env ?? [
29
+ "VOLCENGINE_ACCESS_KEY",
30
+ "VOLCENGINE_SECRET_KEY",
31
+ "VOLCENGINE_SESSION_TOKEN",
32
+ ];
33
+ roleStsLines.push(`- Call \`identity_get_role_credentials(provider="${b.provider}", useTip=${b.useTip ?? true})\`.`, ` Map result fields to env: \`credentials.AccessKeyId\` -> \`${ak}\`, \`credentials.SecretAccessKey\` -> \`${sk}\`, \`credentials.SessionToken\` -> \`${st}\`.`, b.required ? ` Required: if fetch fails, do not continue with private API calls.` : "");
34
+ }
35
+ else if (b.type === "apikey") {
36
+ apikeyLines.push(`- Call \`identity_fetch(provider="${b.provider}", flow="apikey", returnValue=true)\`.`, ` Map returned value to env: \`${b.env}\`.`, b.required ? ` Required: if fetch fails, do not continue.` : "");
37
+ }
38
+ else if (b.type === "oauth") {
39
+ const flow = b.flow ?? "oauth2-user";
40
+ oauthLines.push(`- Call \`identity_fetch(provider="${b.provider}", flow="${flow}", returnValue=true)\`.`, ` Map access token to env: \`${b.env}\`.`, b.required ? ` Required: if fetch fails, do not continue.` : "");
41
+ }
42
+ else if (b.type === "tip") {
43
+ tipLines.push(`- Call \`identity_get_tip_token()\`.`, ` Map result field \`tipToken\` to env: \`${b.env}\`.`, b.required ? ` Required: if the call fails, do not continue with private API calls.` : "");
44
+ }
45
+ else if (b.type === "user") {
46
+ userSessionLines.push(`- Call \`identity_get_session_token()\`.`, ` Map result field \`sessionIdToken\` (OIDC id_token) to env: \`${b.env}\`.`, b.required ? ` Required: if the call fails, do not continue.` : "");
47
+ }
48
+ }
49
+ const sections = [];
50
+ if (roleStsLines.length) {
51
+ sections.push("**Role STS**\n" + roleStsLines.filter(Boolean).join("\n"));
52
+ }
53
+ if (apikeyLines.length) {
54
+ sections.push("**API Key**\n" + apikeyLines.filter(Boolean).join("\n"));
55
+ }
56
+ if (oauthLines.length) {
57
+ sections.push("**OAuth**\n" + oauthLines.filter(Boolean).join("\n"));
58
+ }
59
+ if (tipLines.length) {
60
+ sections.push("**TIP (workload token)**\n" + tipLines.filter(Boolean).join("\n"));
61
+ }
62
+ if (userSessionLines.length) {
63
+ sections.push("**User session (OIDC id_token)**\n" + userSessionLines.filter(Boolean).join("\n"));
64
+ }
65
+ const executionFlow = sections.length
66
+ ? sections.join("\n\n")
67
+ : "No credential bindings.";
68
+ return `${CONTRACT_MARKER}
69
+
70
+ ## Identity Credential Runtime Contract
71
+
72
+ ### Agent Rules
73
+ - Before any private API operation requiring credentials, call the identity tools as specified below.
74
+ - Never ask users to provide credentials manually.
75
+ - Never print credential values (AccessKeyId, SecretAccessKey, SessionToken, tokens) in chat output.
76
+ - Never put secrets directly into command strings.
77
+
78
+ ### Execution Flow
79
+ ${executionFlow}
80
+
81
+ ### Failure Handling
82
+ - If a required credential fetch fails, do not continue with private API calls.
83
+ - If the execution tool does not support secure env injection, stop and report unsupported secure runtime.
84
+ `;
85
+ }
86
+ export function patchToolResultContent(message, contractText) {
87
+ if (message.role !== "toolResult")
88
+ return message;
89
+ const content = message.content;
90
+ if (content == null)
91
+ return message;
92
+ const existingText = extractTextFromContent(content);
93
+ if (existingText && existingText.includes(CONTRACT_MARKER))
94
+ return message;
95
+ const suffix = `\n\n---\n\n${contractText}`;
96
+ if (typeof content === "string") {
97
+ return { ...message, content: content + suffix };
98
+ }
99
+ if (Array.isArray(content)) {
100
+ const textBlock = content.find((b) => b && typeof b === "object" && b.type === "text");
101
+ if (textBlock && typeof textBlock.text === "string") {
102
+ const newContent = content.map((b) => b === textBlock ? { ...textBlock, text: textBlock.text + suffix } : b);
103
+ return { ...message, content: newContent };
104
+ }
105
+ return {
106
+ ...message,
107
+ content: [...content, { type: "text", text: suffix.trimStart() }],
108
+ };
109
+ }
110
+ return message;
111
+ }
112
+ function extractTextFromContent(content) {
113
+ if (typeof content === "string")
114
+ return content;
115
+ if (Array.isArray(content)) {
116
+ const textBlock = content.find((b) => b && typeof b === "object" && b.type === "text");
117
+ return textBlock?.text;
118
+ }
119
+ return undefined;
120
+ }
@@ -2,6 +2,7 @@
2
2
  * Shared TIP propagation logic for sessions_send and sessions_spawn.
3
3
  */
4
4
  import type { IdentityService } from "./identity-service.js";
5
+ import type { OIDCConfigForRefresh } from "./session-refresh.js";
5
6
  import type { TIPTokenEntry } from "../store/tip-store.js";
6
7
  export type PropagateTIPParams = {
7
8
  storeDir: string;
@@ -11,6 +12,7 @@ export type PropagateTIPParams = {
11
12
  configWorkloadName?: string;
12
13
  subagentTipPropagation?: boolean;
13
14
  ctxAgentId?: string;
15
+ getOidcConfigForRefresh?: () => Promise<OIDCConfigForRefresh>;
14
16
  getCallerTIP: () => Promise<TIPTokenEntry | null>;
15
17
  logger: {
16
18
  info?: (msg: string) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"tip-propagation.d.ts","sourceRoot":"","sources":["../../../src/services/tip-propagation.ts"],"names":[],"mappings":"AAgBA;;GAEG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAM3D,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,eAAe,CAAC;IACjC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;IAClD,MAAM,EAAE;QAAE,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QAAC,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE,CAAC;CACzE,CAAC;AAEF;;;GAGG;AACH,wBAAsB,oBAAoB,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CA0CpF"}
1
+ {"version":3,"file":"tip-propagation.d.ts","sourceRoot":"","sources":["../../../src/services/tip-propagation.ts"],"names":[],"mappings":"AAgBA;;GAEG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAO3D,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,eAAe,CAAC;IACjC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uBAAuB,CAAC,EAAE,MAAM,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAC9D,YAAY,EAAE,MAAM,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;IAClD,MAAM,EAAE;QAAE,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QAAC,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE,CAAC;CACzE,CAAC;AAEF;;;GAGG;AACH,wBAAsB,oBAAoB,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CA2CpF"}
@@ -13,7 +13,8 @@
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
15
15
  */
16
- import { getSession, setSession } from "../store/session-store.js";
16
+ import { setSession } from "../store/session-store.js";
17
+ import { getSessionWithRefresh } from "./session-refresh.js";
17
18
  import { setTIPToken } from "../store/tip-store.js";
18
19
  import { logDebug, logInfo } from "../utils/logger.js";
19
20
  import { fetchAndStoreTIP } from "./tip-acquisition.js";
@@ -22,7 +23,7 @@ import { fetchAndStoreTIP } from "./tip-acquisition.js";
22
23
  * Uses getCallerTIP() to obtain caller's TIP (supports refresh).
23
24
  */
24
25
  export async function propagateTIPToTarget(params) {
25
- const { storeDir, callerSessionKey, targetSessionKey, identityService, configWorkloadName, subagentTipPropagation, ctxAgentId, getCallerTIP, logger, } = params;
26
+ const { storeDir, callerSessionKey, targetSessionKey, identityService, configWorkloadName, subagentTipPropagation, ctxAgentId, getOidcConfigForRefresh, getCallerTIP, logger, } = params;
26
27
  const callerTIP = await getCallerTIP();
27
28
  if (!callerTIP) {
28
29
  logDebug(logger, `propagation skip (caller ${callerSessionKey.slice(0, 24)}... has no TIP)`);
@@ -47,7 +48,7 @@ export async function propagateTIPToTarget(params) {
47
48
  });
48
49
  logDebug(logger, `TIP passed through to ${targetSessionKey.slice(0, 24)}...`);
49
50
  }
50
- const callerSession = await getSession(storeDir, callerSessionKey);
51
+ const callerSession = await getSessionWithRefresh(storeDir, callerSessionKey, getOidcConfigForRefresh);
51
52
  if (callerSession) {
52
53
  await setSession(storeDir, targetSessionKey, callerSession);
53
54
  }
@@ -22,7 +22,7 @@ export type GetOrRefreshTIPOptions = {
22
22
  };
23
23
  /**
24
24
  * Get TIP token for session. If missing or expired and refresh options provided,
25
- * attempts to fetch TIP (refreshing userToken if needed).
25
+ * attempts to fetch TIP (refreshing userToken if needed, with one retry).
26
26
  */
27
27
  export declare function getOrRefreshTIPToken(storeDir: string, sessionKey: string, options?: GetOrRefreshTIPOptions): Promise<ReturnType<typeof getTIPToken>>;
28
28
  //# sourceMappingURL=tip-with-refresh.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tip-with-refresh.d.ts","sourceRoot":"","sources":["../../../src/services/tip-with-refresh.ts"],"names":[],"mappings":"AAgBA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAEjE,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAMpD,MAAM,MAAM,sBAAsB,GAAG;IACnC,eAAe,EAAE,eAAe,CAAC;IACjC,uBAAuB,CAAC,EAAE,MAAM,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAC9D,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QAAC,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE,CAAC;IACzE,uFAAuF;IACvF,WAAW,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;CACnC,CAAC;AAEF;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,OAAO,CAAC,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC,CAgEzC"}
1
+ {"version":3,"file":"tip-with-refresh.d.ts","sourceRoot":"","sources":["../../../src/services/tip-with-refresh.ts"],"names":[],"mappings":"AAgBA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAEjE,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAKpD,MAAM,MAAM,sBAAsB,GAAG;IACnC,eAAe,EAAE,eAAe,CAAC;IACjC,uBAAuB,CAAC,EAAE,MAAM,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAC9D,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QAAC,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE,CAAC;IACzE,uFAAuF;IACvF,WAAW,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;CACnC,CAAC;AAEF;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,OAAO,CAAC,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC,CA8CzC"}