@kya-os/contracts 1.5.3-canary.22 → 1.5.3-canary.23
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/consent/schemas.d.ts +149 -77
- package/dist/consent/schemas.js +29 -2
- package/package.json +23 -1
- package/.turbo/turbo-build.log +0 -19
- package/.turbo/turbo-test$colon$coverage.log +0 -117
- package/.turbo/turbo-test.log +0 -32
- package/coverage/coverage-final.json +0 -38
- package/schemas/cli/register-output/v1.0.0.json +0 -69
- package/schemas/identity/v1.0.0.json +0 -46
- package/schemas/proof/v1.0.0.json +0 -80
- package/schemas/registry/receipt-v1.0.0.json +0 -60
- package/schemas/verifier/verify-page/v1.0.0.json +0 -94
- package/schemas/well-known/agent/v1.0.0.json +0 -67
- package/schemas/well-known/did/v1.0.0.json +0 -174
- package/scripts/emit-schemas.js +0 -11
- package/src/agentshield-api/admin-schemas.ts +0 -31
- package/src/agentshield-api/admin-types.ts +0 -47
- package/src/agentshield-api/endpoints.ts +0 -60
- package/src/agentshield-api/index.ts +0 -70
- package/src/agentshield-api/schemas.ts +0 -304
- package/src/agentshield-api/types.ts +0 -317
- package/src/audit/index.ts +0 -128
- package/src/cli.ts +0 -156
- package/src/config/base.ts +0 -107
- package/src/config/builder.ts +0 -97
- package/src/config/delegation.ts +0 -232
- package/src/config/identity.ts +0 -252
- package/src/config/index.ts +0 -78
- package/src/config/proofing.ts +0 -138
- package/src/config/tool-context.ts +0 -41
- package/src/config/tool-protection.ts +0 -174
- package/src/consent/index.ts +0 -32
- package/src/consent/schemas.ts +0 -334
- package/src/consent/types.ts +0 -199
- package/src/dashboard-config/default-config.json +0 -86
- package/src/dashboard-config/default-config.ts +0 -266
- package/src/dashboard-config/index.ts +0 -48
- package/src/dashboard-config/schemas.ts +0 -286
- package/src/dashboard-config/types.ts +0 -404
- package/src/delegation/constraints.ts +0 -267
- package/src/delegation/index.ts +0 -8
- package/src/delegation/schemas.ts +0 -595
- package/src/did/index.ts +0 -9
- package/src/did/resolve-contract.ts +0 -255
- package/src/did/schemas.ts +0 -190
- package/src/did/types.ts +0 -224
- package/src/env/constants.ts +0 -70
- package/src/env/index.ts +0 -5
- package/src/handshake.ts +0 -125
- package/src/index.ts +0 -45
- package/src/proof/index.ts +0 -31
- package/src/proof/proof-record.ts +0 -163
- package/src/proof/signing-spec.ts +0 -146
- package/src/proof.ts +0 -99
- package/src/registry.ts +0 -146
- package/src/runtime/errors.ts +0 -153
- package/src/runtime/headers.ts +0 -136
- package/src/runtime/index.ts +0 -6
- package/src/test.ts +0 -143
- package/src/tlkrc/index.ts +0 -5
- package/src/tlkrc/rotation.ts +0 -153
- package/src/tool-protection/index.ts +0 -406
- package/src/utils/validation.ts +0 -93
- package/src/vc/index.ts +0 -8
- package/src/vc/schemas.ts +0 -277
- package/src/vc/statuslist.ts +0 -279
- package/src/verifier/index.ts +0 -2
- package/src/verifier.ts +0 -92
- package/src/well-known/index.ts +0 -237
package/src/tlkrc/rotation.ts
DELETED
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TLKRC (Transparent Log Key Rotation Contract)
|
|
3
|
-
*
|
|
4
|
-
* Types for key rotation events in a transparent, auditable manner
|
|
5
|
-
*
|
|
6
|
-
* Related Spec: MCP-I Core
|
|
7
|
-
* Python Reference: Core-Documentation.md
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { z } from 'zod';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Rotation Event Schema
|
|
14
|
-
*
|
|
15
|
-
* Represents a key rotation event in a transparent log.
|
|
16
|
-
* Events form a hash-linked chain for auditability.
|
|
17
|
-
*
|
|
18
|
-
* **Dual-Key Grace Window:**
|
|
19
|
-
* During rotation, both `prevKeyId` and `nextKeyId` are valid
|
|
20
|
-
* from `effectiveAt` until `effectiveAt + grace period`.
|
|
21
|
-
*/
|
|
22
|
-
export const RotationEventSchema = z.object({
|
|
23
|
-
/** DID of the issuer performing the rotation */
|
|
24
|
-
issuerDid: z.string().min(1),
|
|
25
|
-
|
|
26
|
-
/** Previous key ID being rotated out */
|
|
27
|
-
prevKeyId: z.string().min(1),
|
|
28
|
-
|
|
29
|
-
/** New key ID being rotated in */
|
|
30
|
-
nextKeyId: z.string().min(1),
|
|
31
|
-
|
|
32
|
-
/** Timestamp when new key becomes effective (Unix seconds) */
|
|
33
|
-
effectiveAt: z.number().int().positive(),
|
|
34
|
-
|
|
35
|
-
/** Timestamp when event was issued (Unix seconds) */
|
|
36
|
-
issuedAt: z.number().int().positive(),
|
|
37
|
-
|
|
38
|
-
/** Sequence number (monotonically increasing) */
|
|
39
|
-
seq: z.number().int().nonnegative(),
|
|
40
|
-
|
|
41
|
-
/** Hash of previous rotation event (null for first rotation) */
|
|
42
|
-
prevEventHash: z.string().optional(),
|
|
43
|
-
|
|
44
|
-
/** Signature over the event (using prevKeyId) */
|
|
45
|
-
signature: z.string().min(1),
|
|
46
|
-
|
|
47
|
-
/** Optional metadata */
|
|
48
|
-
metadata: z.record(z.any()).optional(),
|
|
49
|
-
}).refine(
|
|
50
|
-
(event) => event.effectiveAt >= event.issuedAt,
|
|
51
|
-
{
|
|
52
|
-
message: 'effectiveAt must be >= issuedAt',
|
|
53
|
-
}
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
export type RotationEvent = z.infer<typeof RotationEventSchema>;
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Rotation Chain
|
|
60
|
-
*
|
|
61
|
-
* Represents a chain of rotation events
|
|
62
|
-
*/
|
|
63
|
-
export const RotationChainSchema = z.object({
|
|
64
|
-
/** Issuer DID */
|
|
65
|
-
issuerDid: z.string().min(1),
|
|
66
|
-
|
|
67
|
-
/** All rotation events in order */
|
|
68
|
-
events: z.array(RotationEventSchema).min(1),
|
|
69
|
-
|
|
70
|
-
/** Current active key ID */
|
|
71
|
-
currentKeyId: z.string().min(1),
|
|
72
|
-
|
|
73
|
-
/** Whether chain is valid */
|
|
74
|
-
valid: z.boolean(),
|
|
75
|
-
|
|
76
|
-
/** Optional validation errors */
|
|
77
|
-
errors: z.array(z.string()).optional(),
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
export type RotationChain = z.infer<typeof RotationChainSchema>;
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Validation Helpers
|
|
84
|
-
*/
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Validate a rotation event
|
|
88
|
-
*
|
|
89
|
-
* @param event - The event to validate
|
|
90
|
-
* @returns Validation result
|
|
91
|
-
*/
|
|
92
|
-
export function validateRotationEvent(event: unknown) {
|
|
93
|
-
return RotationEventSchema.safeParse(event);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Validate rotation chain integrity
|
|
98
|
-
*
|
|
99
|
-
* @param chain - The chain to validate
|
|
100
|
-
* @returns true if chain is valid
|
|
101
|
-
*/
|
|
102
|
-
export function isRotationChainValid(chain: RotationChain): boolean {
|
|
103
|
-
if (chain.events.length === 0) {
|
|
104
|
-
return false;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// Check sequence numbers are monotonic
|
|
108
|
-
for (let i = 1; i < chain.events.length; i++) {
|
|
109
|
-
if (chain.events[i].seq <= chain.events[i - 1].seq) {
|
|
110
|
-
return false;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return chain.valid;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Get active key at a specific timestamp
|
|
119
|
-
*
|
|
120
|
-
* @param chain - The rotation chain
|
|
121
|
-
* @param timestamp - Timestamp in seconds
|
|
122
|
-
* @returns Active key ID at that time, or null if none
|
|
123
|
-
*/
|
|
124
|
-
export function getActiveKeyAt(chain: RotationChain, timestamp: number): string | null {
|
|
125
|
-
if (chain.events.length === 0) {
|
|
126
|
-
return null;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// Find the most recent event that's effective at the timestamp
|
|
130
|
-
for (let i = chain.events.length - 1; i >= 0; i--) {
|
|
131
|
-
const event = chain.events[i];
|
|
132
|
-
if (event.effectiveAt <= timestamp) {
|
|
133
|
-
return event.nextKeyId;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// If no event is effective yet, use the initial key
|
|
138
|
-
return chain.events[0].prevKeyId;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Constants
|
|
143
|
-
*/
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Default grace period for dual-key validity (24 hours)
|
|
147
|
-
*/
|
|
148
|
-
export const DEFAULT_GRACE_PERIOD_SEC = 24 * 60 * 60;
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Maximum reasonable grace period (30 days)
|
|
152
|
-
*/
|
|
153
|
-
export const MAX_GRACE_PERIOD_SEC = 30 * 24 * 60 * 60;
|
|
@@ -1,406 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MCP-I Tool Protection Specification
|
|
3
|
-
*
|
|
4
|
-
* This module defines the core tool protection types as specified in the
|
|
5
|
-
* MCP-I protocol. These are pure specification types that define how tools
|
|
6
|
-
* can be protected with delegation requirements and scopes.
|
|
7
|
-
*
|
|
8
|
-
* @module @kya-os/contracts/tool-protection
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { z } from 'zod';
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Authorization Requirement (Discriminated Union)
|
|
15
|
-
*
|
|
16
|
-
* Defines the type of authorization required for a tool.
|
|
17
|
-
* Extensible design to support OAuth, MDL, IDV, credentials, etc.
|
|
18
|
-
*/
|
|
19
|
-
export type AuthorizationRequirement =
|
|
20
|
-
| {
|
|
21
|
-
type: 'oauth';
|
|
22
|
-
provider: string; // "github", "google", etc.
|
|
23
|
-
requiredScopes?: string[]; // Provider-specific scopes
|
|
24
|
-
}
|
|
25
|
-
| {
|
|
26
|
-
type: 'mdl';
|
|
27
|
-
issuer: string; // MDL issuer DID or identifier
|
|
28
|
-
credentialType?: string; // Specific MDL credential type
|
|
29
|
-
}
|
|
30
|
-
| {
|
|
31
|
-
type: 'idv';
|
|
32
|
-
provider: string; // IDV provider name
|
|
33
|
-
verificationLevel?: 'basic' | 'enhanced' | 'loa3';
|
|
34
|
-
}
|
|
35
|
-
| {
|
|
36
|
-
type: 'credential';
|
|
37
|
-
credentialType: string; // Generic credential type
|
|
38
|
-
issuer?: string; // Optional issuer constraint
|
|
39
|
-
}
|
|
40
|
-
| {
|
|
41
|
-
type: 'none'; // Just consent checkbox, no external auth
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Tool Protection Definition
|
|
46
|
-
*
|
|
47
|
-
* Defines the protection requirements for a tool as per MCP-I spec.
|
|
48
|
-
* This is the canonical definition that all implementations must follow.
|
|
49
|
-
*/
|
|
50
|
-
export interface ToolProtection {
|
|
51
|
-
/**
|
|
52
|
-
* Whether this tool requires explicit delegation from the user
|
|
53
|
-
*/
|
|
54
|
-
requiresDelegation: boolean;
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* The scopes required to execute this tool
|
|
58
|
-
* Format: "resource:action" (e.g., "files:read", "payment:send")
|
|
59
|
-
*/
|
|
60
|
-
requiredScopes: string[];
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Risk level classification for the tool
|
|
64
|
-
* Used to determine appropriate authorization flows
|
|
65
|
-
*/
|
|
66
|
-
riskLevel?: 'low' | 'medium' | 'high' | 'critical';
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* OAuth provider name for this tool (Phase 2+)
|
|
70
|
-
* If specified, this tool will use the specified OAuth provider.
|
|
71
|
-
* If not specified, provider will be resolved via fallback strategies.
|
|
72
|
-
* @example "github", "google", "microsoft"
|
|
73
|
-
* @deprecated Use `authorization` field instead. Will be removed in Phase 3.
|
|
74
|
-
*/
|
|
75
|
-
oauthProvider?: string;
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Authorization requirement for this tool
|
|
79
|
-
* If requiresDelegation=true, authorization must be specified (or inferred from legacy fields)
|
|
80
|
-
*/
|
|
81
|
-
authorization?: AuthorizationRequirement;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Tool Protection Map
|
|
86
|
-
*
|
|
87
|
-
* A mapping of tool names to their protection configurations.
|
|
88
|
-
* This is how tool protections are typically stored and transmitted.
|
|
89
|
-
*/
|
|
90
|
-
export type ToolProtectionMap = Record<string, ToolProtection>;
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Partial tool protection for updates (all fields optional)
|
|
94
|
-
* Use this when accepting partial updates to tool protection settings
|
|
95
|
-
*/
|
|
96
|
-
export type PartialToolProtection = Partial<ToolProtection>;
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Tool protection with explicit optional fields
|
|
100
|
-
* Useful when TypeScript's Partial<T> doesn't preserve optional property access
|
|
101
|
-
* Supports explicit null values to clear fields
|
|
102
|
-
*/
|
|
103
|
-
export type ToolProtectionUpdate = {
|
|
104
|
-
requiresDelegation?: boolean;
|
|
105
|
-
requiredScopes?: string[];
|
|
106
|
-
riskLevel?: 'low' | 'medium' | 'high' | 'critical';
|
|
107
|
-
oauthProvider?: string | null; // null explicitly clears the field
|
|
108
|
-
authorization?: AuthorizationRequirement | null; // null explicitly clears the field
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Tool Protection Response
|
|
113
|
-
*
|
|
114
|
-
* The response format when querying for tool protections.
|
|
115
|
-
* Used by tool protection services and APIs.
|
|
116
|
-
*/
|
|
117
|
-
export interface ToolProtectionResponse {
|
|
118
|
-
/**
|
|
119
|
-
* The tool protections keyed by tool name
|
|
120
|
-
*/
|
|
121
|
-
toolProtections: ToolProtectionMap;
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Optional metadata about the response
|
|
125
|
-
*/
|
|
126
|
-
metadata?: {
|
|
127
|
-
/**
|
|
128
|
-
* When this configuration was last updated
|
|
129
|
-
*/
|
|
130
|
-
lastUpdated?: string;
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Version of the configuration
|
|
134
|
-
*/
|
|
135
|
-
version?: string;
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* Source of the configuration
|
|
139
|
-
*/
|
|
140
|
-
source?: string;
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Delegation Required Error Data
|
|
146
|
-
*
|
|
147
|
-
* The standardized error data returned when a tool requires delegation
|
|
148
|
-
* but none was provided. This is part of the MCP-I error protocol.
|
|
149
|
-
*/
|
|
150
|
-
export interface DelegationRequiredErrorData {
|
|
151
|
-
/**
|
|
152
|
-
* The name of the tool that requires delegation
|
|
153
|
-
*/
|
|
154
|
-
toolName: string;
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* The scopes required for this tool
|
|
158
|
-
*/
|
|
159
|
-
requiredScopes: string[];
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* URL where the user can provide consent/delegation
|
|
163
|
-
*/
|
|
164
|
-
consentUrl?: string;
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Alternative field for consent URL (for compatibility)
|
|
168
|
-
*/
|
|
169
|
-
authorizationUrl?: string;
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* Additional context about why delegation is required
|
|
173
|
-
*/
|
|
174
|
-
reason?: string;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* Legacy tool protection format (pre-authorization field)
|
|
179
|
-
* Used during migration period to support both old and new formats
|
|
180
|
-
*/
|
|
181
|
-
export type LegacyToolProtection = Omit<ToolProtection, 'authorization'> & {
|
|
182
|
-
oauthProvider?: string;
|
|
183
|
-
};
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Union type for both legacy and new formats
|
|
187
|
-
* Useful during migration period when accepting tool protection input
|
|
188
|
-
*/
|
|
189
|
-
export type ToolProtectionInput = ToolProtection | LegacyToolProtection;
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* Zod Schemas for Validation
|
|
193
|
-
*/
|
|
194
|
-
|
|
195
|
-
export const AuthorizationRequirementSchema = z.discriminatedUnion('type', [
|
|
196
|
-
z.object({
|
|
197
|
-
type: z.literal('oauth'),
|
|
198
|
-
provider: z.string(),
|
|
199
|
-
requiredScopes: z.array(z.string()).optional(),
|
|
200
|
-
}),
|
|
201
|
-
z.object({
|
|
202
|
-
type: z.literal('mdl'),
|
|
203
|
-
issuer: z.string(),
|
|
204
|
-
credentialType: z.string().optional(),
|
|
205
|
-
}),
|
|
206
|
-
z.object({
|
|
207
|
-
type: z.literal('idv'),
|
|
208
|
-
provider: z.string(),
|
|
209
|
-
verificationLevel: z.enum(['basic', 'enhanced', 'loa3']).optional(),
|
|
210
|
-
}),
|
|
211
|
-
z.object({
|
|
212
|
-
type: z.literal('credential'),
|
|
213
|
-
credentialType: z.string(),
|
|
214
|
-
issuer: z.string().optional(),
|
|
215
|
-
}),
|
|
216
|
-
z.object({
|
|
217
|
-
type: z.literal('none'),
|
|
218
|
-
}),
|
|
219
|
-
]);
|
|
220
|
-
|
|
221
|
-
export const ToolProtectionSchema = z.object({
|
|
222
|
-
requiresDelegation: z.boolean(),
|
|
223
|
-
requiredScopes: z.array(z.string()),
|
|
224
|
-
riskLevel: z.enum(['low', 'medium', 'high', 'critical']).optional(),
|
|
225
|
-
oauthProvider: z.string().optional(), // Phase 2: Tool-specific OAuth provider
|
|
226
|
-
authorization: AuthorizationRequirementSchema.optional(),
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
export const ToolProtectionMapSchema = z.record(z.string(), ToolProtectionSchema);
|
|
230
|
-
|
|
231
|
-
export const ToolProtectionResponseSchema = z.object({
|
|
232
|
-
toolProtections: ToolProtectionMapSchema,
|
|
233
|
-
metadata: z.object({
|
|
234
|
-
lastUpdated: z.string().optional(),
|
|
235
|
-
version: z.string().optional(),
|
|
236
|
-
source: z.string().optional()
|
|
237
|
-
}).optional()
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
export const DelegationRequiredErrorDataSchema = z.object({
|
|
241
|
-
toolName: z.string(),
|
|
242
|
-
requiredScopes: z.array(z.string()),
|
|
243
|
-
consentUrl: z.string().optional(),
|
|
244
|
-
authorizationUrl: z.string().optional(),
|
|
245
|
-
reason: z.string().optional()
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
/**
|
|
249
|
-
* Type Guards
|
|
250
|
-
*/
|
|
251
|
-
|
|
252
|
-
export function isToolProtection(obj: any): obj is ToolProtection {
|
|
253
|
-
return ToolProtectionSchema.safeParse(obj).success;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
export function isToolProtectionMap(obj: any): obj is ToolProtectionMap {
|
|
257
|
-
return ToolProtectionMapSchema.safeParse(obj).success;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
export function isToolProtectionResponse(obj: any): obj is ToolProtectionResponse {
|
|
261
|
-
return ToolProtectionResponseSchema.safeParse(obj).success;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
export function isDelegationRequiredErrorData(obj: any): obj is DelegationRequiredErrorData {
|
|
265
|
-
return DelegationRequiredErrorDataSchema.safeParse(obj).success;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
/**
|
|
269
|
-
* Type guard to check if an object is a valid AuthorizationRequirement
|
|
270
|
-
*/
|
|
271
|
-
export function isAuthorizationRequirement(obj: unknown): obj is AuthorizationRequirement {
|
|
272
|
-
return AuthorizationRequirementSchema.safeParse(obj).success;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
/**
|
|
276
|
-
* Type guard to check if a ToolProtection has OAuth authorization
|
|
277
|
-
*/
|
|
278
|
-
export function hasOAuthAuthorization(
|
|
279
|
-
protection: ToolProtection
|
|
280
|
-
): protection is ToolProtection & { authorization: { type: 'oauth' } } {
|
|
281
|
-
return protection.authorization?.type === 'oauth';
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
/**
|
|
285
|
-
* Validation Functions
|
|
286
|
-
*/
|
|
287
|
-
|
|
288
|
-
export function validateToolProtection(obj: any): ToolProtection {
|
|
289
|
-
return ToolProtectionSchema.parse(obj);
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
export function validateToolProtectionMap(obj: any): ToolProtectionMap {
|
|
293
|
-
return ToolProtectionMapSchema.parse(obj);
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
export function validateToolProtectionResponse(obj: any): ToolProtectionResponse {
|
|
297
|
-
return ToolProtectionResponseSchema.parse(obj);
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
export function validateDelegationRequiredErrorData(obj: any): DelegationRequiredErrorData {
|
|
301
|
-
return DelegationRequiredErrorDataSchema.parse(obj);
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
/**
|
|
305
|
-
* Utility Functions
|
|
306
|
-
*/
|
|
307
|
-
|
|
308
|
-
/**
|
|
309
|
-
* Check if a tool requires delegation
|
|
310
|
-
*/
|
|
311
|
-
export function toolRequiresDelegation(
|
|
312
|
-
toolName: string,
|
|
313
|
-
protections: ToolProtectionMap
|
|
314
|
-
): boolean {
|
|
315
|
-
const protection = protections[toolName];
|
|
316
|
-
return protection?.requiresDelegation ?? false;
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
/**
|
|
320
|
-
* Get required scopes for a tool
|
|
321
|
-
*/
|
|
322
|
-
export function getToolRequiredScopes(
|
|
323
|
-
toolName: string,
|
|
324
|
-
protections: ToolProtectionMap
|
|
325
|
-
): string[] {
|
|
326
|
-
const protection = protections[toolName];
|
|
327
|
-
return protection?.requiredScopes ?? [];
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
/**
|
|
331
|
-
* Get risk level for a tool
|
|
332
|
-
*/
|
|
333
|
-
export function getToolRiskLevel(
|
|
334
|
-
toolName: string,
|
|
335
|
-
protections: ToolProtectionMap
|
|
336
|
-
): ToolProtection['riskLevel'] | undefined {
|
|
337
|
-
return protections[toolName]?.riskLevel;
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
/**
|
|
341
|
-
* Create a delegation required error
|
|
342
|
-
*/
|
|
343
|
-
export function createDelegationRequiredError(
|
|
344
|
-
toolName: string,
|
|
345
|
-
requiredScopes: string[],
|
|
346
|
-
consentUrl?: string
|
|
347
|
-
): DelegationRequiredErrorData {
|
|
348
|
-
return {
|
|
349
|
-
toolName,
|
|
350
|
-
requiredScopes,
|
|
351
|
-
consentUrl,
|
|
352
|
-
authorizationUrl: consentUrl // Include both for compatibility
|
|
353
|
-
};
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
/**
|
|
357
|
-
* Normalize tool protection configuration
|
|
358
|
-
* Migrates legacy oauthProvider field to authorization object
|
|
359
|
-
*
|
|
360
|
-
* - Migrates `oauthProvider` → `authorization: { type: 'oauth', provider: ... }`
|
|
361
|
-
* - Ensures `authorization` field is present when `requiresDelegation=true`
|
|
362
|
-
* - Returns fully normalized ToolProtection object
|
|
363
|
-
*
|
|
364
|
-
* @param raw - Raw tool protection data (may have legacy fields or be partial)
|
|
365
|
-
* @returns Normalized ToolProtection object
|
|
366
|
-
*
|
|
367
|
-
* // TODO: Remove normalizeToolProtection() when all tools migrated (target: Phase 3)
|
|
368
|
-
*/
|
|
369
|
-
export function normalizeToolProtection(
|
|
370
|
-
raw: ToolProtection | PartialToolProtection
|
|
371
|
-
): ToolProtection {
|
|
372
|
-
// Ensure we have required fields (provide defaults for partial input)
|
|
373
|
-
const normalized: ToolProtection = {
|
|
374
|
-
requiresDelegation: raw.requiresDelegation ?? false,
|
|
375
|
-
requiredScopes: raw.requiredScopes ?? [],
|
|
376
|
-
...(raw.riskLevel && { riskLevel: raw.riskLevel }),
|
|
377
|
-
...(raw.oauthProvider && { oauthProvider: raw.oauthProvider }),
|
|
378
|
-
};
|
|
379
|
-
|
|
380
|
-
// If authorization is already present, use it
|
|
381
|
-
if (raw.authorization) {
|
|
382
|
-
normalized.authorization = raw.authorization;
|
|
383
|
-
return normalized;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
// Migrate oauthProvider to authorization
|
|
387
|
-
if (raw.oauthProvider) {
|
|
388
|
-
normalized.authorization = {
|
|
389
|
-
type: 'oauth',
|
|
390
|
-
provider: raw.oauthProvider,
|
|
391
|
-
};
|
|
392
|
-
// Keep oauthProvider for backward compatibility until Phase 3
|
|
393
|
-
return normalized;
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
// Default for requiresDelegation=true without specific auth: type='none' (consent only)
|
|
397
|
-
// But ONLY if authorization is missing entirely
|
|
398
|
-
if (normalized.requiresDelegation && !normalized.authorization && !normalized.oauthProvider) {
|
|
399
|
-
// We don't automatically set type='none' here to allow
|
|
400
|
-
// ProviderResolver to do its scope inference fallback logic.
|
|
401
|
-
// The fallback logic will eventually be moved into an AuthorizationService.
|
|
402
|
-
return normalized;
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
return normalized;
|
|
406
|
-
}
|
package/src/utils/validation.ts
DELETED
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared validation utilities for mcpi packages
|
|
3
|
-
* Consolidates common validation patterns to follow DRY principles
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { z } from "zod";
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Generic validation result type
|
|
10
|
-
*/
|
|
11
|
-
export interface ValidationResult<T = any> {
|
|
12
|
-
valid: boolean;
|
|
13
|
-
data?: T;
|
|
14
|
-
errors: string[];
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Generic validation function with helpful error messages
|
|
19
|
-
*/
|
|
20
|
-
export function validateInput<T>(
|
|
21
|
-
schema: z.ZodSchema<T>,
|
|
22
|
-
data: unknown,
|
|
23
|
-
context?: string
|
|
24
|
-
): ValidationResult<T> {
|
|
25
|
-
const result = schema.safeParse(data);
|
|
26
|
-
|
|
27
|
-
if (result.success) {
|
|
28
|
-
return {
|
|
29
|
-
valid: true,
|
|
30
|
-
data: result.data,
|
|
31
|
-
errors: [],
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const errors = result.error.errors.map((err) => {
|
|
36
|
-
const path = err.path.length > 0 ? ` at ${err.path.join(".")}` : "";
|
|
37
|
-
const contextStr = context ? ` (${context})` : "";
|
|
38
|
-
return `${err.message}${path}${contextStr}`;
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
return {
|
|
42
|
-
valid: false,
|
|
43
|
-
errors,
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Validate object has required properties
|
|
49
|
-
*/
|
|
50
|
-
export function hasRequiredProperties(
|
|
51
|
-
obj: any,
|
|
52
|
-
properties: string[],
|
|
53
|
-
context?: string
|
|
54
|
-
): ValidationResult {
|
|
55
|
-
if (typeof obj !== "object" || obj === null) {
|
|
56
|
-
return {
|
|
57
|
-
valid: false,
|
|
58
|
-
errors: [`Expected object${context ? ` for ${context}` : ""}`],
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const missing = properties.filter((prop) => !(prop in obj));
|
|
63
|
-
|
|
64
|
-
if (missing.length > 0) {
|
|
65
|
-
return {
|
|
66
|
-
valid: false,
|
|
67
|
-
errors: [
|
|
68
|
-
`Missing required properties: ${missing.join(", ")}${context ? ` in ${context}` : ""}`,
|
|
69
|
-
],
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
return { valid: true, errors: [] };
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Validate string format patterns
|
|
78
|
-
*/
|
|
79
|
-
export const StringValidators = {
|
|
80
|
-
did: (value: string): boolean =>
|
|
81
|
-
/^did:[a-z0-9]+:[a-zA-Z0-9._-]+$/.test(value),
|
|
82
|
-
kid: (value: string): boolean => /^[a-zA-Z0-9._-]+$/.test(value),
|
|
83
|
-
url: (value: string): boolean => {
|
|
84
|
-
try {
|
|
85
|
-
new URL(value);
|
|
86
|
-
return true;
|
|
87
|
-
} catch {
|
|
88
|
-
return false;
|
|
89
|
-
}
|
|
90
|
-
},
|
|
91
|
-
projectName: (value: string): boolean =>
|
|
92
|
-
/^[a-z0-9-]+$/.test(value) && value.length >= 1 && value.length <= 214,
|
|
93
|
-
};
|