@kya-os/mcp-i 1.6.13 → 1.6.15
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/dist/cli-adapter/index.js +23 -4
- package/dist/runtime/adapter-express.js +3 -3
- package/dist/runtime/adapter-nextjs.js +3 -3
- package/dist/runtime/auth-handshake.d.ts +5 -5
- package/dist/runtime/auth-handshake.js +31 -31
- package/dist/runtime/delegation-hooks.d.ts +1 -1
- package/dist/runtime/delegation-hooks.js +36 -8
- package/dist/runtime/delegation-verifier-agentshield.js +8 -6
- package/dist/runtime/delegation-verifier-kv.d.ts +2 -2
- package/dist/runtime/delegation-verifier-kv.js +24 -18
- package/dist/runtime/delegation-verifier-memory.d.ts +2 -2
- package/dist/runtime/delegation-verifier-memory.js +11 -7
- package/dist/runtime/http.js +3 -3
- package/dist/runtime/mcpi-runtime-wrapper.js +1 -1
- package/dist/runtime/migrate-identity.js +6 -6
- package/dist/runtime/proof-batch-queue.d.ts +1 -1
- package/dist/runtime/proof-batch-queue.js +24 -21
- package/dist/runtime/stdio.js +3 -3
- package/dist/runtime/transports/http/stateless-streamable-http.js +9 -9
- package/dist/storage/encryption.js +3 -2
- package/package.json +3 -3
|
@@ -16,9 +16,9 @@
|
|
|
16
16
|
*
|
|
17
17
|
* Related: PHASE_1_XMCP_I_SERVER.md Epic 2 (Runtime Interceptor)
|
|
18
18
|
*/
|
|
19
|
-
import { NeedsAuthorizationError } from
|
|
20
|
-
import { DelegationVerifier } from
|
|
21
|
-
import { DelegationRecord } from
|
|
19
|
+
import { NeedsAuthorizationError } from "@kya-os/contracts/runtime";
|
|
20
|
+
import { DelegationVerifier } from "./delegation-verifier";
|
|
21
|
+
import { DelegationRecord } from "@kya-os/contracts/delegation";
|
|
22
22
|
/**
|
|
23
23
|
* Agent reputation data from KTA
|
|
24
24
|
*/
|
|
@@ -32,7 +32,7 @@ export interface AgentReputation {
|
|
|
32
32
|
/** Success rate (0-1) */
|
|
33
33
|
successRate: number;
|
|
34
34
|
/** Risk level assessment */
|
|
35
|
-
riskLevel:
|
|
35
|
+
riskLevel: "low" | "medium" | "high" | "unknown";
|
|
36
36
|
/** Last updated timestamp */
|
|
37
37
|
updatedAt: number;
|
|
38
38
|
}
|
|
@@ -77,7 +77,7 @@ export interface VerifyOrHintsResult {
|
|
|
77
77
|
user_did: string;
|
|
78
78
|
scopes: string[];
|
|
79
79
|
authorization: {
|
|
80
|
-
type:
|
|
80
|
+
type: "oauth" | "credential" | "none";
|
|
81
81
|
provider?: string;
|
|
82
82
|
credentialType?: string;
|
|
83
83
|
};
|
|
@@ -84,7 +84,7 @@ exports.MemoryResumeTokenStore = MemoryResumeTokenStore;
|
|
|
84
84
|
async function verifyOrHints(agentDid, scopes, config, _resumeToken) {
|
|
85
85
|
const startTime = Date.now();
|
|
86
86
|
if (config.debug) {
|
|
87
|
-
console.
|
|
87
|
+
console.error(`[AuthHandshake] Verifying ${agentDid} for scopes: ${scopes.join(", ")}`);
|
|
88
88
|
}
|
|
89
89
|
// Step 1: Check reputation (optional, if KTA configured)
|
|
90
90
|
let reputation;
|
|
@@ -92,25 +92,25 @@ async function verifyOrHints(agentDid, scopes, config, _resumeToken) {
|
|
|
92
92
|
try {
|
|
93
93
|
reputation = await fetchAgentReputation(agentDid, config.kta);
|
|
94
94
|
if (config.debug) {
|
|
95
|
-
console.
|
|
95
|
+
console.error(`[AuthHandshake] Reputation score: ${reputation.score}`);
|
|
96
96
|
}
|
|
97
97
|
// If reputation is too low, require authorization
|
|
98
98
|
if (reputation.score < config.bouncer.minReputationScore) {
|
|
99
99
|
if (config.debug) {
|
|
100
|
-
console.
|
|
100
|
+
console.error(`[AuthHandshake] Reputation ${reputation.score} < ${config.bouncer.minReputationScore}, requiring authorization`);
|
|
101
101
|
}
|
|
102
|
-
const authError = await buildNeedsAuthorizationError(agentDid, scopes, config,
|
|
102
|
+
const authError = await buildNeedsAuthorizationError(agentDid, scopes, config, "Agent reputation score below threshold");
|
|
103
103
|
return {
|
|
104
104
|
authorized: false,
|
|
105
105
|
authError,
|
|
106
106
|
reputation,
|
|
107
|
-
reason:
|
|
107
|
+
reason: "Low reputation score",
|
|
108
108
|
};
|
|
109
109
|
}
|
|
110
110
|
}
|
|
111
111
|
catch (error) {
|
|
112
112
|
// Don't fail hard on reputation check failure
|
|
113
|
-
console.warn(
|
|
113
|
+
console.warn("[AuthHandshake] Failed to check reputation:", error);
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
116
|
// Step 2: Check for existing delegation
|
|
@@ -119,8 +119,8 @@ async function verifyOrHints(agentDid, scopes, config, _resumeToken) {
|
|
|
119
119
|
delegationResult = await config.delegationVerifier.verify(agentDid, scopes);
|
|
120
120
|
}
|
|
121
121
|
catch (error) {
|
|
122
|
-
console.error(
|
|
123
|
-
const errorMessage = `Delegation verification error: ${error instanceof Error ? error.message :
|
|
122
|
+
console.error("[AuthHandshake] Delegation verification failed:", error);
|
|
123
|
+
const errorMessage = `Delegation verification error: ${error instanceof Error ? error.message : "Unknown error"}`;
|
|
124
124
|
const authError = await buildNeedsAuthorizationError(agentDid, scopes, config, errorMessage);
|
|
125
125
|
return {
|
|
126
126
|
authorized: false,
|
|
@@ -131,26 +131,26 @@ async function verifyOrHints(agentDid, scopes, config, _resumeToken) {
|
|
|
131
131
|
// Step 3: If delegation exists and valid, authorize immediately
|
|
132
132
|
if (delegationResult.valid && delegationResult.delegation) {
|
|
133
133
|
if (config.debug) {
|
|
134
|
-
console.
|
|
134
|
+
console.error(`[AuthHandshake] Delegation valid, authorized (${Date.now() - startTime}ms)`);
|
|
135
135
|
}
|
|
136
136
|
return {
|
|
137
137
|
authorized: true,
|
|
138
138
|
delegation: delegationResult.delegation,
|
|
139
139
|
credential: delegationResult.credential, // Include credential for auth method validation
|
|
140
140
|
reputation,
|
|
141
|
-
reason:
|
|
141
|
+
reason: "Valid delegation found",
|
|
142
142
|
};
|
|
143
143
|
}
|
|
144
144
|
// Step 4: No delegation found - return needs_authorization error
|
|
145
145
|
if (config.debug) {
|
|
146
|
-
console.
|
|
146
|
+
console.error(`[AuthHandshake] No delegation found, returning needs_authorization (${Date.now() - startTime}ms)`);
|
|
147
147
|
}
|
|
148
|
-
const authError = await buildNeedsAuthorizationError(agentDid, scopes, config, delegationResult.reason ||
|
|
148
|
+
const authError = await buildNeedsAuthorizationError(agentDid, scopes, config, delegationResult.reason || "No valid delegation found");
|
|
149
149
|
return {
|
|
150
150
|
authorized: false,
|
|
151
151
|
authError,
|
|
152
152
|
reputation,
|
|
153
|
-
reason: delegationResult.reason ||
|
|
153
|
+
reason: delegationResult.reason || "No delegation",
|
|
154
154
|
};
|
|
155
155
|
}
|
|
156
156
|
/**
|
|
@@ -161,15 +161,15 @@ async function verifyOrHints(agentDid, scopes, config, _resumeToken) {
|
|
|
161
161
|
* @returns Agent reputation data
|
|
162
162
|
*/
|
|
163
163
|
async function fetchAgentReputation(agentDid, ktaConfig) {
|
|
164
|
-
const apiUrl = ktaConfig.apiUrl.replace(/\/$/,
|
|
164
|
+
const apiUrl = ktaConfig.apiUrl.replace(/\/$/, "");
|
|
165
165
|
const headers = {
|
|
166
|
-
|
|
166
|
+
"Content-Type": "application/json",
|
|
167
167
|
};
|
|
168
168
|
if (ktaConfig.apiKey) {
|
|
169
|
-
headers[
|
|
169
|
+
headers["X-API-Key"] = ktaConfig.apiKey;
|
|
170
170
|
}
|
|
171
171
|
const response = await fetch(`${apiUrl}/api/v1/reputation/${encodeURIComponent(agentDid)}`, {
|
|
172
|
-
method:
|
|
172
|
+
method: "GET",
|
|
173
173
|
headers,
|
|
174
174
|
});
|
|
175
175
|
if (!response.ok) {
|
|
@@ -180,7 +180,7 @@ async function fetchAgentReputation(agentDid, ktaConfig) {
|
|
|
180
180
|
score: 50, // Neutral score
|
|
181
181
|
totalInteractions: 0,
|
|
182
182
|
successRate: 0,
|
|
183
|
-
riskLevel:
|
|
183
|
+
riskLevel: "unknown",
|
|
184
184
|
updatedAt: Date.now(),
|
|
185
185
|
};
|
|
186
186
|
}
|
|
@@ -192,7 +192,7 @@ async function fetchAgentReputation(agentDid, ktaConfig) {
|
|
|
192
192
|
score: data.score || 50,
|
|
193
193
|
totalInteractions: data.totalInteractions || 0,
|
|
194
194
|
successRate: data.successRate || 0,
|
|
195
|
-
riskLevel: data.riskLevel ||
|
|
195
|
+
riskLevel: data.riskLevel || "unknown",
|
|
196
196
|
updatedAt: data.updatedAt || Date.now(),
|
|
197
197
|
};
|
|
198
198
|
}
|
|
@@ -213,15 +213,15 @@ async function buildNeedsAuthorizationError(agentDid, scopes, config, message) {
|
|
|
213
213
|
const expiresAt = Date.now() + (config.bouncer.resumeTokenTtl || 600_000);
|
|
214
214
|
// Build authorization URL
|
|
215
215
|
const authUrl = new URL(config.bouncer.authorizationUrl);
|
|
216
|
-
authUrl.searchParams.set(
|
|
217
|
-
authUrl.searchParams.set(
|
|
218
|
-
authUrl.searchParams.set(
|
|
216
|
+
authUrl.searchParams.set("agent_did", agentDid);
|
|
217
|
+
authUrl.searchParams.set("scopes", scopes.join(","));
|
|
218
|
+
authUrl.searchParams.set("resume_token", resumeToken);
|
|
219
219
|
// Generate short authorization code (for display)
|
|
220
220
|
const authCode = resumeToken.substring(0, 8).toUpperCase();
|
|
221
221
|
// Build display hints
|
|
222
222
|
const display = {
|
|
223
|
-
title:
|
|
224
|
-
hint: [
|
|
223
|
+
title: "Authorization Required",
|
|
224
|
+
hint: ["link", "qr"],
|
|
225
225
|
authorizationCode: authCode,
|
|
226
226
|
qrUrl: `https://chart.googleapis.com/chart?cht=qr&chs=300x300&chl=${encodeURIComponent(authUrl.toString())}`,
|
|
227
227
|
};
|
|
@@ -242,13 +242,13 @@ async function buildNeedsAuthorizationError(agentDid, scopes, config, message) {
|
|
|
242
242
|
*/
|
|
243
243
|
function hasSensitiveScopes(scopes) {
|
|
244
244
|
const sensitivePatterns = [
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
245
|
+
"write",
|
|
246
|
+
"delete",
|
|
247
|
+
"admin",
|
|
248
|
+
"payment",
|
|
249
|
+
"transfer",
|
|
250
|
+
"execute",
|
|
251
|
+
"modify",
|
|
252
252
|
];
|
|
253
253
|
return scopes.some((scope) => sensitivePatterns.some((pattern) => scope.toLowerCase().includes(pattern)));
|
|
254
254
|
}
|
|
@@ -33,7 +33,7 @@ export declare class DefaultDelegationHooks implements DelegationHooks {
|
|
|
33
33
|
constructor(delegationManager: DelegationManager, options?: DelegationHookOptions);
|
|
34
34
|
beforeProof(meta: Partial<ProofMeta>): Promise<Partial<ProofMeta>>;
|
|
35
35
|
afterProof(meta: ProofMeta): Promise<void>;
|
|
36
|
-
resolveDelegation(
|
|
36
|
+
resolveDelegation(context: RequestContext): Promise<string | undefined>;
|
|
37
37
|
}
|
|
38
38
|
export interface DelegationHookOptions {
|
|
39
39
|
/**
|
|
@@ -52,14 +52,42 @@ class DefaultDelegationHooks {
|
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
|
-
async resolveDelegation(
|
|
56
|
-
//
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
55
|
+
async resolveDelegation(context) {
|
|
56
|
+
// Implement delegation resolution logic to reuse existing chains
|
|
57
|
+
try {
|
|
58
|
+
// 1. Look up active delegations for the DID (subject)
|
|
59
|
+
const delegations = await this.delegationManager.listBySubject(context.did);
|
|
60
|
+
if (!delegations || delegations.length === 0) {
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
// 2. Filter by audience and scopes
|
|
64
|
+
// We want to find a delegation that satisfies ALL required scopes and matches the audience
|
|
65
|
+
const validDelegation = delegations.find((d) => {
|
|
66
|
+
// Check audience if context specifies one
|
|
67
|
+
if (context.audience && d.aud && d.aud !== context.audience) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
// Check scopes if context specifies them
|
|
71
|
+
if (context.scopes && context.scopes.length > 0) {
|
|
72
|
+
const hasAllScopes = context.scopes.every((scope) => d.scopes.includes(scope));
|
|
73
|
+
if (!hasAllScopes)
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
// Check expiry (redundant with isActive check but good for safety)
|
|
77
|
+
const now = Math.floor(Date.now() / 1000);
|
|
78
|
+
if (d.exp < now)
|
|
79
|
+
return false;
|
|
80
|
+
if (d.nbf && d.nbf > now)
|
|
81
|
+
return false;
|
|
82
|
+
return true;
|
|
83
|
+
});
|
|
84
|
+
// 3. Return the best match
|
|
85
|
+
return validDelegation?.delegationRef;
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
console.warn("Failed to resolve delegation:", error);
|
|
89
|
+
return undefined;
|
|
90
|
+
}
|
|
63
91
|
}
|
|
64
92
|
}
|
|
65
93
|
exports.DefaultDelegationHooks = DefaultDelegationHooks;
|
|
@@ -93,7 +93,9 @@ class AgentShieldAPIDelegationVerifier {
|
|
|
93
93
|
baseUrl: this.apiUrl,
|
|
94
94
|
apiKey: this.apiKey,
|
|
95
95
|
fetchProvider,
|
|
96
|
-
logger: this.debug
|
|
96
|
+
logger: this.debug
|
|
97
|
+
? (msg, data) => console.error(`[AgentShield] ${msg}`, data)
|
|
98
|
+
: undefined,
|
|
97
99
|
});
|
|
98
100
|
}
|
|
99
101
|
/**
|
|
@@ -121,14 +123,14 @@ class AgentShieldAPIDelegationVerifier {
|
|
|
121
123
|
const cached = this.cache.get(cacheKey);
|
|
122
124
|
if (cached) {
|
|
123
125
|
if (this.debug) {
|
|
124
|
-
console.
|
|
126
|
+
console.error(`[AgentShield] Cache HIT for ${agentDid} (${Date.now() - startTime}ms)`);
|
|
125
127
|
}
|
|
126
128
|
return { ...cached, cached: true };
|
|
127
129
|
}
|
|
128
130
|
}
|
|
129
131
|
// Slow path: API call
|
|
130
132
|
if (this.debug) {
|
|
131
|
-
console.
|
|
133
|
+
console.error(`[AgentShield] Cache MISS for ${agentDid}, calling API...`);
|
|
132
134
|
}
|
|
133
135
|
try {
|
|
134
136
|
// Validate request input using contracts schema
|
|
@@ -153,7 +155,7 @@ class AgentShieldAPIDelegationVerifier {
|
|
|
153
155
|
const ttl = data.valid ? this.cacheTtl : this.cacheTtl / 2;
|
|
154
156
|
this.cache.set(cacheKey, result, ttl);
|
|
155
157
|
if (this.debug) {
|
|
156
|
-
console.
|
|
158
|
+
console.error(`[AgentShield] Delegation ${data.valid ? "verified" : "rejected"} (${Date.now() - startTime}ms)`);
|
|
157
159
|
}
|
|
158
160
|
return result;
|
|
159
161
|
}
|
|
@@ -240,7 +242,7 @@ class AgentShieldAPIDelegationVerifier {
|
|
|
240
242
|
this.cache.delete(`delegation:${delegation.id}`);
|
|
241
243
|
this.cache.delete(`verify:${delegation.subjectDid}:${scopesKey}`);
|
|
242
244
|
if (this.debug) {
|
|
243
|
-
console.
|
|
245
|
+
console.error(`[AgentShield] Stored delegation ${delegation.id}`);
|
|
244
246
|
}
|
|
245
247
|
}
|
|
246
248
|
catch (error) {
|
|
@@ -267,7 +269,7 @@ class AgentShieldAPIDelegationVerifier {
|
|
|
267
269
|
// Invalidate cache
|
|
268
270
|
this.cache.delete(`delegation:${delegationId}`);
|
|
269
271
|
if (this.debug) {
|
|
270
|
-
console.
|
|
272
|
+
console.error(`[AgentShield] Revoked delegation ${delegationId}`);
|
|
271
273
|
}
|
|
272
274
|
}
|
|
273
275
|
catch (error) {
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
*
|
|
16
16
|
* Related: PHASE_1_XMCP_I_SERVER.md Ticket 1.2
|
|
17
17
|
*/
|
|
18
|
-
import { DelegationRecord } from
|
|
19
|
-
import { DelegationVerifier, DelegationVerifierConfig, VerifyDelegationResult, VerifyDelegationOptions } from
|
|
18
|
+
import { DelegationRecord } from "@kya-os/contracts/delegation";
|
|
19
|
+
import { DelegationVerifier, DelegationVerifierConfig, VerifyDelegationResult, VerifyDelegationOptions } from "./delegation-verifier";
|
|
20
20
|
/**
|
|
21
21
|
* Cloudflare KV Delegation Verifier
|
|
22
22
|
*
|
|
@@ -72,7 +72,7 @@ class CloudflareKVDelegationVerifier {
|
|
|
72
72
|
debug;
|
|
73
73
|
constructor(config) {
|
|
74
74
|
if (!config.kvNamespace) {
|
|
75
|
-
throw new Error(
|
|
75
|
+
throw new Error("CloudflareKVDelegationVerifier requires kvNamespace in config");
|
|
76
76
|
}
|
|
77
77
|
this.kv = config.kvNamespace;
|
|
78
78
|
this.cache = new DelegationCache();
|
|
@@ -84,11 +84,15 @@ class CloudflareKVDelegationVerifier {
|
|
|
84
84
|
*/
|
|
85
85
|
async verify(agentDid, scopes, options) {
|
|
86
86
|
// Validate inputs
|
|
87
|
-
const validation = delegation_verifier_2.VerifyDelegationInputSchema.safeParse({
|
|
87
|
+
const validation = delegation_verifier_2.VerifyDelegationInputSchema.safeParse({
|
|
88
|
+
agentDid,
|
|
89
|
+
scopes,
|
|
90
|
+
options,
|
|
91
|
+
});
|
|
88
92
|
if (!validation.success) {
|
|
89
93
|
return {
|
|
90
94
|
valid: false,
|
|
91
|
-
reason: `Invalid request: ${validation.error.errors.map(e => `${e.path.join(
|
|
95
|
+
reason: `Invalid request: ${validation.error.errors.map((e) => `${e.path.join(".")}: ${e.message}`).join(", ")}`,
|
|
92
96
|
};
|
|
93
97
|
}
|
|
94
98
|
const startTime = Date.now();
|
|
@@ -100,27 +104,29 @@ class CloudflareKVDelegationVerifier {
|
|
|
100
104
|
const cached = this.cache.get(cacheKey);
|
|
101
105
|
if (cached) {
|
|
102
106
|
if (this.debug) {
|
|
103
|
-
console.
|
|
107
|
+
console.error(`[KV] Cache HIT for ${agentDid} (${Date.now() - startTime}ms)`);
|
|
104
108
|
}
|
|
105
109
|
return { ...cached, cached: true };
|
|
106
110
|
}
|
|
107
111
|
}
|
|
108
112
|
// Slow path: Lookup in KV
|
|
109
113
|
if (this.debug) {
|
|
110
|
-
console.
|
|
114
|
+
console.error(`[KV] Cache MISS for ${agentDid}, querying KV...`);
|
|
111
115
|
}
|
|
112
116
|
// List all delegations for this agent (to support subset scope matching)
|
|
113
|
-
const listResult = await this.kv.list({
|
|
117
|
+
const listResult = await this.kv.list({
|
|
118
|
+
prefix: `agent:${agentDid}:scopes:`,
|
|
119
|
+
});
|
|
114
120
|
if (!listResult.keys || listResult.keys.length === 0) {
|
|
115
121
|
const result = {
|
|
116
122
|
valid: false,
|
|
117
|
-
reason:
|
|
123
|
+
reason: "No delegation found for agent",
|
|
118
124
|
cached: false,
|
|
119
125
|
};
|
|
120
126
|
// Cache negative result (shorter TTL)
|
|
121
127
|
this.cache.set(cacheKey, result, this.cacheTtl / 2);
|
|
122
128
|
if (this.debug) {
|
|
123
|
-
console.
|
|
129
|
+
console.error(`[KV] No delegation found (${Date.now() - startTime}ms)`);
|
|
124
130
|
}
|
|
125
131
|
return result;
|
|
126
132
|
}
|
|
@@ -145,12 +151,12 @@ class CloudflareKVDelegationVerifier {
|
|
|
145
151
|
if (!matchingDelegation) {
|
|
146
152
|
const result = {
|
|
147
153
|
valid: false,
|
|
148
|
-
reason:
|
|
154
|
+
reason: "No delegation found with required scopes",
|
|
149
155
|
cached: false,
|
|
150
156
|
};
|
|
151
157
|
this.cache.set(cacheKey, result, this.cacheTtl / 2);
|
|
152
158
|
if (this.debug) {
|
|
153
|
-
console.
|
|
159
|
+
console.error(`[KV] No matching delegation found (${Date.now() - startTime}ms)`);
|
|
154
160
|
}
|
|
155
161
|
return result;
|
|
156
162
|
}
|
|
@@ -174,7 +180,7 @@ class CloudflareKVDelegationVerifier {
|
|
|
174
180
|
const result = {
|
|
175
181
|
valid: false,
|
|
176
182
|
delegation,
|
|
177
|
-
reason:
|
|
183
|
+
reason: "Insufficient scopes",
|
|
178
184
|
cached: false,
|
|
179
185
|
};
|
|
180
186
|
this.cache.set(cacheKey, result, this.cacheTtl / 2);
|
|
@@ -189,7 +195,7 @@ class CloudflareKVDelegationVerifier {
|
|
|
189
195
|
// Cache positive result
|
|
190
196
|
this.cache.set(cacheKey, result, this.cacheTtl);
|
|
191
197
|
if (this.debug) {
|
|
192
|
-
console.
|
|
198
|
+
console.error(`[KV] Delegation verified (${Date.now() - startTime}ms)`);
|
|
193
199
|
}
|
|
194
200
|
return result;
|
|
195
201
|
}
|
|
@@ -206,13 +212,13 @@ class CloudflareKVDelegationVerifier {
|
|
|
206
212
|
const data = JSON.parse(raw);
|
|
207
213
|
const parsed = delegation_1.DelegationRecordSchema.safeParse(data);
|
|
208
214
|
if (!parsed.success) {
|
|
209
|
-
console.error(
|
|
215
|
+
console.error("[KV] Invalid delegation record:", parsed.error);
|
|
210
216
|
return null;
|
|
211
217
|
}
|
|
212
218
|
return parsed.data;
|
|
213
219
|
}
|
|
214
220
|
catch (error) {
|
|
215
|
-
console.error(
|
|
221
|
+
console.error("[KV] Failed to parse delegation:", error);
|
|
216
222
|
return null;
|
|
217
223
|
}
|
|
218
224
|
}
|
|
@@ -238,7 +244,7 @@ class CloudflareKVDelegationVerifier {
|
|
|
238
244
|
this.cache.delete(`delegation:${validated.id}`);
|
|
239
245
|
this.cache.delete(`verify:${validated.subjectDid}:${scopesKey}`);
|
|
240
246
|
if (this.debug) {
|
|
241
|
-
console.
|
|
247
|
+
console.error(`[KV] Stored delegation ${validated.id}`);
|
|
242
248
|
}
|
|
243
249
|
}
|
|
244
250
|
/**
|
|
@@ -250,7 +256,7 @@ class CloudflareKVDelegationVerifier {
|
|
|
250
256
|
throw new Error(`Delegation not found: ${delegationId}`);
|
|
251
257
|
}
|
|
252
258
|
// Update status
|
|
253
|
-
delegation.status =
|
|
259
|
+
delegation.status = "revoked";
|
|
254
260
|
delegation.revokedAt = Date.now();
|
|
255
261
|
if (reason) {
|
|
256
262
|
delegation.revokedReason = reason;
|
|
@@ -258,7 +264,7 @@ class CloudflareKVDelegationVerifier {
|
|
|
258
264
|
// Store updated record
|
|
259
265
|
await this.put(delegation);
|
|
260
266
|
if (this.debug) {
|
|
261
|
-
console.
|
|
267
|
+
console.error(`[KV] Revoked delegation ${delegationId}`);
|
|
262
268
|
}
|
|
263
269
|
}
|
|
264
270
|
/**
|
|
@@ -268,7 +274,7 @@ class CloudflareKVDelegationVerifier {
|
|
|
268
274
|
// Sort scopes for deterministic key
|
|
269
275
|
const sorted = [...scopes].sort();
|
|
270
276
|
// Simple hash (for production, consider crypto.subtle.digest)
|
|
271
|
-
const str = sorted.join(
|
|
277
|
+
const str = sorted.join(",");
|
|
272
278
|
let hash = 0;
|
|
273
279
|
for (let i = 0; i < str.length; i++) {
|
|
274
280
|
const char = str.charCodeAt(i);
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
*
|
|
12
12
|
* Related: PHASE_1_XMCP_I_SERVER.md Testing section
|
|
13
13
|
*/
|
|
14
|
-
import { DelegationRecord } from
|
|
15
|
-
import { DelegationVerifier, DelegationVerifierConfig, VerifyDelegationResult, VerifyDelegationOptions } from
|
|
14
|
+
import { DelegationRecord } from "@kya-os/contracts/delegation";
|
|
15
|
+
import { DelegationVerifier, DelegationVerifierConfig, VerifyDelegationResult, VerifyDelegationOptions } from "./delegation-verifier";
|
|
16
16
|
/**
|
|
17
17
|
* Memory Delegation Verifier
|
|
18
18
|
*
|
|
@@ -33,11 +33,15 @@ class MemoryDelegationVerifier {
|
|
|
33
33
|
*/
|
|
34
34
|
async verify(agentDid, scopes, _options) {
|
|
35
35
|
// Validate inputs
|
|
36
|
-
const validation = delegation_verifier_1.VerifyDelegationInputSchema.safeParse({
|
|
36
|
+
const validation = delegation_verifier_1.VerifyDelegationInputSchema.safeParse({
|
|
37
|
+
agentDid,
|
|
38
|
+
scopes,
|
|
39
|
+
options: _options,
|
|
40
|
+
});
|
|
37
41
|
if (!validation.success) {
|
|
38
42
|
return {
|
|
39
43
|
valid: false,
|
|
40
|
-
reason: `Invalid request: ${validation.error.errors.map(e => `${e.path.join(
|
|
44
|
+
reason: `Invalid request: ${validation.error.errors.map((e) => `${e.path.join(".")}: ${e.message}`).join(", ")}`,
|
|
41
45
|
};
|
|
42
46
|
}
|
|
43
47
|
// Find all delegations for this agent
|
|
@@ -45,7 +49,7 @@ class MemoryDelegationVerifier {
|
|
|
45
49
|
if (!delegationIds || delegationIds.size === 0) {
|
|
46
50
|
return {
|
|
47
51
|
valid: false,
|
|
48
|
-
reason:
|
|
52
|
+
reason: "No delegation found for agent",
|
|
49
53
|
cached: false,
|
|
50
54
|
};
|
|
51
55
|
}
|
|
@@ -71,7 +75,7 @@ class MemoryDelegationVerifier {
|
|
|
71
75
|
// No matching delegation found
|
|
72
76
|
return {
|
|
73
77
|
valid: false,
|
|
74
|
-
reason:
|
|
78
|
+
reason: "No delegation with required scopes",
|
|
75
79
|
cached: false,
|
|
76
80
|
};
|
|
77
81
|
}
|
|
@@ -99,7 +103,7 @@ class MemoryDelegationVerifier {
|
|
|
99
103
|
}
|
|
100
104
|
this.agentIndex.get(validated.subjectDid).add(validated.id);
|
|
101
105
|
if (this.debug) {
|
|
102
|
-
console.
|
|
106
|
+
console.error(`[Memory] Stored delegation ${validated.id}`);
|
|
103
107
|
}
|
|
104
108
|
}
|
|
105
109
|
/**
|
|
@@ -110,13 +114,13 @@ class MemoryDelegationVerifier {
|
|
|
110
114
|
if (!delegation) {
|
|
111
115
|
throw new Error(`Delegation not found: ${delegationId}`);
|
|
112
116
|
}
|
|
113
|
-
delegation.status =
|
|
117
|
+
delegation.status = "revoked";
|
|
114
118
|
delegation.revokedAt = Date.now();
|
|
115
119
|
if (reason) {
|
|
116
120
|
delegation.revokedReason = reason;
|
|
117
121
|
}
|
|
118
122
|
if (this.debug) {
|
|
119
|
-
console.
|
|
123
|
+
console.error(`[Memory] Revoked delegation ${delegationId}`);
|
|
120
124
|
}
|
|
121
125
|
}
|
|
122
126
|
/**
|