@sanctuary-framework/mcp-server 0.7.0 → 0.10.0
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/README.md +10 -0
- package/dist/cli.cjs +20807 -11985
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +21573 -12751
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +4805 -101
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1973 -1576
- package/dist/index.d.ts +1973 -1576
- package/dist/index.js +4803 -104
- package/dist/index.js.map +1 -1
- package/package.json +5 -3
package/dist/index.d.cts
CHANGED
|
@@ -6,7 +6,6 @@ import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
|
|
|
6
6
|
interface SanctuaryConfig {
|
|
7
7
|
version: string;
|
|
8
8
|
storage_path: string;
|
|
9
|
-
principal_id?: string;
|
|
10
9
|
state: {
|
|
11
10
|
encryption: "aes-256-gcm";
|
|
12
11
|
key_protection: "passphrase" | "hardware-key" | "none";
|
|
@@ -127,157 +126,6 @@ interface StorageBackend {
|
|
|
127
126
|
totalSize(): Promise<number>;
|
|
128
127
|
}
|
|
129
128
|
|
|
130
|
-
/**
|
|
131
|
-
* Sanctuary MCP Server — AES-256-GCM Encryption
|
|
132
|
-
*
|
|
133
|
-
* All state encryption in Sanctuary uses AES-256-GCM (authenticated encryption).
|
|
134
|
-
* This provides both confidentiality and integrity — a modified ciphertext will
|
|
135
|
-
* fail authentication, detecting tampering.
|
|
136
|
-
*
|
|
137
|
-
* Security invariants:
|
|
138
|
-
* - Every encryption uses a unique 12-byte IV (NIST SP 800-38D)
|
|
139
|
-
* - The 16-byte authentication tag is always verified on decryption
|
|
140
|
-
* - Keys are 256 bits (32 bytes)
|
|
141
|
-
*/
|
|
142
|
-
/** Encrypted payload structure stored on disk */
|
|
143
|
-
interface EncryptedPayload {
|
|
144
|
-
/** Format version */
|
|
145
|
-
v: number;
|
|
146
|
-
/** Algorithm identifier */
|
|
147
|
-
alg: "aes-256-gcm";
|
|
148
|
-
/** Initialization vector (base64url) */
|
|
149
|
-
iv: string;
|
|
150
|
-
/** Ciphertext (base64url) */
|
|
151
|
-
ct: string;
|
|
152
|
-
/** Authentication tag (base64url) — included in ciphertext by @noble/ciphers */
|
|
153
|
-
/** Timestamp */
|
|
154
|
-
ts: string;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Sanctuary MCP Server — L1 Cognitive Sovereignty: StateStore
|
|
159
|
-
*
|
|
160
|
-
* The encrypted state store is the foundation of Sanctuary.
|
|
161
|
-
* Every read and write goes through here. All data is encrypted
|
|
162
|
-
* with namespace-specific keys. All writes are signed by an identity.
|
|
163
|
-
* All reads verify integrity via Merkle proofs.
|
|
164
|
-
*
|
|
165
|
-
* Security invariants:
|
|
166
|
-
* - Plaintext never touches the filesystem
|
|
167
|
-
* - Every write gets a unique IV
|
|
168
|
-
* - Every write is signed (non-repudiation)
|
|
169
|
-
* - Monotonic version numbers prevent rollback
|
|
170
|
-
* - Merkle tree verifies namespace integrity
|
|
171
|
-
* - Secure deletion overwrites before unlinking
|
|
172
|
-
*/
|
|
173
|
-
|
|
174
|
-
/** Result of a state write operation */
|
|
175
|
-
interface WriteResult {
|
|
176
|
-
key: string;
|
|
177
|
-
namespace: string;
|
|
178
|
-
version: number;
|
|
179
|
-
merkle_root: string;
|
|
180
|
-
written_at: string;
|
|
181
|
-
size_bytes: number;
|
|
182
|
-
integrity_hash: string;
|
|
183
|
-
}
|
|
184
|
-
/** Result of a state read operation */
|
|
185
|
-
interface ReadResult {
|
|
186
|
-
key: string;
|
|
187
|
-
namespace: string;
|
|
188
|
-
value: string;
|
|
189
|
-
version: number;
|
|
190
|
-
integrity_verified: boolean;
|
|
191
|
-
merkle_proof: string[];
|
|
192
|
-
written_at: string;
|
|
193
|
-
written_by: string;
|
|
194
|
-
}
|
|
195
|
-
/** Options for state write */
|
|
196
|
-
interface WriteOptions {
|
|
197
|
-
content_type?: string;
|
|
198
|
-
ttl_seconds?: number;
|
|
199
|
-
tags?: string[];
|
|
200
|
-
}
|
|
201
|
-
declare class StateStore {
|
|
202
|
-
private storage;
|
|
203
|
-
private masterKey;
|
|
204
|
-
private versionCache;
|
|
205
|
-
private contentHashes;
|
|
206
|
-
constructor(storage: StorageBackend, masterKey: Uint8Array);
|
|
207
|
-
private versionKey;
|
|
208
|
-
/**
|
|
209
|
-
* Get or initialize the content hash map for a namespace.
|
|
210
|
-
*/
|
|
211
|
-
private getNamespaceHashes;
|
|
212
|
-
/**
|
|
213
|
-
* Write encrypted state.
|
|
214
|
-
*
|
|
215
|
-
* @param namespace - Logical grouping
|
|
216
|
-
* @param key - State key
|
|
217
|
-
* @param value - Plaintext value (will be encrypted)
|
|
218
|
-
* @param identityId - Identity performing the write
|
|
219
|
-
* @param encryptedPrivateKey - Identity's encrypted private key (for signing)
|
|
220
|
-
* @param identityEncryptionKey - Key to decrypt the identity's private key
|
|
221
|
-
* @param options - Optional metadata
|
|
222
|
-
*/
|
|
223
|
-
write(namespace: string, key: string, value: string, identityId: string, encryptedPrivateKey: EncryptedPayload, identityEncryptionKey: Uint8Array, options?: WriteOptions): Promise<WriteResult>;
|
|
224
|
-
/**
|
|
225
|
-
* Read and decrypt state.
|
|
226
|
-
*
|
|
227
|
-
* @param namespace - Logical grouping
|
|
228
|
-
* @param key - State key
|
|
229
|
-
* @param signerPublicKey - Expected signer's public key (for signature verification)
|
|
230
|
-
* @param verifyIntegrity - Whether to verify Merkle proof (default: true)
|
|
231
|
-
*/
|
|
232
|
-
read(namespace: string, key: string, signerPublicKey?: Uint8Array, verifyIntegrity?: boolean): Promise<ReadResult | null>;
|
|
233
|
-
/**
|
|
234
|
-
* List keys in a namespace (metadata only — no decryption).
|
|
235
|
-
*/
|
|
236
|
-
list(namespace: string, prefix?: string, tags?: string[], limit?: number, offset?: number): Promise<{
|
|
237
|
-
keys: Array<{
|
|
238
|
-
key: string;
|
|
239
|
-
version: number;
|
|
240
|
-
size_bytes: number;
|
|
241
|
-
written_at: string;
|
|
242
|
-
tags: string[];
|
|
243
|
-
}>;
|
|
244
|
-
total: number;
|
|
245
|
-
merkle_root: string;
|
|
246
|
-
}>;
|
|
247
|
-
/**
|
|
248
|
-
* Securely delete state (overwrite with random bytes before removal).
|
|
249
|
-
*/
|
|
250
|
-
delete(namespace: string, key: string): Promise<{
|
|
251
|
-
deleted: boolean;
|
|
252
|
-
key: string;
|
|
253
|
-
namespace: string;
|
|
254
|
-
new_merkle_root: string;
|
|
255
|
-
deleted_at: string;
|
|
256
|
-
}>;
|
|
257
|
-
/**
|
|
258
|
-
* Export all state for a namespace as an encrypted bundle.
|
|
259
|
-
*/
|
|
260
|
-
export(namespace?: string): Promise<{
|
|
261
|
-
bundle: string;
|
|
262
|
-
namespaces: string[];
|
|
263
|
-
total_keys: number;
|
|
264
|
-
bundle_hash: string;
|
|
265
|
-
exported_at: string;
|
|
266
|
-
}>;
|
|
267
|
-
/**
|
|
268
|
-
* Import a previously exported state bundle.
|
|
269
|
-
*/
|
|
270
|
-
import(bundleBase64: string, conflictResolution: "skip" | "overwrite" | "version" | undefined, publicKeyResolver: (kid: string) => Uint8Array | null): Promise<{
|
|
271
|
-
imported_keys: number;
|
|
272
|
-
skipped_keys: number;
|
|
273
|
-
skipped_invalid_sig: number;
|
|
274
|
-
skipped_unknown_kid: number;
|
|
275
|
-
conflicts: number;
|
|
276
|
-
namespaces: string[];
|
|
277
|
-
imported_at: string;
|
|
278
|
-
}>;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
129
|
/**
|
|
282
130
|
* Sanctuary MCP Server — L2 Operational Isolation: Audit Log
|
|
283
131
|
*
|
|
@@ -297,17 +145,31 @@ interface AuditEntry {
|
|
|
297
145
|
result: "success" | "failure";
|
|
298
146
|
details?: Record<string, unknown>;
|
|
299
147
|
}
|
|
148
|
+
interface AuditLogConfig {
|
|
149
|
+
/** Maximum total size of stored audit entries in bytes. Default: 100 MB. */
|
|
150
|
+
maxTotalSizeBytes?: number;
|
|
151
|
+
/** Maximum number of stored audit entry files to retain. Default: 100_000. */
|
|
152
|
+
maxEntries?: number;
|
|
153
|
+
}
|
|
300
154
|
declare class AuditLog {
|
|
301
155
|
private storage;
|
|
302
156
|
private encryptionKey;
|
|
303
157
|
private entries;
|
|
304
158
|
private counter;
|
|
305
|
-
|
|
159
|
+
private readonly maxTotalSizeBytes;
|
|
160
|
+
private readonly maxEntries;
|
|
161
|
+
private rotationInFlight;
|
|
162
|
+
constructor(storage: StorageBackend, masterKey: Uint8Array, config?: AuditLogConfig);
|
|
306
163
|
/**
|
|
307
164
|
* Append an audit entry.
|
|
308
165
|
*/
|
|
309
166
|
append(layer: AuditEntry["layer"], operation: string, identityId: string, details?: Record<string, unknown>, result?: "success" | "failure"): void;
|
|
310
167
|
private persistEntry;
|
|
168
|
+
/**
|
|
169
|
+
* Prune oldest audit entries when storage exceeds configured limits.
|
|
170
|
+
* Entries are sorted by key (timestamp-based) so oldest are pruned first.
|
|
171
|
+
*/
|
|
172
|
+
private maybeRotate;
|
|
311
173
|
/**
|
|
312
174
|
* Query the audit log with filtering.
|
|
313
175
|
*/
|
|
@@ -328,942 +190,1010 @@ declare class AuditLog {
|
|
|
328
190
|
}
|
|
329
191
|
|
|
330
192
|
/**
|
|
331
|
-
* Sanctuary MCP Server —
|
|
332
|
-
*
|
|
333
|
-
* Cryptographic commitments allow an agent to commit to a value
|
|
334
|
-
* without revealing it, then later prove what was committed.
|
|
335
|
-
*
|
|
336
|
-
* This is the MVS approach to selective disclosure — simpler than
|
|
337
|
-
* full ZK proofs but still cryptographically sound. The commitment
|
|
338
|
-
* is SHA-256(value || blinding_factor), which is:
|
|
339
|
-
* - Hiding: the commitment reveals nothing about the value
|
|
340
|
-
* - Binding: the committer cannot change the value after committing
|
|
193
|
+
* Sanctuary MCP Server — Principal Policy Types
|
|
341
194
|
*
|
|
342
|
-
*
|
|
343
|
-
*
|
|
344
|
-
*
|
|
345
|
-
* - Revealed values are verified via constant-time comparison
|
|
195
|
+
* Type definitions for the Principal Policy system.
|
|
196
|
+
* The Principal Policy is the human-controlled, agent-immutable
|
|
197
|
+
* configuration that gates operations through approval tiers.
|
|
346
198
|
*/
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
/**
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
revealed: boolean;
|
|
364
|
-
revealed_at?: string;
|
|
199
|
+
/** Tier 2 anomaly action: what to do when an anomaly is detected */
|
|
200
|
+
type AnomalyAction = "approve" | "log" | "allow";
|
|
201
|
+
/** Tier 2 anomaly detection configuration */
|
|
202
|
+
interface Tier2Config {
|
|
203
|
+
/** Action when agent accesses a namespace it hasn't used before */
|
|
204
|
+
new_namespace_access: AnomalyAction;
|
|
205
|
+
/** Action when agent interacts with an unknown counterparty DID */
|
|
206
|
+
new_counterparty: AnomalyAction;
|
|
207
|
+
/** Tool call frequency multiplier that triggers anomaly */
|
|
208
|
+
frequency_spike_multiplier: number;
|
|
209
|
+
/** Maximum signing operations per minute before triggering */
|
|
210
|
+
max_signs_per_minute: number;
|
|
211
|
+
/** Reading more than N keys in a namespace within 60 seconds */
|
|
212
|
+
bulk_read_threshold: number;
|
|
213
|
+
/** Policy for first session when no baseline exists */
|
|
214
|
+
first_session_policy: AnomalyAction;
|
|
365
215
|
}
|
|
366
|
-
/**
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
private storage;
|
|
371
|
-
private encryptionKey;
|
|
372
|
-
constructor(storage: StorageBackend, masterKey: Uint8Array);
|
|
373
|
-
/**
|
|
374
|
-
* Store a commitment (encrypted) for later reference.
|
|
375
|
-
*/
|
|
376
|
-
store(commitment: Commitment, value: string): Promise<string>;
|
|
377
|
-
/**
|
|
378
|
-
* Retrieve a stored commitment by ID.
|
|
379
|
-
*/
|
|
380
|
-
get(id: string): Promise<StoredCommitment | null>;
|
|
216
|
+
/** Approval channel configuration */
|
|
217
|
+
interface ApprovalChannelConfig {
|
|
218
|
+
type: "stderr" | "webhook" | "callback";
|
|
219
|
+
timeout_seconds: number;
|
|
381
220
|
/**
|
|
382
|
-
*
|
|
221
|
+
* SEC-002: auto_deny is hardcoded to true and not configurable.
|
|
222
|
+
* Timeout on any approval channel ALWAYS results in denial.
|
|
223
|
+
* This field is retained for backward compatibility with existing
|
|
224
|
+
* policy files but is ignored — timeout always denies.
|
|
383
225
|
*/
|
|
384
|
-
|
|
226
|
+
auto_deny?: boolean;
|
|
227
|
+
webhook_url?: string;
|
|
228
|
+
webhook_secret?: string;
|
|
385
229
|
}
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
* Ristretto255 is available via @noble/curves/ed25519, which we already depend on.
|
|
398
|
-
* This is genuine zero-knowledge — proofs reveal nothing beyond the stated property.
|
|
399
|
-
*
|
|
400
|
-
* Architecture note:
|
|
401
|
-
* The existing commitment scheme (SHA-256 based) remains available for backward
|
|
402
|
-
* compatibility. The ZK proofs operate on a separate Pedersen commitment system
|
|
403
|
-
* that provides algebraic structure for proper ZK properties.
|
|
404
|
-
*
|
|
405
|
-
* Security invariants:
|
|
406
|
-
* - Generator H is derived via hash-to-curve (nothing-up-my-sleeve)
|
|
407
|
-
* - Blinding factors are cryptographically random (32 bytes)
|
|
408
|
-
* - Fiat-Shamir challenges use domain-separated hashing
|
|
409
|
-
* - Range proofs use a bit-decomposition approach (sound but logarithmic size)
|
|
410
|
-
*/
|
|
411
|
-
/** A Pedersen commitment: C = v*G + b*H */
|
|
412
|
-
interface PedersenCommitment {
|
|
413
|
-
/** The commitment point (encoded as base64url) */
|
|
414
|
-
commitment: string;
|
|
415
|
-
/** The blinding factor b (base64url, 32 bytes) — keep secret */
|
|
416
|
-
blinding_factor: string;
|
|
417
|
-
/** When the commitment was created */
|
|
418
|
-
committed_at: string;
|
|
230
|
+
/** Complete Principal Policy */
|
|
231
|
+
interface PrincipalPolicy {
|
|
232
|
+
version: number;
|
|
233
|
+
/** Operations that always require human approval */
|
|
234
|
+
tier1_always_approve: string[];
|
|
235
|
+
/** Behavioral anomaly detection configuration */
|
|
236
|
+
tier2_anomaly: Tier2Config;
|
|
237
|
+
/** Operations that never require approval (audit only) */
|
|
238
|
+
tier3_always_allow: string[];
|
|
239
|
+
/** How approval requests reach the human */
|
|
240
|
+
approval_channel: ApprovalChannelConfig;
|
|
419
241
|
}
|
|
420
|
-
/**
|
|
421
|
-
interface
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
announcement: string;
|
|
428
|
-
/** Response scalar s_v (base64url) */
|
|
429
|
-
response_v: string;
|
|
430
|
-
/** Response scalar s_b (base64url) */
|
|
431
|
-
response_b: string;
|
|
432
|
-
/** Proof generated at */
|
|
433
|
-
generated_at: string;
|
|
242
|
+
/** Approval request sent to the human */
|
|
243
|
+
interface ApprovalRequest {
|
|
244
|
+
operation: string;
|
|
245
|
+
tier: 1 | 2;
|
|
246
|
+
reason: string;
|
|
247
|
+
context: Record<string, unknown>;
|
|
248
|
+
timestamp: string;
|
|
434
249
|
}
|
|
435
|
-
/**
|
|
436
|
-
interface
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
/**
|
|
462
|
-
|
|
250
|
+
/** Approval response from the human */
|
|
251
|
+
interface ApprovalResponse {
|
|
252
|
+
decision: "approve" | "deny";
|
|
253
|
+
decided_at: string;
|
|
254
|
+
decided_by: "human" | "timeout" | "auto" | "stderr:non-interactive";
|
|
255
|
+
}
|
|
256
|
+
/** Result of the approval gate evaluation */
|
|
257
|
+
interface GateResult {
|
|
258
|
+
allowed: boolean;
|
|
259
|
+
tier: 1 | 2 | 3;
|
|
260
|
+
reason: string;
|
|
261
|
+
approval_required: boolean;
|
|
262
|
+
approval_response?: ApprovalResponse;
|
|
263
|
+
}
|
|
264
|
+
/** Behavioral baseline for anomaly detection */
|
|
265
|
+
interface SessionProfile {
|
|
266
|
+
/** Namespaces accessed (read or write) */
|
|
267
|
+
known_namespaces: string[];
|
|
268
|
+
/** Counterparty DIDs seen in reputation operations */
|
|
269
|
+
known_counterparties: string[];
|
|
270
|
+
/** Tool call counts per tool name (lifetime in session) */
|
|
271
|
+
tool_call_counts: Record<string, number>;
|
|
272
|
+
/** Whether this is the first session (no prior baseline) */
|
|
273
|
+
is_first_session: boolean;
|
|
274
|
+
/** Session start time */
|
|
275
|
+
started_at: string;
|
|
276
|
+
/** When the baseline was last saved */
|
|
277
|
+
saved_at?: string;
|
|
463
278
|
}
|
|
279
|
+
|
|
464
280
|
/**
|
|
465
|
-
*
|
|
466
|
-
*
|
|
467
|
-
* C = v*G + b*H
|
|
468
|
-
*
|
|
469
|
-
* Properties:
|
|
470
|
-
* - Computationally hiding (under discrete log assumption)
|
|
471
|
-
* - Perfectly binding (information-theoretic)
|
|
472
|
-
* - Homomorphic: C(v1) + C(v2) = C(v1+v2) with adjusted blinding
|
|
281
|
+
* Sanctuary MCP Server — Approval Channel
|
|
473
282
|
*
|
|
474
|
-
*
|
|
475
|
-
*
|
|
476
|
-
|
|
477
|
-
declare function createPedersenCommitment(value: number): PedersenCommitment;
|
|
478
|
-
/**
|
|
479
|
-
* Verify a Pedersen commitment against a revealed value and blinding factor.
|
|
283
|
+
* Out-of-band communication with the human principal for operation approval.
|
|
284
|
+
* The default channel uses stderr (outside MCP's stdin/stdout protocol),
|
|
285
|
+
* ensuring the agent cannot intercept or forge approval responses.
|
|
480
286
|
*
|
|
481
|
-
*
|
|
287
|
+
* Security invariant:
|
|
288
|
+
* - Approval prompts go through a channel the agent cannot access.
|
|
289
|
+
* - Timeouts result in denial by default (fail closed).
|
|
482
290
|
*/
|
|
483
|
-
|
|
291
|
+
|
|
292
|
+
/** Abstract approval channel interface */
|
|
293
|
+
interface ApprovalChannel {
|
|
294
|
+
requestApproval(request: ApprovalRequest): Promise<ApprovalResponse>;
|
|
295
|
+
}
|
|
484
296
|
/**
|
|
485
|
-
*
|
|
486
|
-
* of a Pedersen commitment C = v*G + b*H.
|
|
487
|
-
*
|
|
488
|
-
* Schnorr sigma protocol with Fiat-Shamir transform:
|
|
489
|
-
* 1. Pick random r_v, r_b
|
|
490
|
-
* 2. Compute R = r_v*G + r_b*H (announcement)
|
|
491
|
-
* 3. Compute e = H_FS(C || R) (challenge via Fiat-Shamir)
|
|
492
|
-
* 4. Compute s_v = r_v + e*v, s_b = r_b + e*b (responses)
|
|
493
|
-
* 5. Proof = (R, s_v, s_b)
|
|
297
|
+
* Stderr approval channel — non-interactive informational channel.
|
|
494
298
|
*
|
|
495
|
-
*
|
|
496
|
-
*
|
|
299
|
+
* In the MCP stdio model:
|
|
300
|
+
* - stdin/stdout carry the MCP protocol (JSON-RPC)
|
|
301
|
+
* - stderr is available for out-of-band human communication
|
|
497
302
|
*
|
|
498
|
-
*
|
|
499
|
-
*
|
|
500
|
-
*
|
|
501
|
-
|
|
502
|
-
declare function createProofOfKnowledge(value: number, blindingFactor: string, commitment: string): ZKProofOfKnowledge;
|
|
503
|
-
/**
|
|
504
|
-
* Verify a ZK proof of knowledge of a commitment's opening.
|
|
303
|
+
* Because stdin is consumed by the MCP JSON-RPC transport, this channel
|
|
304
|
+
* CANNOT read interactive human input. It is strictly informational:
|
|
305
|
+
* the prompt is displayed so the human sees what is happening, and the
|
|
306
|
+
* operation is denied immediately.
|
|
505
307
|
*
|
|
506
|
-
*
|
|
308
|
+
* SEC-002 + SEC-016 invariants:
|
|
309
|
+
* - This channel ALWAYS denies. No configuration can change this.
|
|
310
|
+
* - There is no timeout or async delay — denial is synchronous.
|
|
311
|
+
* - The `auto_deny` config field is ignored (SEC-002).
|
|
312
|
+
* - For interactive approval, use the dashboard or webhook channel.
|
|
507
313
|
*/
|
|
508
|
-
declare
|
|
314
|
+
declare class StderrApprovalChannel implements ApprovalChannel {
|
|
315
|
+
constructor(_config: ApprovalChannelConfig);
|
|
316
|
+
requestApproval(request: ApprovalRequest): Promise<ApprovalResponse>;
|
|
317
|
+
private formatPrompt;
|
|
318
|
+
}
|
|
509
319
|
/**
|
|
510
|
-
*
|
|
511
|
-
*
|
|
512
|
-
* Approach: bit-decomposition of (value - min) into n bits where 2^n > max - min.
|
|
513
|
-
* Each bit gets a Pedersen commitment and a proof it's 0 or 1.
|
|
514
|
-
* A sum proof shows the bit commitments reconstruct the original commitment
|
|
515
|
-
* (shifted by min).
|
|
516
|
-
*
|
|
517
|
-
* @param value - The committed value
|
|
518
|
-
* @param blindingFactor - The blinding factor (base64url)
|
|
519
|
-
* @param commitment - The commitment (base64url)
|
|
520
|
-
* @param min - Minimum value (inclusive)
|
|
521
|
-
* @param max - Maximum value (inclusive)
|
|
320
|
+
* Programmatic approval channel — for testing and API integration.
|
|
522
321
|
*/
|
|
523
|
-
declare
|
|
524
|
-
|
|
525
|
-
|
|
322
|
+
declare class CallbackApprovalChannel implements ApprovalChannel {
|
|
323
|
+
private callback;
|
|
324
|
+
constructor(callback: (request: ApprovalRequest) => Promise<ApprovalResponse>);
|
|
325
|
+
requestApproval(request: ApprovalRequest): Promise<ApprovalResponse>;
|
|
326
|
+
}
|
|
526
327
|
/**
|
|
527
|
-
*
|
|
328
|
+
* Auto-approve channel — for testing. Approves everything.
|
|
528
329
|
*/
|
|
529
|
-
declare
|
|
330
|
+
declare class AutoApproveChannel implements ApprovalChannel {
|
|
331
|
+
requestApproval(_request: ApprovalRequest): Promise<ApprovalResponse>;
|
|
332
|
+
}
|
|
530
333
|
|
|
531
334
|
/**
|
|
532
|
-
* Sanctuary MCP Server —
|
|
533
|
-
*
|
|
534
|
-
* Disclosure policies define what an agent will and will not disclose
|
|
535
|
-
* in different interaction contexts. Policies are evaluated against
|
|
536
|
-
* incoming disclosure requests to produce per-field decisions.
|
|
335
|
+
* Sanctuary MCP Server — Behavioral Baseline Tracker
|
|
537
336
|
*
|
|
538
|
-
*
|
|
539
|
-
*
|
|
337
|
+
* Tracks the agent's behavioral profile during a session and persists
|
|
338
|
+
* it for cross-session anomaly detection. The baseline defines "normal"
|
|
339
|
+
* so that deviations can trigger Tier 2 approval.
|
|
540
340
|
*
|
|
541
341
|
* Security invariants:
|
|
542
|
-
* -
|
|
543
|
-
* -
|
|
544
|
-
* -
|
|
342
|
+
* - Baseline is stored encrypted under L1 sovereignty
|
|
343
|
+
* - Baseline changes are audit-logged
|
|
344
|
+
* - Baseline is integrity-verified via L1 Merkle tree
|
|
345
|
+
* - No MCP tool can directly modify the baseline
|
|
545
346
|
*/
|
|
546
347
|
|
|
547
|
-
|
|
548
|
-
interface DisclosureRule {
|
|
549
|
-
/** Interaction context this rule applies to */
|
|
550
|
-
context: string;
|
|
551
|
-
/** Fields/claims the agent MAY disclose */
|
|
552
|
-
disclose: string[];
|
|
553
|
-
/** Fields/claims the agent MUST NOT disclose */
|
|
554
|
-
withhold: string[];
|
|
555
|
-
/** Fields that require proof rather than plain disclosure */
|
|
556
|
-
proof_required: string[];
|
|
557
|
-
}
|
|
558
|
-
/** A complete disclosure policy */
|
|
559
|
-
interface DisclosurePolicy {
|
|
560
|
-
policy_id: string;
|
|
561
|
-
policy_name: string;
|
|
562
|
-
rules: DisclosureRule[];
|
|
563
|
-
default_action: "withhold" | "ask-principal";
|
|
564
|
-
identity_id?: string;
|
|
565
|
-
created_at: string;
|
|
566
|
-
updated_at: string;
|
|
567
|
-
}
|
|
568
|
-
/**
|
|
569
|
-
* Policy store — manages disclosure policies encrypted under L1 sovereignty.
|
|
570
|
-
*/
|
|
571
|
-
declare class PolicyStore {
|
|
348
|
+
declare class BaselineTracker {
|
|
572
349
|
private storage;
|
|
573
350
|
private encryptionKey;
|
|
574
|
-
private
|
|
351
|
+
private profile;
|
|
352
|
+
/** Sliding window: timestamps of tool calls per tool name (last 60s) */
|
|
353
|
+
private callWindows;
|
|
354
|
+
/** Sliding window: read counts per namespace (last 60s) */
|
|
355
|
+
private readWindows;
|
|
356
|
+
/** Sliding window: sign call timestamps (last 60s) */
|
|
357
|
+
private signWindow;
|
|
575
358
|
constructor(storage: StorageBackend, masterKey: Uint8Array);
|
|
576
359
|
/**
|
|
577
|
-
*
|
|
360
|
+
* Load the previous session's baseline from storage.
|
|
361
|
+
* If none exists, this is a first session.
|
|
578
362
|
*/
|
|
579
|
-
|
|
363
|
+
load(): Promise<void>;
|
|
580
364
|
/**
|
|
581
|
-
*
|
|
365
|
+
* Save the current baseline to storage (encrypted).
|
|
366
|
+
* Called at session end or periodically.
|
|
582
367
|
*/
|
|
583
|
-
|
|
368
|
+
save(): Promise<void>;
|
|
584
369
|
/**
|
|
585
|
-
*
|
|
370
|
+
* Record a tool call for baseline tracking.
|
|
371
|
+
* Returns anomaly information if applicable.
|
|
586
372
|
*/
|
|
587
|
-
|
|
373
|
+
recordToolCall(toolName: string): void;
|
|
588
374
|
/**
|
|
589
|
-
*
|
|
375
|
+
* Record a namespace access.
|
|
376
|
+
* @returns true if this is a new namespace (not in baseline)
|
|
590
377
|
*/
|
|
591
|
-
|
|
592
|
-
|
|
378
|
+
recordNamespaceAccess(namespace: string): boolean;
|
|
379
|
+
/**
|
|
380
|
+
* Record a namespace read for bulk-read detection.
|
|
381
|
+
* @returns the number of reads in the current 60-second window
|
|
382
|
+
*/
|
|
383
|
+
recordNamespaceRead(namespace: string): number;
|
|
384
|
+
/**
|
|
385
|
+
* Record a counterparty DID interaction.
|
|
386
|
+
* @returns true if this is a new counterparty (not in baseline)
|
|
387
|
+
*/
|
|
388
|
+
recordCounterparty(did: string): boolean;
|
|
389
|
+
/**
|
|
390
|
+
* Record a signing operation.
|
|
391
|
+
* @returns the number of signs in the current 60-second window
|
|
392
|
+
*/
|
|
393
|
+
recordSign(): number;
|
|
394
|
+
/**
|
|
395
|
+
* Get the current call rate for a tool (calls per minute).
|
|
396
|
+
*/
|
|
397
|
+
getCallRate(toolName: string): number;
|
|
398
|
+
/**
|
|
399
|
+
* Get the average call rate across all tools in the baseline.
|
|
400
|
+
*/
|
|
401
|
+
getAverageCallRate(): number;
|
|
402
|
+
/** Whether this is the first session */
|
|
403
|
+
get isFirstSession(): boolean;
|
|
404
|
+
/** Get a read-only view of the current profile */
|
|
405
|
+
getProfile(): SessionProfile;
|
|
593
406
|
}
|
|
594
407
|
|
|
595
408
|
/**
|
|
596
|
-
* Sanctuary MCP Server —
|
|
597
|
-
*
|
|
598
|
-
* Sovereign identity based on Ed25519 keypairs.
|
|
599
|
-
* Private keys are always encrypted at rest — never stored in plaintext.
|
|
409
|
+
* Sanctuary MCP Server — Prompt Injection Detection Layer
|
|
600
410
|
*
|
|
601
|
-
*
|
|
602
|
-
*
|
|
603
|
-
*
|
|
604
|
-
* - Key rotation produces a signed rotation event (verifiable chain)
|
|
605
|
-
*/
|
|
606
|
-
|
|
607
|
-
/** Public identity information (safe to share) */
|
|
608
|
-
interface PublicIdentity {
|
|
609
|
-
identity_id: string;
|
|
610
|
-
label: string;
|
|
611
|
-
public_key: string;
|
|
612
|
-
did: string;
|
|
613
|
-
created_at: string;
|
|
614
|
-
key_type: "ed25519";
|
|
615
|
-
key_protection: "passphrase" | "hardware-key" | "recovery-key";
|
|
616
|
-
}
|
|
617
|
-
/** Stored identity (private key is encrypted) */
|
|
618
|
-
interface StoredIdentity extends PublicIdentity {
|
|
619
|
-
encrypted_private_key: EncryptedPayload;
|
|
620
|
-
/** Previous public keys (for rotation chain verification) */
|
|
621
|
-
rotation_history: Array<{
|
|
622
|
-
old_public_key: string;
|
|
623
|
-
new_public_key: string;
|
|
624
|
-
rotation_event: string;
|
|
625
|
-
rotated_at: string;
|
|
626
|
-
}>;
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
/**
|
|
630
|
-
* Sanctuary MCP Server — Sovereignty Health Report (SHR) Types
|
|
411
|
+
* Fast, zero-dependency detection of common prompt injection patterns.
|
|
412
|
+
* Scans tool arguments for role override, security bypass, encoding evasion,
|
|
413
|
+
* data exfiltration, and prompt stuffing signals.
|
|
631
414
|
*
|
|
632
|
-
*
|
|
633
|
-
*
|
|
634
|
-
* The SHR is signed by one of the instance's Ed25519 identities and can be
|
|
635
|
-
* independently verified by any party without trusting the presenter.
|
|
415
|
+
* SEC-034/SEC-035: Enhanced with Unicode sanitization pre-pass, decoded content
|
|
416
|
+
* re-scanning, token budget analysis, and outbound content scanning.
|
|
636
417
|
*
|
|
637
|
-
*
|
|
418
|
+
* Security invariants:
|
|
419
|
+
* - Always returns a result, never throws
|
|
420
|
+
* - Typical scan completes in < 5ms
|
|
421
|
+
* - False positives minimized via field-aware scanning
|
|
422
|
+
* - Recursive scanning of nested objects/arrays
|
|
423
|
+
* - Outbound scanning catches secret leaks and injection artifact survival
|
|
638
424
|
*/
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
encryption: string;
|
|
645
|
-
key_custody: "self" | "delegated" | "platform";
|
|
646
|
-
integrity: string;
|
|
647
|
-
identity_type: string;
|
|
648
|
-
state_portable: boolean;
|
|
649
|
-
}
|
|
650
|
-
interface SHRLayerL2 {
|
|
651
|
-
status: LayerStatus;
|
|
652
|
-
isolation_type: string;
|
|
653
|
-
attestation_available: boolean;
|
|
654
|
-
/** Model provenance: what inference model(s) power this agent */
|
|
655
|
-
model_provenance?: {
|
|
656
|
-
model_id: string;
|
|
657
|
-
model_name: string;
|
|
658
|
-
provider: string;
|
|
659
|
-
open_weights: boolean;
|
|
660
|
-
open_source: boolean;
|
|
661
|
-
local_inference: boolean;
|
|
662
|
-
weights_hash?: string;
|
|
663
|
-
};
|
|
664
|
-
}
|
|
665
|
-
interface SHRLayerL3 {
|
|
666
|
-
status: LayerStatus;
|
|
667
|
-
proof_system: string;
|
|
668
|
-
selective_disclosure: boolean;
|
|
669
|
-
}
|
|
670
|
-
interface SHRLayerL4 {
|
|
671
|
-
status: LayerStatus;
|
|
672
|
-
reputation_mode: string;
|
|
673
|
-
attestation_format: string;
|
|
674
|
-
reputation_portable: boolean;
|
|
425
|
+
interface InjectionDetectorConfig {
|
|
426
|
+
enabled: boolean;
|
|
427
|
+
sensitivity: "low" | "medium" | "high";
|
|
428
|
+
on_detection: "escalate" | "block" | "log";
|
|
429
|
+
custom_patterns?: string[];
|
|
675
430
|
}
|
|
676
|
-
interface
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
mitigation?: string;
|
|
431
|
+
interface InjectionSignal {
|
|
432
|
+
type: string;
|
|
433
|
+
pattern: string;
|
|
434
|
+
location: string;
|
|
435
|
+
severity: "low" | "medium" | "high";
|
|
682
436
|
}
|
|
683
|
-
interface
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
437
|
+
interface DetectionResult {
|
|
438
|
+
flagged: boolean;
|
|
439
|
+
confidence: number;
|
|
440
|
+
signals: InjectionSignal[];
|
|
441
|
+
recommendation: "allow" | "escalate" | "block";
|
|
688
442
|
}
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
443
|
+
declare class InjectionDetector {
|
|
444
|
+
private config;
|
|
445
|
+
private stats;
|
|
446
|
+
constructor(config?: Partial<InjectionDetectorConfig>);
|
|
447
|
+
/**
|
|
448
|
+
* Scan tool arguments for injection signals.
|
|
449
|
+
* @param toolName Full tool name (e.g., "state_read")
|
|
450
|
+
* @param args Tool arguments
|
|
451
|
+
* @returns DetectionResult with all detected signals
|
|
452
|
+
*/
|
|
453
|
+
scan(toolName: string, args: Record<string, unknown>): DetectionResult;
|
|
454
|
+
/**
|
|
455
|
+
* SEC-035: Scan outbound content for secret leaks, data exfiltration,
|
|
456
|
+
* internal path exposure, and injection artifact survival.
|
|
457
|
+
*
|
|
458
|
+
* @param content The outbound content string to scan
|
|
459
|
+
* @returns DetectionResult with outbound-specific signal types
|
|
460
|
+
*/
|
|
461
|
+
scanOutbound(content: string): DetectionResult;
|
|
462
|
+
/**
|
|
463
|
+
* Recursively scan a value and all nested values.
|
|
464
|
+
*/
|
|
465
|
+
private scanValue;
|
|
466
|
+
/**
|
|
467
|
+
* Scan a single string for injection signals.
|
|
468
|
+
*/
|
|
469
|
+
private scanString;
|
|
470
|
+
/**
|
|
471
|
+
* Count invisible Unicode characters in a string.
|
|
472
|
+
* Includes zero-width chars, soft hyphens, directional marks,
|
|
473
|
+
* variation selectors, and other invisible categories.
|
|
474
|
+
*/
|
|
475
|
+
private countInvisibleChars;
|
|
476
|
+
/**
|
|
477
|
+
* Strip invisible characters from a string for clean pattern matching.
|
|
478
|
+
* Returns a new string with all invisible chars removed.
|
|
479
|
+
*/
|
|
480
|
+
private stripInvisibleChars;
|
|
481
|
+
/**
|
|
482
|
+
* SEC-034: Token budget attack detection.
|
|
483
|
+
* Some Unicode sequences expand dramatically during tokenization (e.g., CJK
|
|
484
|
+
* ideographs, combining characters, emoji sequences). If the estimated token
|
|
485
|
+
* cost per character is anomalously high, this may be a wallet-drain payload.
|
|
486
|
+
*
|
|
487
|
+
* Heuristic: count chars that typically tokenize into multiple tokens.
|
|
488
|
+
* If the ratio of estimated tokens to char count exceeds 3x, flag it.
|
|
489
|
+
*/
|
|
490
|
+
private detectTokenBudgetAttack;
|
|
491
|
+
/**
|
|
492
|
+
* Detect encoded content (base64, hex, HTML entities, URL encoding),
|
|
493
|
+
* decode it, and re-scan the decoded content through injection patterns.
|
|
494
|
+
* If the decoded content contains injection patterns, flag as encoding_evasion.
|
|
495
|
+
*/
|
|
496
|
+
private detectEncodedPayloads;
|
|
497
|
+
/**
|
|
498
|
+
* Check if a string contains any injection patterns (role override or security bypass).
|
|
499
|
+
*/
|
|
500
|
+
private containsInjectionPatterns;
|
|
501
|
+
/**
|
|
502
|
+
* Safely decode a base64 string. Returns null if it's not valid base64
|
|
503
|
+
* or doesn't decode to a meaningful string.
|
|
504
|
+
*/
|
|
505
|
+
private safeBase64Decode;
|
|
506
|
+
/**
|
|
507
|
+
* Safely decode a hex string. Returns null on failure.
|
|
508
|
+
*/
|
|
509
|
+
private safeHexDecode;
|
|
510
|
+
/**
|
|
511
|
+
* Decode HTML numeric entities (&#xHH; and &#DDD;) in a string.
|
|
512
|
+
*/
|
|
513
|
+
private decodeHtmlEntities;
|
|
514
|
+
/**
|
|
515
|
+
* Safely decode a URL-encoded string. Returns null on failure.
|
|
516
|
+
*/
|
|
517
|
+
private safeUrlDecode;
|
|
518
|
+
/**
|
|
519
|
+
* Heuristic: does this look like readable text (vs. binary garbage)?
|
|
520
|
+
* Checks that most characters are printable ASCII or common Unicode.
|
|
521
|
+
*/
|
|
522
|
+
private looksLikeText;
|
|
523
|
+
/**
|
|
524
|
+
* Detect API keys and secrets in outbound content.
|
|
525
|
+
*/
|
|
526
|
+
private detectSecretPatterns;
|
|
527
|
+
/**
|
|
528
|
+
* Detect data exfiltration via markdown images with data-carrying query params.
|
|
529
|
+
*/
|
|
530
|
+
private detectOutboundExfiltration;
|
|
531
|
+
/**
|
|
532
|
+
* Detect internal filesystem path leaks in outbound content.
|
|
533
|
+
*/
|
|
534
|
+
private detectInternalPathLeaks;
|
|
535
|
+
/**
|
|
536
|
+
* Detect private IP addresses and localhost references in outbound content.
|
|
537
|
+
*/
|
|
538
|
+
private detectPrivateNetworkLeaks;
|
|
539
|
+
/**
|
|
540
|
+
* Detect role markers / prompt template artifacts in outbound content.
|
|
541
|
+
* These should never appear in agent output — their presence indicates
|
|
542
|
+
* injection artifact survival.
|
|
543
|
+
*/
|
|
544
|
+
private detectOutputRoleMarkers;
|
|
545
|
+
/**
|
|
546
|
+
* Detect base64 strings, base64url, and zero-width character evasion.
|
|
547
|
+
*/
|
|
548
|
+
private detectEncodingEvasion;
|
|
549
|
+
/**
|
|
550
|
+
* Detect URLs and emails in fields that shouldn't have them.
|
|
551
|
+
*/
|
|
552
|
+
private detectDataExfiltration;
|
|
553
|
+
/**
|
|
554
|
+
* Detect prompt stuffing: very large strings or high repetition.
|
|
555
|
+
*/
|
|
556
|
+
private detectPromptStuffing;
|
|
557
|
+
/**
|
|
558
|
+
* Determine if this field is inherently safe from role override.
|
|
559
|
+
*/
|
|
560
|
+
private isSafeField;
|
|
561
|
+
/**
|
|
562
|
+
* Determine if this is a tool name field (where tool refs are expected).
|
|
563
|
+
*/
|
|
564
|
+
private isToolNameField;
|
|
565
|
+
/**
|
|
566
|
+
* Determine if this field is safe for URLs.
|
|
567
|
+
*/
|
|
568
|
+
private isUrlSafeField;
|
|
569
|
+
/**
|
|
570
|
+
* Determine if this field is safe for emails.
|
|
571
|
+
*/
|
|
572
|
+
private isEmailSafeField;
|
|
573
|
+
/**
|
|
574
|
+
* Determine if this field is safe for structured data (JSON/XML).
|
|
575
|
+
*/
|
|
576
|
+
private isStructuredField;
|
|
577
|
+
/**
|
|
578
|
+
* SEC-032/SEC-034: Map common cross-script confusable characters to their
|
|
579
|
+
* Latin equivalents. NFKC normalization handles fullwidth and compatibility
|
|
580
|
+
* forms, but does NOT map Cyrillic/Greek/Armenian/Georgian lookalikes to
|
|
581
|
+
* Latin (they're distinct codepoints by design).
|
|
582
|
+
*
|
|
583
|
+
* Extended to 50+ confusable pairs covering Cyrillic, Greek, Armenian,
|
|
584
|
+
* Georgian, Cherokee, and mathematical/symbol lookalikes.
|
|
585
|
+
*/
|
|
586
|
+
private normalizeConfusables;
|
|
587
|
+
/**
|
|
588
|
+
* Compute confidence score based on signals.
|
|
589
|
+
* More high-severity signals = higher confidence.
|
|
590
|
+
*/
|
|
591
|
+
private computeConfidence;
|
|
592
|
+
/**
|
|
593
|
+
* Compute recommendation based on signals and sensitivity.
|
|
594
|
+
*/
|
|
595
|
+
private computeRecommendation;
|
|
596
|
+
/**
|
|
597
|
+
* Get statistics about scans performed.
|
|
598
|
+
*/
|
|
599
|
+
getStats(): {
|
|
600
|
+
total_scans: number;
|
|
601
|
+
total_flags: number;
|
|
602
|
+
total_blocks: number;
|
|
603
|
+
signals_by_type: Record<string, number>;
|
|
708
604
|
};
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
* The complete signed SHR — body + signature envelope.
|
|
714
|
-
*/
|
|
715
|
-
interface SignedSHR {
|
|
716
|
-
body: SHRBody;
|
|
717
|
-
signed_by: string;
|
|
718
|
-
signature: string;
|
|
719
|
-
}
|
|
720
|
-
interface SHRVerificationResult {
|
|
721
|
-
valid: boolean;
|
|
722
|
-
errors: string[];
|
|
723
|
-
warnings: string[];
|
|
724
|
-
sovereignty_level: "full" | "degraded" | "minimal";
|
|
725
|
-
counterparty_id: string;
|
|
726
|
-
expires_at: string;
|
|
727
|
-
}
|
|
728
|
-
|
|
729
|
-
/**
|
|
730
|
-
* Sanctuary MCP Server — Sovereignty Handshake Types
|
|
731
|
-
*
|
|
732
|
-
* The sovereignty handshake is a mutual verification protocol between
|
|
733
|
-
* two Sanctuary instances. Each party presents its SHR and proves
|
|
734
|
-
* liveness via nonce challenge-response.
|
|
735
|
-
*
|
|
736
|
-
* Protocol:
|
|
737
|
-
* A → B: HandshakeChallenge (A's SHR + nonce)
|
|
738
|
-
* B → A: HandshakeResponse (B's SHR + B's nonce + signature over A's nonce)
|
|
739
|
-
* A → B: HandshakeCompletion (signature over B's nonce)
|
|
740
|
-
* Result: Both hold a HandshakeResult with verified counterparty status
|
|
741
|
-
*/
|
|
742
|
-
|
|
743
|
-
/** Trust tier derived from sovereignty handshake */
|
|
744
|
-
type TrustTier = "verified-sovereign" | "verified-degraded" | "unverified";
|
|
745
|
-
/** Sovereignty level from SHR assessment */
|
|
746
|
-
type SovereigntyLevel = "full" | "degraded" | "minimal" | "unverified";
|
|
747
|
-
/**
|
|
748
|
-
* Step 1: Initiator sends challenge
|
|
749
|
-
*/
|
|
750
|
-
interface HandshakeChallenge {
|
|
751
|
-
protocol_version: "1.0";
|
|
752
|
-
shr: SignedSHR;
|
|
753
|
-
nonce: string;
|
|
754
|
-
initiated_at: string;
|
|
755
|
-
}
|
|
756
|
-
/**
|
|
757
|
-
* Step 2: Responder sends response
|
|
758
|
-
*/
|
|
759
|
-
interface HandshakeResponse {
|
|
760
|
-
protocol_version: "1.0";
|
|
761
|
-
shr: SignedSHR;
|
|
762
|
-
responder_nonce: string;
|
|
763
|
-
initiator_nonce_signature: string;
|
|
764
|
-
responded_at: string;
|
|
765
|
-
}
|
|
766
|
-
/**
|
|
767
|
-
* Step 3: Initiator sends completion
|
|
768
|
-
*/
|
|
769
|
-
interface HandshakeCompletion {
|
|
770
|
-
protocol_version: "1.0";
|
|
771
|
-
responder_nonce_signature: string;
|
|
772
|
-
completed_at: string;
|
|
773
|
-
}
|
|
774
|
-
/**
|
|
775
|
-
* Final result: both parties hold this after a successful handshake
|
|
776
|
-
*/
|
|
777
|
-
interface HandshakeResult {
|
|
778
|
-
counterparty_id: string;
|
|
779
|
-
counterparty_shr: SignedSHR;
|
|
780
|
-
verified: boolean;
|
|
781
|
-
sovereignty_level: SovereigntyLevel;
|
|
782
|
-
trust_tier: TrustTier;
|
|
783
|
-
completed_at: string;
|
|
784
|
-
expires_at: string;
|
|
785
|
-
errors: string[];
|
|
786
|
-
}
|
|
787
|
-
/**
|
|
788
|
-
* In-progress handshake state (stored on initiator side)
|
|
789
|
-
*/
|
|
790
|
-
interface HandshakeSession {
|
|
791
|
-
session_id: string;
|
|
792
|
-
role: "initiator" | "responder";
|
|
793
|
-
state: "initiated" | "responded" | "completed" | "failed";
|
|
794
|
-
our_nonce: string;
|
|
795
|
-
their_nonce?: string;
|
|
796
|
-
our_shr: SignedSHR;
|
|
797
|
-
their_shr?: SignedSHR;
|
|
798
|
-
initiated_at: string;
|
|
799
|
-
result?: HandshakeResult;
|
|
605
|
+
/**
|
|
606
|
+
* Reset statistics.
|
|
607
|
+
*/
|
|
608
|
+
resetStats(): void;
|
|
800
609
|
}
|
|
801
610
|
|
|
802
611
|
/**
|
|
803
|
-
* Sanctuary MCP Server —
|
|
612
|
+
* Sanctuary MCP Server — Approval Gate
|
|
804
613
|
*
|
|
805
|
-
*
|
|
806
|
-
*
|
|
807
|
-
* reputation, attestations from verified-sovereign agents carry more weight
|
|
808
|
-
* than those from unverified agents.
|
|
614
|
+
* The three-tier approval gate sits between the MCP router and tool handlers.
|
|
615
|
+
* Every tool call passes through the gate before execution.
|
|
809
616
|
*
|
|
810
|
-
*
|
|
811
|
-
*
|
|
812
|
-
*
|
|
813
|
-
*
|
|
814
|
-
* 4. "unverified" — no Sanctuary identity or sovereignty proof
|
|
617
|
+
* Evaluation order:
|
|
618
|
+
* 1. Tier 1: Is this operation in the always-approve list? → Request approval.
|
|
619
|
+
* 2. Tier 2: Does this call represent a behavioral anomaly? → Request approval.
|
|
620
|
+
* 3. Tier 3 / default: Allow with audit logging.
|
|
815
621
|
*
|
|
816
|
-
*
|
|
817
|
-
*
|
|
622
|
+
* Security invariants:
|
|
623
|
+
* - The gate cannot be bypassed — it wraps every tool handler.
|
|
624
|
+
* - Denial responses do not reveal policy details to the agent.
|
|
625
|
+
* - All gate decisions (approve, deny, allow) are audit-logged.
|
|
818
626
|
*/
|
|
819
627
|
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
628
|
+
/** Callback invoked when an injection is detected, for dashboard broadcasting */
|
|
629
|
+
type InjectionAlertCallback = (alert: {
|
|
630
|
+
toolName: string;
|
|
631
|
+
result: DetectionResult;
|
|
632
|
+
timestamp: string;
|
|
633
|
+
}) => void;
|
|
634
|
+
/** Resolver for proxy tool tiers — provided by the ProxyRouter */
|
|
635
|
+
type ProxyTierResolver = (toolName: string) => (1 | 2 | 3) | null;
|
|
636
|
+
declare class ApprovalGate {
|
|
637
|
+
private policy;
|
|
638
|
+
private baseline;
|
|
639
|
+
private channel;
|
|
640
|
+
private auditLog;
|
|
641
|
+
private injectionDetector;
|
|
642
|
+
private onInjectionAlert?;
|
|
643
|
+
private proxyTierResolver?;
|
|
644
|
+
constructor(policy: PrincipalPolicy, baseline: BaselineTracker, channel: ApprovalChannel, auditLog: AuditLog, injectionDetector?: InjectionDetector, onInjectionAlert?: InjectionAlertCallback);
|
|
645
|
+
/**
|
|
646
|
+
* Set the proxy tier resolver. Called after the proxy router is initialized.
|
|
647
|
+
*/
|
|
648
|
+
setProxyTierResolver(resolver: ProxyTierResolver): void;
|
|
649
|
+
/**
|
|
650
|
+
* Evaluate a tool call against the Principal Policy.
|
|
651
|
+
*
|
|
652
|
+
* @param toolName - Full MCP tool name (e.g., "state_export")
|
|
653
|
+
* @param args - Tool call arguments (for context extraction)
|
|
654
|
+
* @returns GateResult indicating whether the call is allowed
|
|
655
|
+
*/
|
|
656
|
+
evaluate(toolName: string, args: Record<string, unknown>): Promise<GateResult>;
|
|
657
|
+
/**
|
|
658
|
+
* Detect Tier 2 behavioral anomalies.
|
|
659
|
+
*/
|
|
660
|
+
private detectAnomaly;
|
|
661
|
+
/**
|
|
662
|
+
* Request approval from the human principal.
|
|
663
|
+
*/
|
|
664
|
+
private requestApproval;
|
|
665
|
+
/**
|
|
666
|
+
* Summarize tool arguments for the approval prompt.
|
|
667
|
+
* Strips potentially large values to keep the prompt readable.
|
|
668
|
+
*/
|
|
669
|
+
private summarizeArgs;
|
|
670
|
+
/** Get the baseline tracker for saving at session end */
|
|
671
|
+
getBaseline(): BaselineTracker;
|
|
672
|
+
/** Get the injection detector for stats/configuration access */
|
|
673
|
+
getInjectionDetector(): InjectionDetector;
|
|
830
674
|
}
|
|
675
|
+
|
|
831
676
|
/**
|
|
832
|
-
*
|
|
677
|
+
* Sanctuary MCP Server — Tool Router
|
|
833
678
|
*
|
|
834
|
-
*
|
|
835
|
-
*
|
|
836
|
-
*
|
|
837
|
-
*
|
|
679
|
+
* Routes sanctuary/* tool calls to their layer-specific handlers.
|
|
680
|
+
* Every tool call passes through schema validation and the ApprovalGate
|
|
681
|
+
* (if configured) before execution. Neither can be bypassed.
|
|
682
|
+
*
|
|
683
|
+
* This module is the abstraction boundary for MCP SDK version migration —
|
|
684
|
+
* if the SDK API changes, only this module needs updating.
|
|
838
685
|
*/
|
|
839
|
-
|
|
840
|
-
/**
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
686
|
+
|
|
687
|
+
/** Tool handler function signature */
|
|
688
|
+
type ToolHandler = (args: Record<string, unknown>) => Promise<{
|
|
689
|
+
content: Array<{
|
|
690
|
+
type: "text";
|
|
691
|
+
text: string;
|
|
692
|
+
}>;
|
|
693
|
+
}>;
|
|
694
|
+
/** Tool definition for registration */
|
|
695
|
+
interface ToolDefinition {
|
|
696
|
+
name: string;
|
|
697
|
+
description: string;
|
|
698
|
+
inputSchema: Record<string, unknown>;
|
|
699
|
+
handler: ToolHandler;
|
|
846
700
|
}
|
|
701
|
+
|
|
847
702
|
/**
|
|
848
|
-
*
|
|
703
|
+
* Sanctuary MCP Server — AES-256-GCM Encryption
|
|
849
704
|
*
|
|
850
|
-
*
|
|
851
|
-
*
|
|
852
|
-
*
|
|
705
|
+
* All state encryption in Sanctuary uses AES-256-GCM (authenticated encryption).
|
|
706
|
+
* This provides both confidentiality and integrity — a modified ciphertext will
|
|
707
|
+
* fail authentication, detecting tampering.
|
|
853
708
|
*
|
|
854
|
-
*
|
|
855
|
-
*
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
/**
|
|
859
|
-
* Compute a tier distribution summary for a set of attestations.
|
|
709
|
+
* Security invariants:
|
|
710
|
+
* - Every encryption uses a unique 12-byte IV (NIST SP 800-38D)
|
|
711
|
+
* - The 16-byte authentication tag is always verified on decryption
|
|
712
|
+
* - Keys are 256 bits (32 bytes)
|
|
860
713
|
*/
|
|
861
|
-
|
|
714
|
+
/** Encrypted payload structure stored on disk */
|
|
715
|
+
interface EncryptedPayload {
|
|
716
|
+
/** Format version */
|
|
717
|
+
v: number;
|
|
718
|
+
/** Algorithm identifier */
|
|
719
|
+
alg: "aes-256-gcm";
|
|
720
|
+
/** Initialization vector (base64url) */
|
|
721
|
+
iv: string;
|
|
722
|
+
/** Ciphertext (base64url) */
|
|
723
|
+
ct: string;
|
|
724
|
+
/** Authentication tag (base64url) — included in ciphertext by @noble/ciphers */
|
|
725
|
+
/** Timestamp */
|
|
726
|
+
ts: string;
|
|
727
|
+
}
|
|
862
728
|
|
|
863
729
|
/**
|
|
864
|
-
* Sanctuary MCP Server —
|
|
865
|
-
*
|
|
866
|
-
* Records interaction outcomes as signed attestations, queries aggregated
|
|
867
|
-
* reputation data, and supports export/import for cross-platform portability.
|
|
730
|
+
* Sanctuary MCP Server — L1 Cognitive Sovereignty: StateStore
|
|
868
731
|
*
|
|
869
|
-
*
|
|
870
|
-
*
|
|
732
|
+
* The encrypted state store is the foundation of Sanctuary.
|
|
733
|
+
* Every read and write goes through here. All data is encrypted
|
|
734
|
+
* with namespace-specific keys. All writes are signed by an identity.
|
|
735
|
+
* All reads verify integrity via Merkle proofs.
|
|
871
736
|
*
|
|
872
737
|
* Security invariants:
|
|
873
|
-
* -
|
|
874
|
-
* -
|
|
875
|
-
* -
|
|
876
|
-
* -
|
|
877
|
-
* -
|
|
738
|
+
* - Plaintext never touches the filesystem
|
|
739
|
+
* - Every write gets a unique IV
|
|
740
|
+
* - Every write is signed (non-repudiation)
|
|
741
|
+
* - Monotonic version numbers prevent rollback
|
|
742
|
+
* - Merkle tree verifies namespace integrity
|
|
743
|
+
* - Secure deletion overwrites before unlinking
|
|
878
744
|
*/
|
|
879
745
|
|
|
880
|
-
/**
|
|
881
|
-
interface
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
schema: "sanctuary-interaction-v1";
|
|
890
|
-
data: {
|
|
891
|
-
interaction_id: string;
|
|
892
|
-
participant_did: string;
|
|
893
|
-
counterparty_did: string;
|
|
894
|
-
outcome_type: string;
|
|
895
|
-
outcome_result: string;
|
|
896
|
-
metrics: Record<string, number>;
|
|
897
|
-
context: string;
|
|
898
|
-
timestamp: string;
|
|
899
|
-
/** Sovereignty tier of the signer at time of recording */
|
|
900
|
-
sovereignty_tier?: SovereigntyTier;
|
|
901
|
-
};
|
|
902
|
-
signature: string;
|
|
903
|
-
signer: string;
|
|
904
|
-
}
|
|
905
|
-
/** Stored attestation (encrypted at rest) */
|
|
906
|
-
interface StoredAttestation {
|
|
907
|
-
attestation: Attestation;
|
|
908
|
-
counterparty_attestation?: string;
|
|
909
|
-
counterparty_confirmed: boolean;
|
|
910
|
-
recorded_at: string;
|
|
911
|
-
}
|
|
912
|
-
/** Aggregated metric statistics */
|
|
913
|
-
interface MetricAggregate {
|
|
914
|
-
mean: number;
|
|
915
|
-
median: number;
|
|
916
|
-
min: number;
|
|
917
|
-
max: number;
|
|
918
|
-
count: number;
|
|
919
|
-
}
|
|
920
|
-
/** Reputation query result */
|
|
921
|
-
interface ReputationSummary {
|
|
922
|
-
total_interactions: number;
|
|
923
|
-
completed: number;
|
|
924
|
-
partial: number;
|
|
925
|
-
failed: number;
|
|
926
|
-
disputed: number;
|
|
927
|
-
contexts: string[];
|
|
928
|
-
time_range: {
|
|
929
|
-
start: string;
|
|
930
|
-
end: string;
|
|
931
|
-
};
|
|
932
|
-
aggregate_metrics: Record<string, MetricAggregate>;
|
|
933
|
-
}
|
|
934
|
-
/** Portable reputation bundle */
|
|
935
|
-
interface ReputationBundle {
|
|
936
|
-
version: "SANCTUARY_REP_V1";
|
|
937
|
-
attestations: Attestation[];
|
|
938
|
-
exported_at: string;
|
|
939
|
-
exporter_did: string;
|
|
940
|
-
bundle_signature: string;
|
|
746
|
+
/** Result of a state write operation */
|
|
747
|
+
interface WriteResult {
|
|
748
|
+
key: string;
|
|
749
|
+
namespace: string;
|
|
750
|
+
version: number;
|
|
751
|
+
merkle_root: string;
|
|
752
|
+
written_at: string;
|
|
753
|
+
size_bytes: number;
|
|
754
|
+
integrity_hash: string;
|
|
941
755
|
}
|
|
942
|
-
/**
|
|
943
|
-
interface
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
status: "pending" | "active" | "released" | "disputed" | "expired";
|
|
756
|
+
/** Result of a state read operation */
|
|
757
|
+
interface ReadResult {
|
|
758
|
+
key: string;
|
|
759
|
+
namespace: string;
|
|
760
|
+
value: string;
|
|
761
|
+
version: number;
|
|
762
|
+
integrity_verified: boolean;
|
|
763
|
+
merkle_proof: string[];
|
|
764
|
+
written_at: string;
|
|
765
|
+
written_by: string;
|
|
953
766
|
}
|
|
954
|
-
/**
|
|
955
|
-
interface
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
scope: string;
|
|
960
|
-
max_liability?: number;
|
|
961
|
-
valid_until: string;
|
|
962
|
-
certificate: string;
|
|
963
|
-
created_at: string;
|
|
767
|
+
/** Options for state write */
|
|
768
|
+
interface WriteOptions {
|
|
769
|
+
content_type?: string;
|
|
770
|
+
ttl_seconds?: number;
|
|
771
|
+
tags?: string[];
|
|
964
772
|
}
|
|
965
|
-
declare class
|
|
773
|
+
declare class StateStore {
|
|
966
774
|
private storage;
|
|
967
|
-
private
|
|
775
|
+
private masterKey;
|
|
776
|
+
private versionCache;
|
|
777
|
+
private contentHashes;
|
|
778
|
+
private namespaceKeyCache;
|
|
779
|
+
private static readonly KEY_CACHE_TTL_MS;
|
|
780
|
+
private static readonly KEY_CACHE_MAX_ENTRIES;
|
|
968
781
|
constructor(storage: StorageBackend, masterKey: Uint8Array);
|
|
969
782
|
/**
|
|
970
|
-
*
|
|
783
|
+
* Get or derive a namespace encryption key, with caching.
|
|
784
|
+
* Cache entries expire after 15 minutes and are evicted LRU when
|
|
785
|
+
* the cache exceeds 128 entries.
|
|
971
786
|
*/
|
|
972
|
-
|
|
787
|
+
private getNamespaceKey;
|
|
788
|
+
/** Invalidate all cached namespace keys (call on master key rotation). */
|
|
789
|
+
invalidateKeyCache(): void;
|
|
790
|
+
private versionKey;
|
|
973
791
|
/**
|
|
974
|
-
*
|
|
975
|
-
* Returns aggregates only — not raw interaction data.
|
|
792
|
+
* Get or initialize the content hash map for a namespace.
|
|
976
793
|
*/
|
|
977
|
-
|
|
978
|
-
context?: string;
|
|
979
|
-
time_range?: {
|
|
980
|
-
start: string;
|
|
981
|
-
end: string;
|
|
982
|
-
};
|
|
983
|
-
metrics?: string[];
|
|
984
|
-
counterparty_did?: string;
|
|
985
|
-
}): Promise<ReputationSummary>;
|
|
794
|
+
private getNamespaceHashes;
|
|
986
795
|
/**
|
|
987
|
-
*
|
|
796
|
+
* Write encrypted state.
|
|
797
|
+
*
|
|
798
|
+
* @param namespace - Logical grouping
|
|
799
|
+
* @param key - State key
|
|
800
|
+
* @param value - Plaintext value (will be encrypted)
|
|
801
|
+
* @param identityId - Identity performing the write
|
|
802
|
+
* @param encryptedPrivateKey - Identity's encrypted private key (for signing)
|
|
803
|
+
* @param identityEncryptionKey - Key to decrypt the identity's private key
|
|
804
|
+
* @param options - Optional metadata
|
|
988
805
|
*/
|
|
989
|
-
|
|
806
|
+
write(namespace: string, key: string, value: string, identityId: string, encryptedPrivateKey: EncryptedPayload, identityEncryptionKey: Uint8Array, options?: WriteOptions): Promise<WriteResult>;
|
|
990
807
|
/**
|
|
991
|
-
*
|
|
992
|
-
* Verifies signatures if requested (default: true).
|
|
808
|
+
* Read and decrypt state.
|
|
993
809
|
*
|
|
994
|
-
* @param
|
|
810
|
+
* @param namespace - Logical grouping
|
|
811
|
+
* @param key - State key
|
|
812
|
+
* @param signerPublicKey - Expected signer's public key (for signature verification)
|
|
813
|
+
* @param verifyIntegrity - Whether to verify Merkle proof (default: true)
|
|
995
814
|
*/
|
|
996
|
-
|
|
997
|
-
imported: number;
|
|
998
|
-
invalid: number;
|
|
999
|
-
contexts: string[];
|
|
1000
|
-
}>;
|
|
815
|
+
read(namespace: string, key: string, signerPublicKey?: Uint8Array, verifyIntegrity?: boolean): Promise<ReadResult | null>;
|
|
1001
816
|
/**
|
|
1002
|
-
*
|
|
817
|
+
* List keys in a namespace (metadata only — no decryption).
|
|
1003
818
|
*/
|
|
1004
|
-
|
|
819
|
+
list(namespace: string, prefix?: string, tags?: string[], limit?: number, offset?: number): Promise<{
|
|
820
|
+
keys: Array<{
|
|
821
|
+
key: string;
|
|
822
|
+
version: number;
|
|
823
|
+
size_bytes: number;
|
|
824
|
+
written_at: string;
|
|
825
|
+
tags: string[];
|
|
826
|
+
}>;
|
|
827
|
+
total: number;
|
|
828
|
+
merkle_root: string;
|
|
829
|
+
}>;
|
|
1005
830
|
/**
|
|
1006
|
-
*
|
|
831
|
+
* Securely delete state (overwrite with random bytes before removal).
|
|
1007
832
|
*/
|
|
1008
|
-
|
|
833
|
+
delete(namespace: string, key: string): Promise<{
|
|
834
|
+
deleted: boolean;
|
|
835
|
+
key: string;
|
|
836
|
+
namespace: string;
|
|
837
|
+
new_merkle_root: string;
|
|
838
|
+
deleted_at: string;
|
|
839
|
+
}>;
|
|
1009
840
|
/**
|
|
1010
|
-
*
|
|
841
|
+
* Export all state for a namespace as an encrypted bundle.
|
|
1011
842
|
*/
|
|
1012
|
-
|
|
843
|
+
export(namespace?: string): Promise<{
|
|
844
|
+
bundle: string;
|
|
845
|
+
namespaces: string[];
|
|
846
|
+
total_keys: number;
|
|
847
|
+
bundle_hash: string;
|
|
848
|
+
exported_at: string;
|
|
849
|
+
}>;
|
|
1013
850
|
/**
|
|
1014
|
-
*
|
|
1015
|
-
* Applies basic context/counterparty filtering, returns full StoredAttestations
|
|
1016
|
-
* so callers can access sovereignty_tier from attestation data.
|
|
851
|
+
* Import a previously exported state bundle.
|
|
1017
852
|
*/
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
853
|
+
import(bundleBase64: string, conflictResolution: "skip" | "overwrite" | "version" | undefined, publicKeyResolver: (kid: string) => Uint8Array | null): Promise<{
|
|
854
|
+
imported_keys: number;
|
|
855
|
+
skipped_keys: number;
|
|
856
|
+
skipped_invalid_sig: number;
|
|
857
|
+
skipped_unknown_kid: number;
|
|
858
|
+
conflicts: number;
|
|
859
|
+
namespaces: string[];
|
|
860
|
+
imported_at: string;
|
|
861
|
+
}>;
|
|
1023
862
|
}
|
|
1024
863
|
|
|
1025
864
|
/**
|
|
1026
|
-
* Sanctuary MCP Server —
|
|
1027
|
-
*
|
|
1028
|
-
* MCP-to-MCP federation enables two Sanctuary instances to:
|
|
1029
|
-
* 1. Discover each other's capabilities (SIM exchange)
|
|
1030
|
-
* 2. Establish mutual trust (sovereignty handshake)
|
|
1031
|
-
* 3. Exchange signed reputation attestations
|
|
1032
|
-
* 4. Evaluate trust for cross-instance interactions
|
|
865
|
+
* Sanctuary MCP Server — Ed25519 Identity Management
|
|
1033
866
|
*
|
|
1034
|
-
*
|
|
1035
|
-
*
|
|
867
|
+
* Sovereign identity based on Ed25519 keypairs.
|
|
868
|
+
* Private keys are always encrypted at rest — never stored in plaintext.
|
|
1036
869
|
*
|
|
1037
|
-
*
|
|
1038
|
-
*
|
|
1039
|
-
*
|
|
870
|
+
* Security invariants:
|
|
871
|
+
* - Private keys never appear in any MCP tool response
|
|
872
|
+
* - Private keys are encrypted with identity-specific keys derived from the master key
|
|
873
|
+
* - Key rotation produces a signed rotation event (verifiable chain)
|
|
1040
874
|
*/
|
|
1041
875
|
|
|
1042
|
-
/**
|
|
1043
|
-
interface
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
last_handshake: string;
|
|
1052
|
-
/** Current trust tier from most recent handshake */
|
|
1053
|
-
trust_tier: SovereigntyTier;
|
|
1054
|
-
/** Handshake result (for tier resolution) */
|
|
1055
|
-
handshake_result: HandshakeResult;
|
|
1056
|
-
/** Peer's advertised capabilities (from their SIM) */
|
|
1057
|
-
capabilities: FederationCapabilities;
|
|
1058
|
-
/** Whether we have a valid (non-expired) handshake */
|
|
1059
|
-
active: boolean;
|
|
876
|
+
/** Public identity information (safe to share) */
|
|
877
|
+
interface PublicIdentity {
|
|
878
|
+
identity_id: string;
|
|
879
|
+
label: string;
|
|
880
|
+
public_key: string;
|
|
881
|
+
did: string;
|
|
882
|
+
created_at: string;
|
|
883
|
+
key_type: "ed25519";
|
|
884
|
+
key_protection: "passphrase" | "hardware-key" | "recovery-key";
|
|
1060
885
|
}
|
|
1061
|
-
/**
|
|
1062
|
-
interface
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
886
|
+
/** Stored identity (private key is encrypted) */
|
|
887
|
+
interface StoredIdentity extends PublicIdentity {
|
|
888
|
+
encrypted_private_key: EncryptedPayload;
|
|
889
|
+
/** Previous public keys (for rotation chain verification) */
|
|
890
|
+
rotation_history: Array<{
|
|
891
|
+
old_public_key: string;
|
|
892
|
+
new_public_key: string;
|
|
893
|
+
rotation_event: string;
|
|
894
|
+
rotated_at: string;
|
|
895
|
+
}>;
|
|
1071
896
|
}
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
897
|
+
|
|
898
|
+
/**
|
|
899
|
+
* Sanctuary MCP Server — L1 Cognitive Sovereignty: Tool Definitions
|
|
900
|
+
*
|
|
901
|
+
* MCP tool wrappers for StateStore and IdentityRoot operations.
|
|
902
|
+
* These tools are the public API that agents interact with.
|
|
903
|
+
*/
|
|
904
|
+
|
|
905
|
+
/** Manages all identities — provides storage and retrieval */
|
|
906
|
+
declare class IdentityManager {
|
|
907
|
+
private storage;
|
|
908
|
+
private masterKey;
|
|
909
|
+
private identities;
|
|
910
|
+
private primaryIdentityId;
|
|
911
|
+
private metadataKey;
|
|
912
|
+
constructor(storage: StorageBackend, masterKey: Uint8Array);
|
|
913
|
+
private get encryptionKey();
|
|
914
|
+
/** Load identities from storage on startup.
|
|
915
|
+
* Returns { total: number of encrypted files found, loaded: number successfully decrypted }.
|
|
916
|
+
* A mismatch (total > 0, loaded === 0) indicates a wrong master key / missing passphrase.
|
|
917
|
+
*/
|
|
918
|
+
load(): Promise<{
|
|
919
|
+
total: number;
|
|
920
|
+
loaded: number;
|
|
921
|
+
failed: number;
|
|
922
|
+
}>;
|
|
923
|
+
/** Save an identity to storage */
|
|
924
|
+
save(identity: StoredIdentity): Promise<void>;
|
|
925
|
+
/** Set which identity is the default/primary identity */
|
|
926
|
+
setPrimary(identityId: string): Promise<boolean>;
|
|
927
|
+
/** Persist the primary identity ID to storage */
|
|
928
|
+
private savePrimaryIdentityId;
|
|
929
|
+
get(id: string): StoredIdentity | undefined;
|
|
930
|
+
getDefault(): StoredIdentity | undefined;
|
|
931
|
+
getPrimaryIdentityId(): string | null;
|
|
932
|
+
list(): PublicIdentity[];
|
|
933
|
+
/** List identities with rotation count (for dashboard display). */
|
|
934
|
+
listWithRotationCount(): Array<PublicIdentity & {
|
|
935
|
+
rotation_count: number;
|
|
936
|
+
}>;
|
|
1089
937
|
}
|
|
1090
938
|
|
|
1091
939
|
/**
|
|
1092
|
-
* Sanctuary MCP Server —
|
|
940
|
+
* Sanctuary MCP Server — L3 Selective Disclosure: Commitment Schemes
|
|
1093
941
|
*
|
|
1094
|
-
*
|
|
1095
|
-
*
|
|
942
|
+
* Cryptographic commitments allow an agent to commit to a value
|
|
943
|
+
* without revealing it, then later prove what was committed.
|
|
1096
944
|
*
|
|
1097
|
-
*
|
|
1098
|
-
*
|
|
1099
|
-
* -
|
|
1100
|
-
* -
|
|
945
|
+
* This is the MVS approach to selective disclosure — simpler than
|
|
946
|
+
* full ZK proofs but still cryptographically sound. The commitment
|
|
947
|
+
* is SHA-256(value || blinding_factor), which is:
|
|
948
|
+
* - Hiding: the commitment reveals nothing about the value
|
|
949
|
+
* - Binding: the committer cannot change the value after committing
|
|
1101
950
|
*
|
|
1102
951
|
* Security invariants:
|
|
1103
|
-
* -
|
|
1104
|
-
* -
|
|
1105
|
-
* -
|
|
952
|
+
* - Blinding factors are cryptographically random (32 bytes)
|
|
953
|
+
* - Commitments are stored encrypted under L1 sovereignty
|
|
954
|
+
* - Revealed values are verified via constant-time comparison
|
|
955
|
+
*/
|
|
956
|
+
|
|
957
|
+
/** A cryptographic commitment */
|
|
958
|
+
interface Commitment {
|
|
959
|
+
/** The commitment hash: SHA-256(value || blinding_factor) as base64url */
|
|
960
|
+
commitment: string;
|
|
961
|
+
/** The blinding factor (must be stored securely for later reveal) */
|
|
962
|
+
blinding_factor: string;
|
|
963
|
+
/** When the commitment was created */
|
|
964
|
+
committed_at: string;
|
|
965
|
+
}
|
|
966
|
+
/** Stored commitment metadata (encrypted at rest) */
|
|
967
|
+
interface StoredCommitment {
|
|
968
|
+
commitment: string;
|
|
969
|
+
blinding_factor: string;
|
|
970
|
+
value: string;
|
|
971
|
+
committed_at: string;
|
|
972
|
+
revealed: boolean;
|
|
973
|
+
revealed_at?: string;
|
|
974
|
+
}
|
|
975
|
+
/**
|
|
976
|
+
* Commitment store — manages commitments encrypted under L1 sovereignty.
|
|
1106
977
|
*/
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
private
|
|
1110
|
-
|
|
1111
|
-
* Register or update a peer from a completed handshake.
|
|
1112
|
-
* This is the ONLY way peers enter the registry.
|
|
1113
|
-
*/
|
|
1114
|
-
registerFromHandshake(result: HandshakeResult, peerDid: string, capabilities?: Partial<FederationCapabilities>): FederationPeer;
|
|
1115
|
-
/**
|
|
1116
|
-
* Get a peer by instance ID.
|
|
1117
|
-
* Automatically updates active status based on handshake expiry.
|
|
1118
|
-
*/
|
|
1119
|
-
getPeer(peerId: string): FederationPeer | null;
|
|
1120
|
-
/**
|
|
1121
|
-
* List all known peers, optionally filtered by status.
|
|
1122
|
-
*/
|
|
1123
|
-
listPeers(filter?: {
|
|
1124
|
-
active_only?: boolean;
|
|
1125
|
-
}): FederationPeer[];
|
|
978
|
+
declare class CommitmentStore {
|
|
979
|
+
private storage;
|
|
980
|
+
private encryptionKey;
|
|
981
|
+
constructor(storage: StorageBackend, masterKey: Uint8Array);
|
|
1126
982
|
/**
|
|
1127
|
-
*
|
|
1128
|
-
*
|
|
1129
|
-
* Trust assessment considers:
|
|
1130
|
-
* - Handshake status (current vs expired)
|
|
1131
|
-
* - Sovereignty tier (verified-sovereign vs degraded vs unverified)
|
|
1132
|
-
* - Reputation data (if available)
|
|
1133
|
-
* - Mutual attestation history
|
|
983
|
+
* Store a commitment (encrypted) for later reference.
|
|
1134
984
|
*/
|
|
1135
|
-
|
|
985
|
+
store(commitment: Commitment, value: string): Promise<string>;
|
|
1136
986
|
/**
|
|
1137
|
-
*
|
|
987
|
+
* Retrieve a stored commitment by ID.
|
|
1138
988
|
*/
|
|
1139
|
-
|
|
989
|
+
get(id: string): Promise<StoredCommitment | null>;
|
|
1140
990
|
/**
|
|
1141
|
-
*
|
|
991
|
+
* Mark a commitment as revealed.
|
|
1142
992
|
*/
|
|
1143
|
-
|
|
993
|
+
markRevealed(id: string): Promise<void>;
|
|
1144
994
|
}
|
|
1145
995
|
|
|
1146
996
|
/**
|
|
1147
|
-
* Sanctuary MCP Server —
|
|
997
|
+
* Sanctuary MCP Server — L3 Selective Disclosure: Zero-Knowledge Proofs
|
|
1148
998
|
*
|
|
1149
|
-
*
|
|
1150
|
-
*
|
|
1151
|
-
* LLM providers. This is the "minimum-necessary context" enforcement layer.
|
|
999
|
+
* Upgrades the commitment-only L3 to support real zero-knowledge proofs.
|
|
1000
|
+
* Uses Ristretto255 (prime-order curve group, no cofactor issues) for:
|
|
1152
1001
|
*
|
|
1153
|
-
*
|
|
1154
|
-
*
|
|
1155
|
-
*
|
|
1156
|
-
* has no control over what the provider sees.
|
|
1002
|
+
* 1. Pedersen commitments: C = v*G + b*H (computationally hiding, perfectly binding)
|
|
1003
|
+
* 2. ZK proof of knowledge: Schnorr sigma protocol via Fiat-Shamir
|
|
1004
|
+
* 3. ZK range proofs: Prove value ∈ [min, max] without revealing it
|
|
1157
1005
|
*
|
|
1158
|
-
*
|
|
1159
|
-
* -
|
|
1160
|
-
* - What fields/categories of context may flow to each provider type
|
|
1161
|
-
* - What must always be redacted (secrets, internal reasoning, PII, etc.)
|
|
1162
|
-
* - What requires transformation (hashing, summarizing, anonymizing)
|
|
1006
|
+
* Ristretto255 is available via @noble/curves/ed25519, which we already depend on.
|
|
1007
|
+
* This is genuine zero-knowledge — proofs reveal nothing beyond the stated property.
|
|
1163
1008
|
*
|
|
1164
|
-
*
|
|
1165
|
-
*
|
|
1166
|
-
*
|
|
1167
|
-
*
|
|
1009
|
+
* Architecture note:
|
|
1010
|
+
* The existing commitment scheme (SHA-256 based) remains available for backward
|
|
1011
|
+
* compatibility. The ZK proofs operate on a separate Pedersen commitment system
|
|
1012
|
+
* that provides algebraic structure for proper ZK properties.
|
|
1168
1013
|
*
|
|
1169
1014
|
* Security invariants:
|
|
1170
|
-
* -
|
|
1171
|
-
* -
|
|
1172
|
-
* -
|
|
1173
|
-
*
|
|
1174
|
-
* - Default policy: redact everything not explicitly allowed
|
|
1015
|
+
* - Generator H is derived via hash-to-curve (nothing-up-my-sleeve)
|
|
1016
|
+
* - Blinding factors are cryptographically random (32 bytes)
|
|
1017
|
+
* - Fiat-Shamir challenges use domain-separated hashing
|
|
1018
|
+
* - Range proofs use a bit-decomposition approach (sound but logarithmic size)
|
|
1175
1019
|
*/
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
provider: ProviderCategory | "*";
|
|
1185
|
-
/** Fields/patterns that may pass through */
|
|
1186
|
-
allow: string[];
|
|
1187
|
-
/** Fields/patterns that must be redacted (highest priority) */
|
|
1188
|
-
redact: string[];
|
|
1189
|
-
/** Fields/patterns that should be hashed */
|
|
1190
|
-
hash: string[];
|
|
1191
|
-
/** Fields/patterns that should be summarized (advisory) */
|
|
1192
|
-
summarize: string[];
|
|
1193
|
-
}
|
|
1194
|
-
/** A complete context-gating policy */
|
|
1195
|
-
interface ContextGatePolicy {
|
|
1196
|
-
policy_id: string;
|
|
1197
|
-
policy_name: string;
|
|
1198
|
-
rules: ContextGateRule[];
|
|
1199
|
-
/** Default action when no rule matches a field */
|
|
1200
|
-
default_action: "redact" | "deny";
|
|
1201
|
-
/** Identity this policy is bound to (optional) */
|
|
1202
|
-
identity_id?: string;
|
|
1203
|
-
created_at: string;
|
|
1204
|
-
updated_at: string;
|
|
1020
|
+
/** A Pedersen commitment: C = v*G + b*H */
|
|
1021
|
+
interface PedersenCommitment {
|
|
1022
|
+
/** The commitment point (encoded as base64url) */
|
|
1023
|
+
commitment: string;
|
|
1024
|
+
/** The blinding factor b (base64url, 32 bytes) — keep secret */
|
|
1025
|
+
blinding_factor: string;
|
|
1026
|
+
/** When the commitment was created */
|
|
1027
|
+
committed_at: string;
|
|
1205
1028
|
}
|
|
1206
|
-
/**
|
|
1207
|
-
interface
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1029
|
+
/** A non-interactive ZK proof of knowledge of a commitment's opening */
|
|
1030
|
+
interface ZKProofOfKnowledge {
|
|
1031
|
+
/** Proof type identifier */
|
|
1032
|
+
type: "schnorr-pedersen-ristretto255";
|
|
1033
|
+
/** The commitment this proof is for */
|
|
1034
|
+
commitment: string;
|
|
1035
|
+
/** Announcement point R (base64url) */
|
|
1036
|
+
announcement: string;
|
|
1037
|
+
/** Response scalar s_v (base64url) */
|
|
1038
|
+
response_v: string;
|
|
1039
|
+
/** Response scalar s_b (base64url) */
|
|
1040
|
+
response_b: string;
|
|
1041
|
+
/** Proof generated at */
|
|
1042
|
+
generated_at: string;
|
|
1213
1043
|
}
|
|
1214
|
-
/**
|
|
1215
|
-
interface
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
/**
|
|
1225
|
-
|
|
1226
|
-
/**
|
|
1227
|
-
|
|
1228
|
-
|
|
1044
|
+
/** A ZK range proof: proves value ∈ [min, max] */
|
|
1045
|
+
interface ZKRangeProof {
|
|
1046
|
+
/** Proof type identifier */
|
|
1047
|
+
type: "range-pedersen-ristretto255";
|
|
1048
|
+
/** The commitment this proof is for */
|
|
1049
|
+
commitment: string;
|
|
1050
|
+
/** Minimum value (inclusive) */
|
|
1051
|
+
min: number;
|
|
1052
|
+
/** Maximum value (inclusive) */
|
|
1053
|
+
max: number;
|
|
1054
|
+
/** Bit commitments for the shifted value (v - min) */
|
|
1055
|
+
bit_commitments: string[];
|
|
1056
|
+
/** Proofs that each bit commitment is 0 or 1 */
|
|
1057
|
+
bit_proofs: Array<{
|
|
1058
|
+
announcement_0: string;
|
|
1059
|
+
announcement_1: string;
|
|
1060
|
+
challenge_0: string;
|
|
1061
|
+
challenge_1: string;
|
|
1062
|
+
response_0: string;
|
|
1063
|
+
response_1: string;
|
|
1064
|
+
}>;
|
|
1065
|
+
/** Sum proof: bit commitments sum to the value commitment */
|
|
1066
|
+
sum_proof: {
|
|
1067
|
+
announcement: string;
|
|
1068
|
+
response: string;
|
|
1069
|
+
};
|
|
1070
|
+
/** Proof generated at */
|
|
1071
|
+
generated_at: string;
|
|
1229
1072
|
}
|
|
1230
1073
|
/**
|
|
1231
|
-
*
|
|
1074
|
+
* Create a Pedersen commitment to a numeric value.
|
|
1232
1075
|
*
|
|
1233
|
-
*
|
|
1234
|
-
*
|
|
1235
|
-
*
|
|
1236
|
-
*
|
|
1237
|
-
*
|
|
1238
|
-
*
|
|
1239
|
-
*
|
|
1076
|
+
* C = v*G + b*H
|
|
1077
|
+
*
|
|
1078
|
+
* Properties:
|
|
1079
|
+
* - Computationally hiding (under discrete log assumption)
|
|
1080
|
+
* - Perfectly binding (information-theoretic)
|
|
1081
|
+
* - Homomorphic: C(v1) + C(v2) = C(v1+v2) with adjusted blinding
|
|
1082
|
+
*
|
|
1083
|
+
* @param value - The value to commit to (integer)
|
|
1084
|
+
* @returns The commitment and blinding factor
|
|
1240
1085
|
*/
|
|
1241
|
-
declare function
|
|
1086
|
+
declare function createPedersenCommitment(value: number): PedersenCommitment;
|
|
1087
|
+
/**
|
|
1088
|
+
* Verify a Pedersen commitment against a revealed value and blinding factor.
|
|
1089
|
+
*
|
|
1090
|
+
* Recomputes C' = v*G + b*H and checks C' == C.
|
|
1091
|
+
*/
|
|
1092
|
+
declare function verifyPedersenCommitment(commitment: string, value: number, blindingFactor: string): boolean;
|
|
1093
|
+
/**
|
|
1094
|
+
* Create a non-interactive ZK proof that you know the opening (v, b)
|
|
1095
|
+
* of a Pedersen commitment C = v*G + b*H.
|
|
1096
|
+
*
|
|
1097
|
+
* Schnorr sigma protocol with Fiat-Shamir transform:
|
|
1098
|
+
* 1. Pick random r_v, r_b
|
|
1099
|
+
* 2. Compute R = r_v*G + r_b*H (announcement)
|
|
1100
|
+
* 3. Compute e = H_FS(C || R) (challenge via Fiat-Shamir)
|
|
1101
|
+
* 4. Compute s_v = r_v + e*v, s_b = r_b + e*b (responses)
|
|
1102
|
+
* 5. Proof = (R, s_v, s_b)
|
|
1103
|
+
*
|
|
1104
|
+
* Zero-knowledge: the transcript (R, e, s_v, s_b) can be simulated
|
|
1105
|
+
* without knowing (v, b), so it reveals nothing.
|
|
1106
|
+
*
|
|
1107
|
+
* @param value - The committed value
|
|
1108
|
+
* @param blindingFactor - The blinding factor (base64url)
|
|
1109
|
+
* @param commitment - The commitment (base64url)
|
|
1110
|
+
*/
|
|
1111
|
+
declare function createProofOfKnowledge(value: number, blindingFactor: string, commitment: string): ZKProofOfKnowledge;
|
|
1112
|
+
/**
|
|
1113
|
+
* Verify a ZK proof of knowledge of a commitment's opening.
|
|
1114
|
+
*
|
|
1115
|
+
* Check: s_v*G + s_b*H == R + e*C
|
|
1116
|
+
*/
|
|
1117
|
+
declare function verifyProofOfKnowledge(proof: ZKProofOfKnowledge): boolean;
|
|
1118
|
+
/**
|
|
1119
|
+
* Create a ZK range proof: prove value ∈ [min, max] without revealing value.
|
|
1120
|
+
*
|
|
1121
|
+
* Approach: bit-decomposition of (value - min) into n bits where 2^n > max - min.
|
|
1122
|
+
* Each bit gets a Pedersen commitment and a proof it's 0 or 1.
|
|
1123
|
+
* A sum proof shows the bit commitments reconstruct the original commitment
|
|
1124
|
+
* (shifted by min).
|
|
1125
|
+
*
|
|
1126
|
+
* @param value - The committed value
|
|
1127
|
+
* @param blindingFactor - The blinding factor (base64url)
|
|
1128
|
+
* @param commitment - The commitment (base64url)
|
|
1129
|
+
* @param min - Minimum value (inclusive)
|
|
1130
|
+
* @param max - Maximum value (inclusive)
|
|
1131
|
+
*/
|
|
1132
|
+
declare function createRangeProof(value: number, blindingFactor: string, commitment: string, min: number, max: number): ZKRangeProof | {
|
|
1133
|
+
error: string;
|
|
1134
|
+
};
|
|
1135
|
+
/**
|
|
1136
|
+
* Verify a ZK range proof.
|
|
1137
|
+
*/
|
|
1138
|
+
declare function verifyRangeProof(proof: ZKRangeProof): boolean;
|
|
1139
|
+
|
|
1242
1140
|
/**
|
|
1243
|
-
*
|
|
1244
|
-
*
|
|
1141
|
+
* Sanctuary MCP Server — L3 Selective Disclosure: Disclosure Policies
|
|
1142
|
+
*
|
|
1143
|
+
* Disclosure policies define what an agent will and will not disclose
|
|
1144
|
+
* in different interaction contexts. Policies are evaluated against
|
|
1145
|
+
* incoming disclosure requests to produce per-field decisions.
|
|
1146
|
+
*
|
|
1147
|
+
* This is the agent's "privacy preferences" layer — it codifies the
|
|
1148
|
+
* human principal's intent about what information can flow where.
|
|
1149
|
+
*
|
|
1150
|
+
* Security invariants:
|
|
1151
|
+
* - Policies are stored encrypted under L1 sovereignty
|
|
1152
|
+
* - Default action is always "withhold" unless explicitly overridden
|
|
1153
|
+
* - Policy evaluation is deterministic (same request → same decision)
|
|
1245
1154
|
*/
|
|
1246
|
-
|
|
1155
|
+
|
|
1156
|
+
/** A single disclosure rule within a policy */
|
|
1157
|
+
interface DisclosureRule {
|
|
1158
|
+
/** Interaction context this rule applies to */
|
|
1159
|
+
context: string;
|
|
1160
|
+
/** Fields/claims the agent MAY disclose */
|
|
1161
|
+
disclose: string[];
|
|
1162
|
+
/** Fields/claims the agent MUST NOT disclose */
|
|
1163
|
+
withhold: string[];
|
|
1164
|
+
/** Fields that require proof rather than plain disclosure */
|
|
1165
|
+
proof_required: string[];
|
|
1166
|
+
}
|
|
1167
|
+
/** A complete disclosure policy */
|
|
1168
|
+
interface DisclosurePolicy {
|
|
1169
|
+
policy_id: string;
|
|
1170
|
+
policy_name: string;
|
|
1171
|
+
rules: DisclosureRule[];
|
|
1172
|
+
default_action: "withhold" | "ask-principal";
|
|
1173
|
+
identity_id?: string;
|
|
1174
|
+
created_at: string;
|
|
1175
|
+
updated_at: string;
|
|
1176
|
+
}
|
|
1247
1177
|
/**
|
|
1248
|
-
*
|
|
1178
|
+
* Policy store — manages disclosure policies encrypted under L1 sovereignty.
|
|
1249
1179
|
*/
|
|
1250
|
-
declare class
|
|
1180
|
+
declare class PolicyStore {
|
|
1251
1181
|
private storage;
|
|
1252
1182
|
private encryptionKey;
|
|
1253
1183
|
private policies;
|
|
1254
1184
|
constructor(storage: StorageBackend, masterKey: Uint8Array);
|
|
1255
1185
|
/**
|
|
1256
|
-
* Create and store a new
|
|
1186
|
+
* Create and store a new disclosure policy.
|
|
1257
1187
|
*/
|
|
1258
|
-
create(policyName: string, rules:
|
|
1188
|
+
create(policyName: string, rules: DisclosureRule[], defaultAction: "withhold" | "ask-principal", identityId?: string): Promise<DisclosurePolicy>;
|
|
1259
1189
|
/**
|
|
1260
1190
|
* Get a policy by ID.
|
|
1261
1191
|
*/
|
|
1262
|
-
get(policyId: string): Promise<
|
|
1192
|
+
get(policyId: string): Promise<DisclosurePolicy | null>;
|
|
1263
1193
|
/**
|
|
1264
|
-
* List all
|
|
1194
|
+
* List all policies.
|
|
1265
1195
|
*/
|
|
1266
|
-
list(): Promise<
|
|
1196
|
+
list(): Promise<DisclosurePolicy[]>;
|
|
1267
1197
|
/**
|
|
1268
1198
|
* Load all persisted policies into memory.
|
|
1269
1199
|
*/
|
|
@@ -1272,736 +1202,907 @@ declare class ContextGatePolicyStore {
|
|
|
1272
1202
|
}
|
|
1273
1203
|
|
|
1274
1204
|
/**
|
|
1275
|
-
* Sanctuary MCP Server —
|
|
1276
|
-
*
|
|
1277
|
-
* Pre-built policies for common use cases. These are starting points —
|
|
1278
|
-
* users should customize them for their specific context structure.
|
|
1279
|
-
*
|
|
1280
|
-
* Templates:
|
|
1281
|
-
*
|
|
1282
|
-
* inference-minimal
|
|
1283
|
-
* Only the current task and query reach the LLM. Everything else
|
|
1284
|
-
* is redacted. Secrets, PII, memory, reasoning, and history are
|
|
1285
|
-
* all blocked. IDs are hashed. Maximum privacy, minimum context.
|
|
1286
|
-
*
|
|
1287
|
-
* inference-standard
|
|
1288
|
-
* Task, query, and tool results pass through. Conversation history
|
|
1289
|
-
* is flagged for summarization (compress before sending). Secrets,
|
|
1290
|
-
* PII, and internal reasoning are redacted. IDs are hashed.
|
|
1291
|
-
* Balanced: the LLM has enough context to be useful without seeing
|
|
1292
|
-
* everything the agent knows.
|
|
1205
|
+
* Sanctuary MCP Server — Sovereignty Health Report (SHR) Types
|
|
1293
1206
|
*
|
|
1294
|
-
*
|
|
1295
|
-
*
|
|
1296
|
-
*
|
|
1297
|
-
*
|
|
1298
|
-
* content exposure.
|
|
1207
|
+
* Machine-readable, signed, versioned sovereignty capability advertisement.
|
|
1208
|
+
* An agent presents its SHR to counterparties to prove its sovereignty posture.
|
|
1209
|
+
* The SHR is signed by one of the instance's Ed25519 identities and can be
|
|
1210
|
+
* independently verified by any party without trusting the presenter.
|
|
1299
1211
|
*
|
|
1300
|
-
*
|
|
1301
|
-
* Allows tool-specific parameters and the current task, redacts
|
|
1302
|
-
* memory, history, secrets, and PII. Hashes IDs. For outbound
|
|
1303
|
-
* calls to external APIs (search, database, etc.) where you need
|
|
1304
|
-
* to send query parameters but not your agent's full state.
|
|
1212
|
+
* SHR version: 1.0
|
|
1305
1213
|
*/
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1214
|
+
type LayerStatus = "active" | "degraded" | "inactive";
|
|
1215
|
+
type DegradationSeverity = "info" | "warning" | "critical";
|
|
1216
|
+
type DegradationCode = "NO_TEE" | "PROCESS_ISOLATION_ONLY" | "COMMITMENT_ONLY" | "NO_ZK_PROOFS" | "SELF_REPORTED_ATTESTATION" | "NO_SELECTIVE_DISCLOSURE" | "BASIC_SYBIL_ONLY" | "NO_REPUTATION_HISTORY" | "LOW_TIER_DOMINANCE" | "STALE_REPUTATION" | "DISPUTE_ON_RECORD" | "NO_VERASCORE_LINK";
|
|
1217
|
+
interface SHRLayerL1 {
|
|
1218
|
+
status: LayerStatus;
|
|
1219
|
+
encryption: string;
|
|
1220
|
+
key_custody: "self" | "delegated" | "platform";
|
|
1221
|
+
integrity: string;
|
|
1222
|
+
identity_type: string;
|
|
1223
|
+
state_portable: boolean;
|
|
1224
|
+
}
|
|
1225
|
+
interface SHRLayerL2 {
|
|
1226
|
+
status: LayerStatus;
|
|
1227
|
+
isolation_type: string;
|
|
1228
|
+
attestation_available: boolean;
|
|
1229
|
+
/** Model provenance: what inference model(s) power this agent */
|
|
1230
|
+
model_provenance?: {
|
|
1231
|
+
model_id: string;
|
|
1232
|
+
model_name: string;
|
|
1233
|
+
provider: string;
|
|
1234
|
+
open_weights: boolean;
|
|
1235
|
+
open_source: boolean;
|
|
1236
|
+
local_inference: boolean;
|
|
1237
|
+
weights_hash?: string;
|
|
1238
|
+
};
|
|
1239
|
+
}
|
|
1240
|
+
interface SHRLayerL3 {
|
|
1241
|
+
status: LayerStatus;
|
|
1242
|
+
proof_system: string;
|
|
1243
|
+
selective_disclosure: boolean;
|
|
1244
|
+
}
|
|
1245
|
+
interface SHRLayerL4 {
|
|
1246
|
+
status: LayerStatus;
|
|
1247
|
+
reputation_mode: string;
|
|
1248
|
+
attestation_format: string;
|
|
1249
|
+
reputation_portable: boolean;
|
|
1250
|
+
}
|
|
1251
|
+
interface SHRDegradation {
|
|
1252
|
+
layer: "l1" | "l2" | "l3" | "l4";
|
|
1253
|
+
code: DegradationCode;
|
|
1254
|
+
severity: DegradationSeverity;
|
|
1314
1255
|
description: string;
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1256
|
+
mitigation?: string;
|
|
1257
|
+
}
|
|
1258
|
+
interface SHRCapabilities {
|
|
1259
|
+
handshake: boolean;
|
|
1260
|
+
shr_exchange: boolean;
|
|
1261
|
+
reputation_verify: boolean;
|
|
1262
|
+
encrypted_channel: boolean;
|
|
1321
1263
|
}
|
|
1322
|
-
/** All available templates, keyed by ID */
|
|
1323
|
-
declare const TEMPLATES: Record<string, ContextGateTemplate>;
|
|
1324
|
-
/** List all available template IDs */
|
|
1325
|
-
declare function listTemplateIds(): string[];
|
|
1326
|
-
/** Get a template by ID (returns undefined if not found) */
|
|
1327
|
-
declare function getTemplate(id: string): ContextGateTemplate | undefined;
|
|
1328
|
-
|
|
1329
1264
|
/**
|
|
1330
|
-
*
|
|
1331
|
-
*
|
|
1332
|
-
* Analyzes a sample context object and recommends a context-gating policy
|
|
1333
|
-
* based on field name heuristics. The agent (or human) can then review,
|
|
1334
|
-
* adjust, and apply the recommendation.
|
|
1335
|
-
*
|
|
1336
|
-
* This is deliberately conservative: when in doubt, it recommends redact.
|
|
1337
|
-
* A false redaction is a usability issue; a false allow is a privacy leak.
|
|
1338
|
-
*
|
|
1339
|
-
* Classification heuristics:
|
|
1340
|
-
* - Known secret patterns → redact (highest confidence)
|
|
1341
|
-
* - Known PII patterns → redact (high confidence)
|
|
1342
|
-
* - Known internal state patterns → redact (high confidence)
|
|
1343
|
-
* - Known ID patterns → hash (medium confidence)
|
|
1344
|
-
* - Known history patterns → summarize (medium confidence)
|
|
1345
|
-
* - Known task/query patterns → allow (medium confidence)
|
|
1346
|
-
* - Everything else → redact (conservative default)
|
|
1347
|
-
*
|
|
1348
|
-
* WARNING: Fields like 'tool_results' and 'tool_output' are classified as
|
|
1349
|
-
* "allow" (medium confidence) but may contain sensitive data from external
|
|
1350
|
-
* API responses, including auth tokens, user data, or PII. Always review
|
|
1351
|
-
* recommendations before applying — the heuristic classifies by field NAME,
|
|
1352
|
-
* not field CONTENT.
|
|
1265
|
+
* The SHR body — the content that gets signed.
|
|
1266
|
+
* Canonical form: JSON with sorted keys, no whitespace.
|
|
1353
1267
|
*/
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
/** Pattern that matched, if any */
|
|
1361
|
-
matched_pattern: string | null;
|
|
1362
|
-
}
|
|
1363
|
-
/** Full recommendation result */
|
|
1364
|
-
interface PolicyRecommendation {
|
|
1365
|
-
provider: string;
|
|
1366
|
-
classifications: FieldClassification[];
|
|
1367
|
-
recommended_rules: {
|
|
1368
|
-
allow: string[];
|
|
1369
|
-
redact: string[];
|
|
1370
|
-
hash: string[];
|
|
1371
|
-
summarize: string[];
|
|
1268
|
+
interface SHRBody {
|
|
1269
|
+
shr_version: "1.0";
|
|
1270
|
+
implementation: {
|
|
1271
|
+
sanctuary_version: string;
|
|
1272
|
+
node_version: string;
|
|
1273
|
+
generated_by: string;
|
|
1372
1274
|
};
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1275
|
+
instance_id: string;
|
|
1276
|
+
generated_at: string;
|
|
1277
|
+
expires_at: string;
|
|
1278
|
+
layers: {
|
|
1279
|
+
l1: SHRLayerL1;
|
|
1280
|
+
l2: SHRLayerL2;
|
|
1281
|
+
l3: SHRLayerL3;
|
|
1282
|
+
l4: SHRLayerL4;
|
|
1380
1283
|
};
|
|
1284
|
+
capabilities: SHRCapabilities;
|
|
1285
|
+
degradations: SHRDegradation[];
|
|
1286
|
+
}
|
|
1287
|
+
/**
|
|
1288
|
+
* The complete signed SHR — body + signature envelope.
|
|
1289
|
+
*/
|
|
1290
|
+
interface SignedSHR {
|
|
1291
|
+
body: SHRBody;
|
|
1292
|
+
signed_by: string;
|
|
1293
|
+
signature: string;
|
|
1294
|
+
}
|
|
1295
|
+
interface SHRVerificationResult {
|
|
1296
|
+
valid: boolean;
|
|
1297
|
+
errors: string[];
|
|
1381
1298
|
warnings: string[];
|
|
1299
|
+
sovereignty_level: "full" | "degraded" | "minimal";
|
|
1300
|
+
counterparty_id: string;
|
|
1301
|
+
expires_at: string;
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1304
|
+
/**
|
|
1305
|
+
* Sanctuary MCP Server — Sovereignty Handshake Types
|
|
1306
|
+
*
|
|
1307
|
+
* The sovereignty handshake is a mutual verification protocol between
|
|
1308
|
+
* two Sanctuary instances. Each party presents its SHR and proves
|
|
1309
|
+
* liveness via nonce challenge-response.
|
|
1310
|
+
*
|
|
1311
|
+
* Protocol:
|
|
1312
|
+
* A → B: HandshakeChallenge (A's SHR + nonce)
|
|
1313
|
+
* B → A: HandshakeResponse (B's SHR + B's nonce + signature over A's nonce)
|
|
1314
|
+
* A → B: HandshakeCompletion (signature over B's nonce)
|
|
1315
|
+
* Result: Both hold a HandshakeResult with verified counterparty status
|
|
1316
|
+
*/
|
|
1317
|
+
|
|
1318
|
+
/** Trust tier derived from sovereignty handshake */
|
|
1319
|
+
type TrustTier = "verified-sovereign" | "verified-degraded" | "unverified";
|
|
1320
|
+
/** Sovereignty level from SHR assessment */
|
|
1321
|
+
type SovereigntyLevel = "full" | "degraded" | "minimal" | "unverified";
|
|
1322
|
+
/**
|
|
1323
|
+
* Step 1: Initiator sends challenge
|
|
1324
|
+
*/
|
|
1325
|
+
interface HandshakeChallenge {
|
|
1326
|
+
protocol_version: "1.0";
|
|
1327
|
+
shr: SignedSHR;
|
|
1328
|
+
nonce: string;
|
|
1329
|
+
initiated_at: string;
|
|
1382
1330
|
}
|
|
1383
1331
|
/**
|
|
1384
|
-
*
|
|
1332
|
+
* Step 2: Responder sends response
|
|
1385
1333
|
*/
|
|
1386
|
-
|
|
1334
|
+
interface HandshakeResponse {
|
|
1335
|
+
protocol_version: "1.0";
|
|
1336
|
+
shr: SignedSHR;
|
|
1337
|
+
responder_nonce: string;
|
|
1338
|
+
initiator_nonce_signature: string;
|
|
1339
|
+
responded_at: string;
|
|
1340
|
+
}
|
|
1387
1341
|
/**
|
|
1388
|
-
*
|
|
1342
|
+
* Step 3: Initiator sends completion
|
|
1389
1343
|
*/
|
|
1390
|
-
|
|
1344
|
+
interface HandshakeCompletion {
|
|
1345
|
+
protocol_version: "1.0";
|
|
1346
|
+
responder_nonce_signature: string;
|
|
1347
|
+
completed_at: string;
|
|
1348
|
+
}
|
|
1349
|
+
/**
|
|
1350
|
+
* Final result: both parties hold this after a successful handshake
|
|
1351
|
+
*/
|
|
1352
|
+
interface HandshakeResult {
|
|
1353
|
+
counterparty_id: string;
|
|
1354
|
+
counterparty_shr: SignedSHR;
|
|
1355
|
+
verified: boolean;
|
|
1356
|
+
sovereignty_level: SovereigntyLevel;
|
|
1357
|
+
trust_tier: TrustTier;
|
|
1358
|
+
completed_at: string;
|
|
1359
|
+
expires_at: string;
|
|
1360
|
+
errors: string[];
|
|
1361
|
+
}
|
|
1362
|
+
/**
|
|
1363
|
+
* In-progress handshake state (stored on initiator side)
|
|
1364
|
+
*/
|
|
1365
|
+
interface HandshakeSession {
|
|
1366
|
+
session_id: string;
|
|
1367
|
+
role: "initiator" | "responder";
|
|
1368
|
+
state: "initiated" | "responded" | "completed" | "failed";
|
|
1369
|
+
our_nonce: string;
|
|
1370
|
+
their_nonce?: string;
|
|
1371
|
+
our_shr: SignedSHR;
|
|
1372
|
+
their_shr?: SignedSHR;
|
|
1373
|
+
initiated_at: string;
|
|
1374
|
+
result?: HandshakeResult;
|
|
1375
|
+
}
|
|
1391
1376
|
|
|
1392
1377
|
/**
|
|
1393
|
-
* Sanctuary MCP Server —
|
|
1394
|
-
*
|
|
1395
|
-
* Declares and attests to the model(s) powering this agent.
|
|
1378
|
+
* Sanctuary MCP Server — Sovereignty-Gated Reputation Tiers
|
|
1396
1379
|
*
|
|
1397
|
-
*
|
|
1398
|
-
*
|
|
1399
|
-
*
|
|
1400
|
-
*
|
|
1380
|
+
* Attestations carry a sovereignty_tier field reflecting the signer's
|
|
1381
|
+
* sovereignty posture at the time of recording. When querying or evaluating
|
|
1382
|
+
* reputation, attestations from verified-sovereign agents carry more weight
|
|
1383
|
+
* than those from unverified agents.
|
|
1401
1384
|
*
|
|
1402
|
-
*
|
|
1403
|
-
*
|
|
1385
|
+
* Tier hierarchy (descending credibility):
|
|
1386
|
+
* 1. "verified-sovereign" — signer completed a handshake with full sovereignty
|
|
1387
|
+
* 2. "verified-degraded" — signer completed a handshake with degraded sovereignty
|
|
1388
|
+
* 3. "self-attested" — signer has a Sanctuary identity but no handshake verification
|
|
1389
|
+
* 4. "unverified" — no Sanctuary identity or sovereignty proof
|
|
1404
1390
|
*
|
|
1405
|
-
*
|
|
1406
|
-
*
|
|
1391
|
+
* Weight multipliers are applied during reputation scoring. They are NOT
|
|
1392
|
+
* gatekeeping — unverified attestations still count, just less.
|
|
1407
1393
|
*/
|
|
1394
|
+
|
|
1395
|
+
type SovereigntyTier = "verified-sovereign" | "verified-degraded" | "self-attested" | "unverified";
|
|
1396
|
+
/** Weight multipliers for each tier */
|
|
1397
|
+
declare const TIER_WEIGHTS: Record<SovereigntyTier, number>;
|
|
1398
|
+
/** Tier metadata embedded in attestations */
|
|
1399
|
+
interface TierMetadata {
|
|
1400
|
+
sovereignty_tier: SovereigntyTier;
|
|
1401
|
+
/** If verified, the handshake that established it */
|
|
1402
|
+
handshake_completed_at?: string;
|
|
1403
|
+
/** Counterparty ID from handshake (if applicable) */
|
|
1404
|
+
verified_by?: string;
|
|
1405
|
+
}
|
|
1408
1406
|
/**
|
|
1409
|
-
*
|
|
1407
|
+
* Resolve the sovereignty tier for a counterparty based on handshake history.
|
|
1408
|
+
*
|
|
1409
|
+
* @param counterpartyId - The counterparty's instance ID
|
|
1410
|
+
* @param handshakeResults - Map of counterparty ID → most recent handshake result
|
|
1411
|
+
* @param hasSanctuaryIdentity - Whether the counterparty has a known Sanctuary identity
|
|
1412
|
+
* @returns TierMetadata for embedding in attestations
|
|
1410
1413
|
*/
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
/**
|
|
1415
|
-
|
|
1416
|
-
/**
|
|
1417
|
-
|
|
1418
|
-
/** Provider/vendor (e.g., "Alibaba Cloud", "Anthropic", "Meta", "local") */
|
|
1419
|
-
provider: string;
|
|
1420
|
-
/** SHA-256 of model weights file, if available and verifiable */
|
|
1421
|
-
weights_hash?: string;
|
|
1422
|
-
/** SHA-256 of training data manifest or metadata, if available */
|
|
1423
|
-
training_data_hash?: string;
|
|
1424
|
-
/** License identifier (e.g., "Apache-2.0", "CC-BY-4.0", "proprietary", "unknown") */
|
|
1425
|
-
license: string;
|
|
1426
|
-
/** True if model weights are publicly available (even if training is proprietary) */
|
|
1427
|
-
open_weights: boolean;
|
|
1428
|
-
/** True if full training code, data, and methodology are publicly available */
|
|
1429
|
-
open_source: boolean;
|
|
1430
|
-
/** True if inference runs on the local agent's hardware (not delegated to cloud API) */
|
|
1431
|
-
local_inference: boolean;
|
|
1432
|
-
/** ISO 8601 timestamp when this provenance was declared */
|
|
1433
|
-
declared_at: string;
|
|
1414
|
+
declare function resolveTier(counterpartyId: string, handshakeResults: Map<string, HandshakeResult>, hasSanctuaryIdentity: boolean): TierMetadata;
|
|
1415
|
+
/** An attestation with its tier for weighted scoring */
|
|
1416
|
+
interface TieredAttestation {
|
|
1417
|
+
/** The raw metric value */
|
|
1418
|
+
value: number;
|
|
1419
|
+
/** The sovereignty tier of the attestation signer */
|
|
1420
|
+
tier: SovereigntyTier;
|
|
1434
1421
|
}
|
|
1435
1422
|
/**
|
|
1436
|
-
*
|
|
1437
|
-
*
|
|
1423
|
+
* Compute a weighted reputation score from tiered attestations.
|
|
1424
|
+
*
|
|
1425
|
+
* Each attestation's contribution is multiplied by its tier weight.
|
|
1426
|
+
* The result is normalized by total weight (not count), so adding
|
|
1427
|
+
* low-tier attestations doesn't dilute high-tier ones.
|
|
1428
|
+
*
|
|
1429
|
+
* @param attestations - Array of value + tier pairs
|
|
1430
|
+
* @returns Weighted score, or null if no attestations
|
|
1438
1431
|
*/
|
|
1439
|
-
|
|
1440
|
-
/**
|
|
1441
|
-
* Declare a model's provenance and add it to the store.
|
|
1442
|
-
*/
|
|
1443
|
-
declare(provenance: ModelProvenance): void;
|
|
1444
|
-
/**
|
|
1445
|
-
* Retrieve a model's provenance by ID.
|
|
1446
|
-
*/
|
|
1447
|
-
get(model_id: string): ModelProvenance | undefined;
|
|
1448
|
-
/**
|
|
1449
|
-
* List all declared models.
|
|
1450
|
-
*/
|
|
1451
|
-
list(): ModelProvenance[];
|
|
1452
|
-
/**
|
|
1453
|
-
* Get the primary/main model (the one the agent uses by default for inference).
|
|
1454
|
-
*/
|
|
1455
|
-
primary(): ModelProvenance | undefined;
|
|
1456
|
-
/**
|
|
1457
|
-
* Set which model is the primary.
|
|
1458
|
-
*/
|
|
1459
|
-
setPrimary(model_id: string): void;
|
|
1460
|
-
}
|
|
1432
|
+
declare function computeWeightedScore(attestations: TieredAttestation[]): number | null;
|
|
1461
1433
|
/**
|
|
1462
|
-
*
|
|
1463
|
-
* Suitable for most use cases. For encrypted persistence, integrate with L1 state store.
|
|
1434
|
+
* Compute a tier distribution summary for a set of attestations.
|
|
1464
1435
|
*/
|
|
1465
|
-
declare
|
|
1466
|
-
|
|
1467
|
-
private primaryModelId;
|
|
1468
|
-
declare(provenance: ModelProvenance): void;
|
|
1469
|
-
get(model_id: string): ModelProvenance | undefined;
|
|
1470
|
-
list(): ModelProvenance[];
|
|
1471
|
-
primary(): ModelProvenance | undefined;
|
|
1472
|
-
setPrimary(model_id: string): void;
|
|
1473
|
-
}
|
|
1436
|
+
declare function tierDistribution(tiers: SovereigntyTier[]): Record<SovereigntyTier, number>;
|
|
1437
|
+
|
|
1474
1438
|
/**
|
|
1475
|
-
*
|
|
1439
|
+
* Sanctuary MCP Server — L4 Verifiable Reputation: Reputation Store
|
|
1440
|
+
*
|
|
1441
|
+
* Records interaction outcomes as signed attestations, queries aggregated
|
|
1442
|
+
* reputation data, and supports export/import for cross-platform portability.
|
|
1443
|
+
*
|
|
1444
|
+
* Attestation format is EAS-compatible (Ethereum Attestation Service) to
|
|
1445
|
+
* enable future on-chain anchoring without requiring blockchain for MVS.
|
|
1446
|
+
*
|
|
1447
|
+
* Security invariants:
|
|
1448
|
+
* - All attestations are signed by the recording identity
|
|
1449
|
+
* - Attestations are stored encrypted under L1 sovereignty
|
|
1450
|
+
* - Reputation queries return aggregates, never raw interaction data
|
|
1451
|
+
* - Export bundles include all signatures for independent verification
|
|
1452
|
+
* - Import verifies every signature before accepting attestations
|
|
1476
1453
|
*/
|
|
1477
|
-
declare const MODEL_PRESETS: {
|
|
1478
|
-
/**
|
|
1479
|
-
* Claude Opus 4 via Anthropic API (cloud inference, closed weights/source)
|
|
1480
|
-
*/
|
|
1481
|
-
claudeOpus4: () => ModelProvenance;
|
|
1482
|
-
/**
|
|
1483
|
-
* Qwen 3.5 via local inference (open weights, proprietary training)
|
|
1484
|
-
*/
|
|
1485
|
-
qwen35Local: () => ModelProvenance;
|
|
1486
|
-
/**
|
|
1487
|
-
* Llama 3.3 70B via local inference (open weights and code)
|
|
1488
|
-
*/
|
|
1489
|
-
llama33Local: () => ModelProvenance;
|
|
1490
|
-
/**
|
|
1491
|
-
* Mistral 7B (open weights, open code, local inference)
|
|
1492
|
-
*/
|
|
1493
|
-
mistral7bLocal: () => ModelProvenance;
|
|
1494
|
-
};
|
|
1495
1454
|
|
|
1455
|
+
/** Interaction outcome for recording */
|
|
1456
|
+
interface InteractionOutcome {
|
|
1457
|
+
type: "transaction" | "negotiation" | "service" | "dispute" | "custom";
|
|
1458
|
+
result: "completed" | "partial" | "failed" | "disputed";
|
|
1459
|
+
metrics?: Record<string, number>;
|
|
1460
|
+
}
|
|
1461
|
+
/** A signed attestation of an interaction */
|
|
1462
|
+
interface Attestation {
|
|
1463
|
+
attestation_id: string;
|
|
1464
|
+
schema: "sanctuary-interaction-v1";
|
|
1465
|
+
data: {
|
|
1466
|
+
interaction_id: string;
|
|
1467
|
+
participant_did: string;
|
|
1468
|
+
counterparty_did: string;
|
|
1469
|
+
outcome_type: string;
|
|
1470
|
+
outcome_result: string;
|
|
1471
|
+
metrics: Record<string, number>;
|
|
1472
|
+
context: string;
|
|
1473
|
+
timestamp: string;
|
|
1474
|
+
/** Sovereignty tier of the signer at time of recording */
|
|
1475
|
+
sovereignty_tier?: SovereigntyTier;
|
|
1476
|
+
};
|
|
1477
|
+
signature: string;
|
|
1478
|
+
signer: string;
|
|
1479
|
+
}
|
|
1480
|
+
/** Stored attestation (encrypted at rest) */
|
|
1481
|
+
interface StoredAttestation {
|
|
1482
|
+
attestation: Attestation;
|
|
1483
|
+
counterparty_attestation?: string;
|
|
1484
|
+
counterparty_confirmed: boolean;
|
|
1485
|
+
recorded_at: string;
|
|
1486
|
+
}
|
|
1487
|
+
/** Aggregated metric statistics */
|
|
1488
|
+
interface MetricAggregate {
|
|
1489
|
+
mean: number;
|
|
1490
|
+
median: number;
|
|
1491
|
+
min: number;
|
|
1492
|
+
max: number;
|
|
1493
|
+
count: number;
|
|
1494
|
+
}
|
|
1495
|
+
/** Reputation query result */
|
|
1496
|
+
interface ReputationSummary {
|
|
1497
|
+
total_interactions: number;
|
|
1498
|
+
completed: number;
|
|
1499
|
+
partial: number;
|
|
1500
|
+
failed: number;
|
|
1501
|
+
disputed: number;
|
|
1502
|
+
contexts: string[];
|
|
1503
|
+
time_range: {
|
|
1504
|
+
start: string;
|
|
1505
|
+
end: string;
|
|
1506
|
+
};
|
|
1507
|
+
aggregate_metrics: Record<string, MetricAggregate>;
|
|
1508
|
+
}
|
|
1496
1509
|
/**
|
|
1497
|
-
*
|
|
1498
|
-
*
|
|
1499
|
-
*
|
|
1500
|
-
* Scans tool arguments for role override, security bypass, encoding evasion,
|
|
1501
|
-
* data exfiltration, and prompt stuffing signals.
|
|
1502
|
-
*
|
|
1503
|
-
* SEC-034/SEC-035: Enhanced with Unicode sanitization pre-pass, decoded content
|
|
1504
|
-
* re-scanning, token budget analysis, and outbound content scanning.
|
|
1505
|
-
*
|
|
1506
|
-
* Security invariants:
|
|
1507
|
-
* - Always returns a result, never throws
|
|
1508
|
-
* - Typical scan completes in < 5ms
|
|
1509
|
-
* - False positives minimized via field-aware scanning
|
|
1510
|
-
* - Recursive scanning of nested objects/arrays
|
|
1511
|
-
* - Outbound scanning catches secret leaks and injection artifact survival
|
|
1510
|
+
* L4 attestation evidence summary for the SHR degradation emitter and the
|
|
1511
|
+
* dashboard evidence widget. Derived from the stored attestations; does not
|
|
1512
|
+
* include Verascore-link state (tracked separately via audit log).
|
|
1512
1513
|
*/
|
|
1513
|
-
interface
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1514
|
+
interface L4AttestationSummary {
|
|
1515
|
+
/** Total number of attestations covered by the summary */
|
|
1516
|
+
attestation_count: number;
|
|
1517
|
+
/** Count of attestations at each sovereignty tier */
|
|
1518
|
+
tier_distribution: Record<SovereigntyTier, number>;
|
|
1519
|
+
/** ISO timestamp of the most recent attestation, or null if none */
|
|
1520
|
+
most_recent_attestation_at: string | null;
|
|
1521
|
+
/** Count of attestations with outcome_result === "disputed" */
|
|
1522
|
+
dispute_count: number;
|
|
1523
|
+
/** Count of attestations per context label */
|
|
1524
|
+
context_breakdown: Record<string, number>;
|
|
1518
1525
|
}
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1526
|
+
/** Portable reputation bundle */
|
|
1527
|
+
interface ReputationBundle {
|
|
1528
|
+
version: "SANCTUARY_REP_V1";
|
|
1529
|
+
attestations: Attestation[];
|
|
1530
|
+
exported_at: string;
|
|
1531
|
+
exporter_did: string;
|
|
1532
|
+
bundle_signature: string;
|
|
1524
1533
|
}
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1534
|
+
/** Escrow for trust bootstrapping */
|
|
1535
|
+
interface Escrow {
|
|
1536
|
+
escrow_id: string;
|
|
1537
|
+
transaction_terms: string;
|
|
1538
|
+
terms_hash: string;
|
|
1539
|
+
collateral_amount?: number;
|
|
1540
|
+
counterparty_did: string;
|
|
1541
|
+
creator_did: string;
|
|
1542
|
+
created_at: string;
|
|
1543
|
+
expires_at: string;
|
|
1544
|
+
status: "pending" | "active" | "released" | "disputed" | "expired";
|
|
1530
1545
|
}
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
* @param content The outbound content string to scan
|
|
1547
|
-
* @returns DetectionResult with outbound-specific signal types
|
|
1548
|
-
*/
|
|
1549
|
-
scanOutbound(content: string): DetectionResult;
|
|
1550
|
-
/**
|
|
1551
|
-
* Recursively scan a value and all nested values.
|
|
1552
|
-
*/
|
|
1553
|
-
private scanValue;
|
|
1546
|
+
/** Principal guarantee for a new agent */
|
|
1547
|
+
interface Guarantee {
|
|
1548
|
+
guarantee_id: string;
|
|
1549
|
+
principal_did: string;
|
|
1550
|
+
agent_did: string;
|
|
1551
|
+
scope: string;
|
|
1552
|
+
max_liability?: number;
|
|
1553
|
+
valid_until: string;
|
|
1554
|
+
certificate: string;
|
|
1555
|
+
created_at: string;
|
|
1556
|
+
}
|
|
1557
|
+
declare class ReputationStore {
|
|
1558
|
+
private storage;
|
|
1559
|
+
private encryptionKey;
|
|
1560
|
+
constructor(storage: StorageBackend, masterKey: Uint8Array);
|
|
1554
1561
|
/**
|
|
1555
|
-
*
|
|
1562
|
+
* Record an interaction outcome as a signed attestation.
|
|
1556
1563
|
*/
|
|
1557
|
-
|
|
1564
|
+
record(interactionId: string, counterpartyDid: string, outcome: InteractionOutcome, context: string, identity: StoredIdentity, identityEncryptionKey: Uint8Array, counterpartyAttestation?: string, sovereigntyTier?: SovereigntyTier): Promise<StoredAttestation>;
|
|
1558
1565
|
/**
|
|
1559
|
-
*
|
|
1560
|
-
*
|
|
1561
|
-
* variation selectors, and other invisible categories.
|
|
1566
|
+
* Query reputation data with filtering.
|
|
1567
|
+
* Returns aggregates only — not raw interaction data.
|
|
1562
1568
|
*/
|
|
1563
|
-
|
|
1569
|
+
query(options: {
|
|
1570
|
+
context?: string;
|
|
1571
|
+
time_range?: {
|
|
1572
|
+
start: string;
|
|
1573
|
+
end: string;
|
|
1574
|
+
};
|
|
1575
|
+
metrics?: string[];
|
|
1576
|
+
counterparty_did?: string;
|
|
1577
|
+
}): Promise<ReputationSummary>;
|
|
1564
1578
|
/**
|
|
1565
|
-
*
|
|
1566
|
-
* Returns a new string with all invisible chars removed.
|
|
1579
|
+
* Export attestations as a portable reputation bundle.
|
|
1567
1580
|
*/
|
|
1568
|
-
|
|
1581
|
+
exportBundle(identity: StoredIdentity, identityEncryptionKey: Uint8Array, context?: string): Promise<ReputationBundle>;
|
|
1569
1582
|
/**
|
|
1570
|
-
*
|
|
1571
|
-
*
|
|
1572
|
-
* ideographs, combining characters, emoji sequences). If the estimated token
|
|
1573
|
-
* cost per character is anomalously high, this may be a wallet-drain payload.
|
|
1583
|
+
* Import attestations from a reputation bundle.
|
|
1584
|
+
* Verifies signatures if requested (default: true).
|
|
1574
1585
|
*
|
|
1575
|
-
*
|
|
1576
|
-
* If the ratio of estimated tokens to char count exceeds 3x, flag it.
|
|
1577
|
-
*/
|
|
1578
|
-
private detectTokenBudgetAttack;
|
|
1579
|
-
/**
|
|
1580
|
-
* Detect encoded content (base64, hex, HTML entities, URL encoding),
|
|
1581
|
-
* decode it, and re-scan the decoded content through injection patterns.
|
|
1582
|
-
* If the decoded content contains injection patterns, flag as encoding_evasion.
|
|
1583
|
-
*/
|
|
1584
|
-
private detectEncodedPayloads;
|
|
1585
|
-
/**
|
|
1586
|
-
* Check if a string contains any injection patterns (role override or security bypass).
|
|
1587
|
-
*/
|
|
1588
|
-
private containsInjectionPatterns;
|
|
1589
|
-
/**
|
|
1590
|
-
* Safely decode a base64 string. Returns null if it's not valid base64
|
|
1591
|
-
* or doesn't decode to a meaningful string.
|
|
1592
|
-
*/
|
|
1593
|
-
private safeBase64Decode;
|
|
1594
|
-
/**
|
|
1595
|
-
* Safely decode a hex string. Returns null on failure.
|
|
1596
|
-
*/
|
|
1597
|
-
private safeHexDecode;
|
|
1598
|
-
/**
|
|
1599
|
-
* Decode HTML numeric entities (&#xHH; and &#DDD;) in a string.
|
|
1600
|
-
*/
|
|
1601
|
-
private decodeHtmlEntities;
|
|
1602
|
-
/**
|
|
1603
|
-
* Safely decode a URL-encoded string. Returns null on failure.
|
|
1604
|
-
*/
|
|
1605
|
-
private safeUrlDecode;
|
|
1606
|
-
/**
|
|
1607
|
-
* Heuristic: does this look like readable text (vs. binary garbage)?
|
|
1608
|
-
* Checks that most characters are printable ASCII or common Unicode.
|
|
1609
|
-
*/
|
|
1610
|
-
private looksLikeText;
|
|
1611
|
-
/**
|
|
1612
|
-
* Detect API keys and secrets in outbound content.
|
|
1613
|
-
*/
|
|
1614
|
-
private detectSecretPatterns;
|
|
1615
|
-
/**
|
|
1616
|
-
* Detect data exfiltration via markdown images with data-carrying query params.
|
|
1617
|
-
*/
|
|
1618
|
-
private detectOutboundExfiltration;
|
|
1619
|
-
/**
|
|
1620
|
-
* Detect internal filesystem path leaks in outbound content.
|
|
1621
|
-
*/
|
|
1622
|
-
private detectInternalPathLeaks;
|
|
1623
|
-
/**
|
|
1624
|
-
* Detect private IP addresses and localhost references in outbound content.
|
|
1586
|
+
* @param publicKeys - Map of DID → public key bytes for signature verification
|
|
1625
1587
|
*/
|
|
1626
|
-
|
|
1588
|
+
importBundle(bundle: ReputationBundle, verifySignatures: boolean, publicKeys: Map<string, Uint8Array>): Promise<{
|
|
1589
|
+
imported: number;
|
|
1590
|
+
invalid: number;
|
|
1591
|
+
contexts: string[];
|
|
1592
|
+
}>;
|
|
1627
1593
|
/**
|
|
1628
|
-
*
|
|
1629
|
-
* These should never appear in agent output — their presence indicates
|
|
1630
|
-
* injection artifact survival.
|
|
1594
|
+
* Create an escrow for trust bootstrapping.
|
|
1631
1595
|
*/
|
|
1632
|
-
|
|
1596
|
+
createEscrow(transactionTerms: string, counterpartyDid: string, timeoutSeconds: number, creatorDid: string, collateralAmount?: number): Promise<Escrow>;
|
|
1633
1597
|
/**
|
|
1634
|
-
*
|
|
1598
|
+
* Get an escrow by ID.
|
|
1635
1599
|
*/
|
|
1636
|
-
|
|
1600
|
+
getEscrow(escrowId: string): Promise<Escrow | null>;
|
|
1637
1601
|
/**
|
|
1638
|
-
*
|
|
1602
|
+
* Create a principal's guarantee for a new agent.
|
|
1639
1603
|
*/
|
|
1640
|
-
|
|
1604
|
+
createGuarantee(principalIdentity: StoredIdentity, agentDid: string, scope: string, durationSeconds: number, identityEncryptionKey: Uint8Array, maxLiability?: number): Promise<Guarantee>;
|
|
1641
1605
|
/**
|
|
1642
|
-
*
|
|
1606
|
+
* Summarize attestations for the L4 degradation emitter and dashboard widget.
|
|
1607
|
+
*
|
|
1608
|
+
* Returns aggregate evidence about the identity's reputation state —
|
|
1609
|
+
* counts, tier distribution, recency, dispute counts, context coverage —
|
|
1610
|
+
* without exposing raw attestations. The caller combines this with an
|
|
1611
|
+
* audit-log check for Verascore link state to produce the final
|
|
1612
|
+
* `L4Evidence` struct consumed by the SHR generator.
|
|
1613
|
+
*
|
|
1614
|
+
* @param participantDid - If provided, only count attestations where the
|
|
1615
|
+
* `participant_did` matches. If omitted, covers all attestations in the
|
|
1616
|
+
* store.
|
|
1643
1617
|
*/
|
|
1644
|
-
|
|
1618
|
+
summarizeForSHR(participantDid?: string): Promise<L4AttestationSummary>;
|
|
1645
1619
|
/**
|
|
1646
|
-
*
|
|
1620
|
+
* Load attestations for tier-weighted scoring.
|
|
1621
|
+
* Applies basic context/counterparty filtering, returns full StoredAttestations
|
|
1622
|
+
* so callers can access sovereignty_tier from attestation data.
|
|
1647
1623
|
*/
|
|
1648
|
-
|
|
1624
|
+
loadAllForTierScoring(options?: {
|
|
1625
|
+
context?: string;
|
|
1626
|
+
counterparty_did?: string;
|
|
1627
|
+
}): Promise<StoredAttestation[]>;
|
|
1628
|
+
private loadAll;
|
|
1649
1629
|
/**
|
|
1650
|
-
*
|
|
1630
|
+
* Cursor-based async iterator that loads attestations in pages.
|
|
1631
|
+
* Prevents OOM at 100K+ records by reading and decrypting in batches.
|
|
1651
1632
|
*/
|
|
1652
|
-
|
|
1633
|
+
loadAllPaginated(pageSize?: number): AsyncGenerator<StoredAttestation[]>;
|
|
1634
|
+
}
|
|
1635
|
+
|
|
1636
|
+
/**
|
|
1637
|
+
* Sanctuary MCP Server — Federation Types
|
|
1638
|
+
*
|
|
1639
|
+
* MCP-to-MCP federation enables two Sanctuary instances to:
|
|
1640
|
+
* 1. Discover each other's capabilities (SIM exchange)
|
|
1641
|
+
* 2. Establish mutual trust (sovereignty handshake)
|
|
1642
|
+
* 3. Exchange signed reputation attestations
|
|
1643
|
+
* 4. Evaluate trust for cross-instance interactions
|
|
1644
|
+
*
|
|
1645
|
+
* Federation operates as a protocol layer atop the handshake:
|
|
1646
|
+
* Handshake establishes trust → Federation uses that trust for ongoing operations.
|
|
1647
|
+
*
|
|
1648
|
+
* Key constraint: Federation MUST respect each party's sovereignty.
|
|
1649
|
+
* Neither party can compel the other to share data they haven't disclosed
|
|
1650
|
+
* via their disclosure policy.
|
|
1651
|
+
*/
|
|
1652
|
+
|
|
1653
|
+
/** A known federation peer */
|
|
1654
|
+
interface FederationPeer {
|
|
1655
|
+
/** The peer's instance ID (from their SHR) */
|
|
1656
|
+
peer_id: string;
|
|
1657
|
+
/** The peer's DID (identity) */
|
|
1658
|
+
peer_did: string;
|
|
1659
|
+
/** When this peer was first seen */
|
|
1660
|
+
first_seen: string;
|
|
1661
|
+
/** When last handshake completed */
|
|
1662
|
+
last_handshake: string;
|
|
1663
|
+
/** Current trust tier from most recent handshake */
|
|
1664
|
+
trust_tier: SovereigntyTier;
|
|
1665
|
+
/** Handshake result (for tier resolution) */
|
|
1666
|
+
handshake_result: HandshakeResult;
|
|
1667
|
+
/** Peer's advertised capabilities (from their SIM) */
|
|
1668
|
+
capabilities: FederationCapabilities;
|
|
1669
|
+
/** Whether we have a valid (non-expired) handshake */
|
|
1670
|
+
active: boolean;
|
|
1671
|
+
}
|
|
1672
|
+
/** Capabilities a peer advertises for federation */
|
|
1673
|
+
interface FederationCapabilities {
|
|
1674
|
+
/** Whether the peer supports reputation exchange */
|
|
1675
|
+
reputation_exchange: boolean;
|
|
1676
|
+
/** Whether the peer supports mutual attestation */
|
|
1677
|
+
mutual_attestation: boolean;
|
|
1678
|
+
/** Whether the peer supports encrypted channels */
|
|
1679
|
+
encrypted_channel: boolean;
|
|
1680
|
+
/** Supported attestation formats */
|
|
1681
|
+
attestation_formats: string[];
|
|
1682
|
+
}
|
|
1683
|
+
/** Trust evaluation result for a federation peer */
|
|
1684
|
+
interface PeerTrustEvaluation {
|
|
1685
|
+
peer_id: string;
|
|
1686
|
+
/** Current sovereignty tier (from handshake) */
|
|
1687
|
+
sovereignty_tier: SovereigntyTier;
|
|
1688
|
+
/** Whether handshake is current (not expired) */
|
|
1689
|
+
handshake_current: boolean;
|
|
1690
|
+
/** Reputation summary (if available) */
|
|
1691
|
+
reputation_score?: number;
|
|
1692
|
+
/** How many mutual attestations we share */
|
|
1693
|
+
mutual_attestation_count: number;
|
|
1694
|
+
/** Overall trust assessment */
|
|
1695
|
+
trust_level: "high" | "medium" | "low" | "none";
|
|
1696
|
+
/** Reasoning for the assessment */
|
|
1697
|
+
factors: string[];
|
|
1698
|
+
/** Evaluated at */
|
|
1699
|
+
evaluated_at: string;
|
|
1700
|
+
}
|
|
1701
|
+
|
|
1702
|
+
/**
|
|
1703
|
+
* Sanctuary MCP Server — Federation Peer Registry
|
|
1704
|
+
*
|
|
1705
|
+
* Manages known federation peers. Peers are discovered through handshakes
|
|
1706
|
+
* and tracked for ongoing federation operations.
|
|
1707
|
+
*
|
|
1708
|
+
* The registry is the source of truth for:
|
|
1709
|
+
* - Who we've federated with
|
|
1710
|
+
* - Current trust status of each peer
|
|
1711
|
+
* - Peer capabilities (what operations they support)
|
|
1712
|
+
*
|
|
1713
|
+
* Security invariants:
|
|
1714
|
+
* - Peers are ONLY added through completed handshakes (not self-registration)
|
|
1715
|
+
* - Trust tiers degrade automatically when handshakes expire
|
|
1716
|
+
* - Peer data is stored encrypted under L1 sovereignty
|
|
1717
|
+
*/
|
|
1718
|
+
|
|
1719
|
+
declare class FederationRegistry {
|
|
1720
|
+
private peers;
|
|
1653
1721
|
/**
|
|
1654
|
-
*
|
|
1722
|
+
* Register or update a peer from a completed handshake.
|
|
1723
|
+
* This is the ONLY way peers enter the registry.
|
|
1655
1724
|
*/
|
|
1656
|
-
|
|
1725
|
+
registerFromHandshake(result: HandshakeResult, peerDid: string, capabilities?: Partial<FederationCapabilities>): FederationPeer;
|
|
1657
1726
|
/**
|
|
1658
|
-
*
|
|
1727
|
+
* Get a peer by instance ID.
|
|
1728
|
+
* Automatically updates active status based on handshake expiry.
|
|
1659
1729
|
*/
|
|
1660
|
-
|
|
1730
|
+
getPeer(peerId: string): FederationPeer | null;
|
|
1661
1731
|
/**
|
|
1662
|
-
*
|
|
1732
|
+
* List all known peers, optionally filtered by status.
|
|
1663
1733
|
*/
|
|
1664
|
-
|
|
1734
|
+
listPeers(filter?: {
|
|
1735
|
+
active_only?: boolean;
|
|
1736
|
+
}): FederationPeer[];
|
|
1665
1737
|
/**
|
|
1666
|
-
*
|
|
1667
|
-
* Latin equivalents. NFKC normalization handles fullwidth and compatibility
|
|
1668
|
-
* forms, but does NOT map Cyrillic/Greek/Armenian/Georgian lookalikes to
|
|
1669
|
-
* Latin (they're distinct codepoints by design).
|
|
1738
|
+
* Evaluate trust for a federation peer.
|
|
1670
1739
|
*
|
|
1671
|
-
*
|
|
1672
|
-
*
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
* Compute confidence score based on signals.
|
|
1677
|
-
* More high-severity signals = higher confidence.
|
|
1678
|
-
*/
|
|
1679
|
-
private computeConfidence;
|
|
1680
|
-
/**
|
|
1681
|
-
* Compute recommendation based on signals and sensitivity.
|
|
1740
|
+
* Trust assessment considers:
|
|
1741
|
+
* - Handshake status (current vs expired)
|
|
1742
|
+
* - Sovereignty tier (verified-sovereign vs degraded vs unverified)
|
|
1743
|
+
* - Reputation data (if available)
|
|
1744
|
+
* - Mutual attestation history
|
|
1682
1745
|
*/
|
|
1683
|
-
|
|
1746
|
+
evaluateTrust(peerId: string, mutualAttestationCount?: number, reputationScore?: number): PeerTrustEvaluation;
|
|
1684
1747
|
/**
|
|
1685
|
-
*
|
|
1748
|
+
* Remove a peer from the registry.
|
|
1686
1749
|
*/
|
|
1687
|
-
|
|
1688
|
-
total_scans: number;
|
|
1689
|
-
total_flags: number;
|
|
1690
|
-
total_blocks: number;
|
|
1691
|
-
signals_by_type: Record<string, number>;
|
|
1692
|
-
};
|
|
1750
|
+
removePeer(peerId: string): boolean;
|
|
1693
1751
|
/**
|
|
1694
|
-
*
|
|
1752
|
+
* Get the handshake results map (for tier resolution integration).
|
|
1695
1753
|
*/
|
|
1696
|
-
|
|
1754
|
+
getHandshakeResults(): Map<string, HandshakeResult>;
|
|
1697
1755
|
}
|
|
1698
1756
|
|
|
1699
1757
|
/**
|
|
1700
|
-
* Sanctuary MCP Server —
|
|
1758
|
+
* Sanctuary MCP Server — L2 Operational Isolation: Context Gating
|
|
1701
1759
|
*
|
|
1702
|
-
*
|
|
1703
|
-
*
|
|
1704
|
-
*
|
|
1760
|
+
* Context gating controls what information leaves the sovereignty boundary
|
|
1761
|
+
* when an agent makes outbound calls — especially inference calls to remote
|
|
1762
|
+
* LLM providers. This is the "minimum-necessary context" enforcement layer.
|
|
1763
|
+
*
|
|
1764
|
+
* The problem: When an agent sends a request to a remote LLM provider (Claude,
|
|
1765
|
+
* GPT, etc.), most harnesses send the agent's full context — conversation
|
|
1766
|
+
* history, memory, tool results, preferences, internal reasoning. The agent
|
|
1767
|
+
* has no control over what the provider sees.
|
|
1768
|
+
*
|
|
1769
|
+
* Context gating lets the agent define:
|
|
1770
|
+
* - Provider categories (inference, tool-api, logging, analytics, etc.)
|
|
1771
|
+
* - What fields/categories of context may flow to each provider type
|
|
1772
|
+
* - What must always be redacted (secrets, internal reasoning, PII, etc.)
|
|
1773
|
+
* - What requires transformation (hashing, summarizing, anonymizing)
|
|
1774
|
+
*
|
|
1775
|
+
* This sits in L2 (Operational Isolation) because it controls information
|
|
1776
|
+
* flow at the execution boundary. L3 (Selective Disclosure) handles agent-
|
|
1777
|
+
* to-agent trust negotiation with cryptographic proofs; context gating
|
|
1778
|
+
* handles agent-to-infrastructure information flow.
|
|
1779
|
+
*
|
|
1780
|
+
* Security invariants:
|
|
1781
|
+
* - Redact rules take absolute priority (like withhold in L3)
|
|
1782
|
+
* - Policies are stored encrypted under L1 sovereignty
|
|
1783
|
+
* - Every filter operation is audit-logged with a content hash
|
|
1784
|
+
* (what was sent, what was redacted — without storing the content itself)
|
|
1785
|
+
* - Default policy: redact everything not explicitly allowed
|
|
1705
1786
|
*/
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
/** Approval channel configuration */
|
|
1724
|
-
interface ApprovalChannelConfig {
|
|
1725
|
-
type: "stderr" | "webhook" | "callback";
|
|
1726
|
-
timeout_seconds: number;
|
|
1727
|
-
/**
|
|
1728
|
-
* SEC-002: auto_deny is hardcoded to true and not configurable.
|
|
1729
|
-
* Timeout on any approval channel ALWAYS results in denial.
|
|
1730
|
-
* This field is retained for backward compatibility with existing
|
|
1731
|
-
* policy files but is ignored — timeout always denies.
|
|
1732
|
-
*/
|
|
1733
|
-
auto_deny?: boolean;
|
|
1734
|
-
webhook_url?: string;
|
|
1735
|
-
webhook_secret?: string;
|
|
1787
|
+
|
|
1788
|
+
/** Provider categories that context may flow to */
|
|
1789
|
+
type ProviderCategory = "inference" | "tool-api" | "logging" | "analytics" | "peer-agent" | "custom";
|
|
1790
|
+
/** Actions that can be taken on a context field */
|
|
1791
|
+
type ContextAction = "allow" | "redact" | "hash" | "summarize" | "deny";
|
|
1792
|
+
/** A rule within a context-gating policy */
|
|
1793
|
+
interface ContextGateRule {
|
|
1794
|
+
/** Provider category this rule applies to */
|
|
1795
|
+
provider: ProviderCategory | "*";
|
|
1796
|
+
/** Fields/patterns that may pass through */
|
|
1797
|
+
allow: string[];
|
|
1798
|
+
/** Fields/patterns that must be redacted (highest priority) */
|
|
1799
|
+
redact: string[];
|
|
1800
|
+
/** Fields/patterns that should be hashed */
|
|
1801
|
+
hash: string[];
|
|
1802
|
+
/** Fields/patterns that should be summarized (advisory) */
|
|
1803
|
+
summarize: string[];
|
|
1736
1804
|
}
|
|
1737
|
-
/**
|
|
1738
|
-
interface
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
/**
|
|
1743
|
-
|
|
1744
|
-
/**
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1805
|
+
/** A complete context-gating policy */
|
|
1806
|
+
interface ContextGatePolicy {
|
|
1807
|
+
policy_id: string;
|
|
1808
|
+
policy_name: string;
|
|
1809
|
+
rules: ContextGateRule[];
|
|
1810
|
+
/** Default action when no rule matches a field */
|
|
1811
|
+
default_action: "redact" | "deny";
|
|
1812
|
+
/** Identity this policy is bound to (optional) */
|
|
1813
|
+
identity_id?: string;
|
|
1814
|
+
created_at: string;
|
|
1815
|
+
updated_at: string;
|
|
1748
1816
|
}
|
|
1749
|
-
/**
|
|
1750
|
-
interface
|
|
1751
|
-
|
|
1752
|
-
|
|
1817
|
+
/** Result of filtering a single field */
|
|
1818
|
+
interface FieldFilterResult {
|
|
1819
|
+
field: string;
|
|
1820
|
+
action: ContextAction;
|
|
1753
1821
|
reason: string;
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
}
|
|
1757
|
-
/** Approval response from the human */
|
|
1758
|
-
interface ApprovalResponse {
|
|
1759
|
-
decision: "approve" | "deny";
|
|
1760
|
-
decided_at: string;
|
|
1761
|
-
decided_by: "human" | "timeout" | "auto" | "stderr:non-interactive";
|
|
1822
|
+
/** If action is "hash", contains the hash */
|
|
1823
|
+
hash_value?: string;
|
|
1762
1824
|
}
|
|
1763
|
-
/** Result of
|
|
1764
|
-
interface
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1825
|
+
/** Result of a full context filter operation */
|
|
1826
|
+
interface ContextFilterResult {
|
|
1827
|
+
policy_id: string;
|
|
1828
|
+
provider: ProviderCategory | string;
|
|
1829
|
+
fields_allowed: number;
|
|
1830
|
+
fields_redacted: number;
|
|
1831
|
+
fields_hashed: number;
|
|
1832
|
+
fields_summarized: number;
|
|
1833
|
+
fields_denied: number;
|
|
1834
|
+
decisions: FieldFilterResult[];
|
|
1835
|
+
/** SHA-256 hash of the original context (for audit trail) */
|
|
1836
|
+
original_context_hash: string;
|
|
1837
|
+
/** SHA-256 hash of the filtered output (for audit trail) */
|
|
1838
|
+
filtered_context_hash: string;
|
|
1839
|
+
filtered_at: string;
|
|
1770
1840
|
}
|
|
1771
|
-
/**
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1841
|
+
/**
|
|
1842
|
+
* Evaluate a context field against a policy for a given provider.
|
|
1843
|
+
*
|
|
1844
|
+
* Priority order (same as L3 disclosure):
|
|
1845
|
+
* 1. Redact (blocks — highest priority)
|
|
1846
|
+
* 2. Deny (blocks entire request)
|
|
1847
|
+
* 3. Hash (transforms)
|
|
1848
|
+
* 4. Summarize (advisory transform)
|
|
1849
|
+
* 5. Allow (passes through)
|
|
1850
|
+
* 6. Default action
|
|
1851
|
+
*/
|
|
1852
|
+
declare function evaluateField(policy: ContextGatePolicy, provider: ProviderCategory | string, field: string): FieldFilterResult;
|
|
1853
|
+
/**
|
|
1854
|
+
* Filter a full context object against a policy for a given provider.
|
|
1855
|
+
* Returns per-field decisions and content hashes for the audit trail.
|
|
1856
|
+
*/
|
|
1857
|
+
declare function filterContext(policy: ContextGatePolicy, provider: ProviderCategory | string, context: Record<string, unknown>): ContextFilterResult;
|
|
1858
|
+
/**
|
|
1859
|
+
* Context gate policy store — encrypted under L1 sovereignty.
|
|
1860
|
+
*/
|
|
1861
|
+
declare class ContextGatePolicyStore {
|
|
1862
|
+
private storage;
|
|
1863
|
+
private encryptionKey;
|
|
1864
|
+
private policies;
|
|
1865
|
+
constructor(storage: StorageBackend, masterKey: Uint8Array);
|
|
1866
|
+
/**
|
|
1867
|
+
* Create and store a new context-gating policy.
|
|
1868
|
+
*/
|
|
1869
|
+
create(policyName: string, rules: ContextGateRule[], defaultAction: "redact" | "deny", identityId?: string): Promise<ContextGatePolicy>;
|
|
1870
|
+
/**
|
|
1871
|
+
* Get a policy by ID.
|
|
1872
|
+
*/
|
|
1873
|
+
get(policyId: string): Promise<ContextGatePolicy | null>;
|
|
1874
|
+
/**
|
|
1875
|
+
* List all context-gating policies.
|
|
1876
|
+
*/
|
|
1877
|
+
list(): Promise<ContextGatePolicy[]>;
|
|
1878
|
+
/**
|
|
1879
|
+
* Load all persisted policies into memory.
|
|
1880
|
+
*/
|
|
1881
|
+
private loadAll;
|
|
1882
|
+
private persist;
|
|
1785
1883
|
}
|
|
1786
1884
|
|
|
1787
1885
|
/**
|
|
1788
|
-
* Sanctuary MCP Server —
|
|
1886
|
+
* Sanctuary MCP Server — L2 Context Gating: Starter Policy Templates
|
|
1789
1887
|
*
|
|
1790
|
-
*
|
|
1791
|
-
*
|
|
1792
|
-
* ensuring the agent cannot intercept or forge approval responses.
|
|
1888
|
+
* Pre-built policies for common use cases. These are starting points —
|
|
1889
|
+
* users should customize them for their specific context structure.
|
|
1793
1890
|
*
|
|
1794
|
-
*
|
|
1795
|
-
*
|
|
1796
|
-
*
|
|
1891
|
+
* Templates:
|
|
1892
|
+
*
|
|
1893
|
+
* inference-minimal
|
|
1894
|
+
* Only the current task and query reach the LLM. Everything else
|
|
1895
|
+
* is redacted. Secrets, PII, memory, reasoning, and history are
|
|
1896
|
+
* all blocked. IDs are hashed. Maximum privacy, minimum context.
|
|
1897
|
+
*
|
|
1898
|
+
* inference-standard
|
|
1899
|
+
* Task, query, and tool results pass through. Conversation history
|
|
1900
|
+
* is flagged for summarization (compress before sending). Secrets,
|
|
1901
|
+
* PII, and internal reasoning are redacted. IDs are hashed.
|
|
1902
|
+
* Balanced: the LLM has enough context to be useful without seeing
|
|
1903
|
+
* everything the agent knows.
|
|
1904
|
+
*
|
|
1905
|
+
* logging-strict
|
|
1906
|
+
* Redacts everything for logging/analytics providers. Only
|
|
1907
|
+
* operation names and timestamps pass through. Use this for
|
|
1908
|
+
* telemetry services where you want usage metrics without
|
|
1909
|
+
* content exposure.
|
|
1910
|
+
*
|
|
1911
|
+
* tool-api-scoped
|
|
1912
|
+
* Allows tool-specific parameters and the current task, redacts
|
|
1913
|
+
* memory, history, secrets, and PII. Hashes IDs. For outbound
|
|
1914
|
+
* calls to external APIs (search, database, etc.) where you need
|
|
1915
|
+
* to send query parameters but not your agent's full state.
|
|
1797
1916
|
*/
|
|
1798
1917
|
|
|
1799
|
-
/**
|
|
1800
|
-
interface
|
|
1801
|
-
|
|
1918
|
+
/** A template definition ready to be applied via the policy store */
|
|
1919
|
+
interface ContextGateTemplate {
|
|
1920
|
+
/** Machine-readable template ID */
|
|
1921
|
+
id: string;
|
|
1922
|
+
/** Human-readable name */
|
|
1923
|
+
name: string;
|
|
1924
|
+
/** One-line description */
|
|
1925
|
+
description: string;
|
|
1926
|
+
/** When to use this template */
|
|
1927
|
+
use_when: string;
|
|
1928
|
+
/** The rules that make up this template */
|
|
1929
|
+
rules: ContextGateRule[];
|
|
1930
|
+
/** Default action for unmatched fields */
|
|
1931
|
+
default_action: "redact" | "deny";
|
|
1802
1932
|
}
|
|
1933
|
+
/** All available templates, keyed by ID */
|
|
1934
|
+
declare const TEMPLATES: Record<string, ContextGateTemplate>;
|
|
1935
|
+
/** List all available template IDs */
|
|
1936
|
+
declare function listTemplateIds(): string[];
|
|
1937
|
+
/** Get a template by ID (returns undefined if not found) */
|
|
1938
|
+
declare function getTemplate(id: string): ContextGateTemplate | undefined;
|
|
1939
|
+
|
|
1803
1940
|
/**
|
|
1804
|
-
*
|
|
1941
|
+
* Sanctuary MCP Server — L2 Context Gating: Policy Recommendation Engine
|
|
1805
1942
|
*
|
|
1806
|
-
*
|
|
1807
|
-
*
|
|
1808
|
-
*
|
|
1943
|
+
* Analyzes a sample context object and recommends a context-gating policy
|
|
1944
|
+
* based on field name heuristics. The agent (or human) can then review,
|
|
1945
|
+
* adjust, and apply the recommendation.
|
|
1809
1946
|
*
|
|
1810
|
-
*
|
|
1811
|
-
*
|
|
1812
|
-
* the prompt is displayed so the human sees what is happening, and the
|
|
1813
|
-
* operation is denied immediately.
|
|
1947
|
+
* This is deliberately conservative: when in doubt, it recommends redact.
|
|
1948
|
+
* A false redaction is a usability issue; a false allow is a privacy leak.
|
|
1814
1949
|
*
|
|
1815
|
-
*
|
|
1816
|
-
* -
|
|
1817
|
-
* -
|
|
1818
|
-
* -
|
|
1819
|
-
* -
|
|
1950
|
+
* Classification heuristics:
|
|
1951
|
+
* - Known secret patterns → redact (highest confidence)
|
|
1952
|
+
* - Known PII patterns → redact (high confidence)
|
|
1953
|
+
* - Known internal state patterns → redact (high confidence)
|
|
1954
|
+
* - Known ID patterns → hash (medium confidence)
|
|
1955
|
+
* - Known history patterns → summarize (medium confidence)
|
|
1956
|
+
* - Known task/query patterns → allow (medium confidence)
|
|
1957
|
+
* - Everything else → redact (conservative default)
|
|
1958
|
+
*
|
|
1959
|
+
* WARNING: Fields like 'tool_results' and 'tool_output' are classified as
|
|
1960
|
+
* "allow" (medium confidence) but may contain sensitive data from external
|
|
1961
|
+
* API responses, including auth tokens, user data, or PII. Always review
|
|
1962
|
+
* recommendations before applying — the heuristic classifies by field NAME,
|
|
1963
|
+
* not field CONTENT.
|
|
1820
1964
|
*/
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1965
|
+
/** Classification result for a single field */
|
|
1966
|
+
interface FieldClassification {
|
|
1967
|
+
field: string;
|
|
1968
|
+
recommended_action: "allow" | "redact" | "hash" | "summarize";
|
|
1969
|
+
reason: string;
|
|
1970
|
+
confidence: "high" | "medium" | "low";
|
|
1971
|
+
/** Pattern that matched, if any */
|
|
1972
|
+
matched_pattern: string | null;
|
|
1973
|
+
}
|
|
1974
|
+
/** Full recommendation result */
|
|
1975
|
+
interface PolicyRecommendation {
|
|
1976
|
+
provider: string;
|
|
1977
|
+
classifications: FieldClassification[];
|
|
1978
|
+
recommended_rules: {
|
|
1979
|
+
allow: string[];
|
|
1980
|
+
redact: string[];
|
|
1981
|
+
hash: string[];
|
|
1982
|
+
summarize: string[];
|
|
1983
|
+
};
|
|
1984
|
+
default_action: "redact";
|
|
1985
|
+
summary: {
|
|
1986
|
+
total_fields: number;
|
|
1987
|
+
allow: number;
|
|
1988
|
+
redact: number;
|
|
1989
|
+
hash: number;
|
|
1990
|
+
summarize: number;
|
|
1991
|
+
};
|
|
1992
|
+
warnings: string[];
|
|
1825
1993
|
}
|
|
1826
1994
|
/**
|
|
1827
|
-
*
|
|
1995
|
+
* Classify a single field name and return a recommendation.
|
|
1828
1996
|
*/
|
|
1829
|
-
declare
|
|
1830
|
-
private callback;
|
|
1831
|
-
constructor(callback: (request: ApprovalRequest) => Promise<ApprovalResponse>);
|
|
1832
|
-
requestApproval(request: ApprovalRequest): Promise<ApprovalResponse>;
|
|
1833
|
-
}
|
|
1997
|
+
declare function classifyField(fieldName: string): FieldClassification;
|
|
1834
1998
|
/**
|
|
1835
|
-
*
|
|
1999
|
+
* Analyze a full context object and recommend a policy.
|
|
1836
2000
|
*/
|
|
1837
|
-
declare
|
|
1838
|
-
requestApproval(_request: ApprovalRequest): Promise<ApprovalResponse>;
|
|
1839
|
-
}
|
|
2001
|
+
declare function recommendPolicy(context: Record<string, unknown>, provider?: string): PolicyRecommendation;
|
|
1840
2002
|
|
|
1841
2003
|
/**
|
|
1842
|
-
* Sanctuary MCP Server —
|
|
2004
|
+
* Sanctuary MCP Server — L2 Model Provenance
|
|
1843
2005
|
*
|
|
1844
|
-
*
|
|
1845
|
-
* it for cross-session anomaly detection. The baseline defines "normal"
|
|
1846
|
-
* so that deviations can trigger Tier 2 approval.
|
|
2006
|
+
* Declares and attests to the model(s) powering this agent.
|
|
1847
2007
|
*
|
|
1848
|
-
*
|
|
1849
|
-
* -
|
|
1850
|
-
*
|
|
1851
|
-
*
|
|
1852
|
-
*
|
|
2008
|
+
* Vitalik Buterin's "Secure LLM" post (April 2026) identified a critical gap:
|
|
2009
|
+
* open-weights-but-not-open-source models can have trained-in backdoors. Model
|
|
2010
|
+
* provenance declaration lets agents and their operators verify the integrity
|
|
2011
|
+
* of the inference backbone.
|
|
2012
|
+
*
|
|
2013
|
+
* Tracks: model name, version, weights hash, license, open-source status,
|
|
2014
|
+
* training data hash (if available). Included in SHR L2 section.
|
|
2015
|
+
*
|
|
2016
|
+
* This sits in L2 (Operational Isolation) because it's part of the runtime
|
|
2017
|
+
* attestation surface — the agent declares what model(s) it's actually running.
|
|
1853
2018
|
*/
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
/**
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
/**
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
2019
|
+
/**
|
|
2020
|
+
* Metadata about a single model powering this agent.
|
|
2021
|
+
*/
|
|
2022
|
+
interface ModelProvenance {
|
|
2023
|
+
/** Machine-readable model ID (e.g., "qwen3.5-35b", "claude-opus-4", "llama-3.3-70b-instruct") */
|
|
2024
|
+
model_id: string;
|
|
2025
|
+
/** Human-readable model name (e.g., "Qwen 3.5", "Claude Opus 4", "Llama 3.3 70B Instruct") */
|
|
2026
|
+
model_name: string;
|
|
2027
|
+
/** Semantic version (e.g., "3.5", "4.0", "3.3") */
|
|
2028
|
+
model_version: string;
|
|
2029
|
+
/** Provider/vendor (e.g., "Alibaba Cloud", "Anthropic", "Meta", "local") */
|
|
2030
|
+
provider: string;
|
|
2031
|
+
/** SHA-256 of model weights file, if available and verifiable */
|
|
2032
|
+
weights_hash?: string;
|
|
2033
|
+
/** SHA-256 of training data manifest or metadata, if available */
|
|
2034
|
+
training_data_hash?: string;
|
|
2035
|
+
/** License identifier (e.g., "Apache-2.0", "CC-BY-4.0", "proprietary", "unknown") */
|
|
2036
|
+
license: string;
|
|
2037
|
+
/** True if model weights are publicly available (even if training is proprietary) */
|
|
2038
|
+
open_weights: boolean;
|
|
2039
|
+
/** True if full training code, data, and methodology are publicly available */
|
|
2040
|
+
open_source: boolean;
|
|
2041
|
+
/** True if inference runs on the local agent's hardware (not delegated to cloud API) */
|
|
2042
|
+
local_inference: boolean;
|
|
2043
|
+
/** ISO 8601 timestamp when this provenance was declared */
|
|
2044
|
+
declared_at: string;
|
|
2045
|
+
}
|
|
2046
|
+
/**
|
|
2047
|
+
* In-memory and persistent store for model provenance declarations.
|
|
2048
|
+
* Declarations are encrypted under L1 sovereignty.
|
|
2049
|
+
*/
|
|
2050
|
+
interface ModelProvenanceStore {
|
|
1886
2051
|
/**
|
|
1887
|
-
*
|
|
1888
|
-
* @returns the number of reads in the current 60-second window
|
|
2052
|
+
* Declare a model's provenance and add it to the store.
|
|
1889
2053
|
*/
|
|
1890
|
-
|
|
2054
|
+
declare(provenance: ModelProvenance): void;
|
|
1891
2055
|
/**
|
|
1892
|
-
*
|
|
1893
|
-
* @returns true if this is a new counterparty (not in baseline)
|
|
2056
|
+
* Retrieve a model's provenance by ID.
|
|
1894
2057
|
*/
|
|
1895
|
-
|
|
2058
|
+
get(model_id: string): ModelProvenance | undefined;
|
|
1896
2059
|
/**
|
|
1897
|
-
*
|
|
1898
|
-
* @returns the number of signs in the current 60-second window
|
|
2060
|
+
* List all declared models.
|
|
1899
2061
|
*/
|
|
1900
|
-
|
|
2062
|
+
list(): ModelProvenance[];
|
|
1901
2063
|
/**
|
|
1902
|
-
* Get the
|
|
2064
|
+
* Get the primary/main model (the one the agent uses by default for inference).
|
|
1903
2065
|
*/
|
|
1904
|
-
|
|
2066
|
+
primary(): ModelProvenance | undefined;
|
|
1905
2067
|
/**
|
|
1906
|
-
*
|
|
2068
|
+
* Set which model is the primary.
|
|
1907
2069
|
*/
|
|
1908
|
-
|
|
1909
|
-
/** Whether this is the first session */
|
|
1910
|
-
get isFirstSession(): boolean;
|
|
1911
|
-
/** Get a read-only view of the current profile */
|
|
1912
|
-
getProfile(): SessionProfile;
|
|
2070
|
+
setPrimary(model_id: string): void;
|
|
1913
2071
|
}
|
|
1914
|
-
|
|
1915
2072
|
/**
|
|
1916
|
-
*
|
|
1917
|
-
*
|
|
1918
|
-
* The three-tier approval gate sits between the MCP router and tool handlers.
|
|
1919
|
-
* Every tool call passes through the gate before execution.
|
|
1920
|
-
*
|
|
1921
|
-
* Evaluation order:
|
|
1922
|
-
* 1. Tier 1: Is this operation in the always-approve list? → Request approval.
|
|
1923
|
-
* 2. Tier 2: Does this call represent a behavioral anomaly? → Request approval.
|
|
1924
|
-
* 3. Tier 3 / default: Allow with audit logging.
|
|
1925
|
-
*
|
|
1926
|
-
* Security invariants:
|
|
1927
|
-
* - The gate cannot be bypassed — it wraps every tool handler.
|
|
1928
|
-
* - Denial responses do not reveal policy details to the agent.
|
|
1929
|
-
* - All gate decisions (approve, deny, allow) are audit-logged.
|
|
2073
|
+
* In-memory implementation of ModelProvenanceStore.
|
|
2074
|
+
* Suitable for most use cases. For encrypted persistence, integrate with L1 state store.
|
|
1930
2075
|
*/
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
private auditLog;
|
|
1945
|
-
private injectionDetector;
|
|
1946
|
-
private onInjectionAlert?;
|
|
1947
|
-
private proxyTierResolver?;
|
|
1948
|
-
constructor(policy: PrincipalPolicy, baseline: BaselineTracker, channel: ApprovalChannel, auditLog: AuditLog, injectionDetector?: InjectionDetector, onInjectionAlert?: InjectionAlertCallback);
|
|
1949
|
-
/**
|
|
1950
|
-
* Set the proxy tier resolver. Called after the proxy router is initialized.
|
|
1951
|
-
*/
|
|
1952
|
-
setProxyTierResolver(resolver: ProxyTierResolver): void;
|
|
2076
|
+
declare class InMemoryModelProvenanceStore implements ModelProvenanceStore {
|
|
2077
|
+
private models;
|
|
2078
|
+
private primaryModelId;
|
|
2079
|
+
declare(provenance: ModelProvenance): void;
|
|
2080
|
+
get(model_id: string): ModelProvenance | undefined;
|
|
2081
|
+
list(): ModelProvenance[];
|
|
2082
|
+
primary(): ModelProvenance | undefined;
|
|
2083
|
+
setPrimary(model_id: string): void;
|
|
2084
|
+
}
|
|
2085
|
+
/**
|
|
2086
|
+
* Common model provenance presets for quick initialization.
|
|
2087
|
+
*/
|
|
2088
|
+
declare const MODEL_PRESETS: {
|
|
1953
2089
|
/**
|
|
1954
|
-
*
|
|
1955
|
-
*
|
|
1956
|
-
* @param toolName - Full MCP tool name (e.g., "state_export")
|
|
1957
|
-
* @param args - Tool call arguments (for context extraction)
|
|
1958
|
-
* @returns GateResult indicating whether the call is allowed
|
|
2090
|
+
* Claude Opus 4 via Anthropic API (cloud inference, closed weights/source)
|
|
1959
2091
|
*/
|
|
1960
|
-
|
|
2092
|
+
claudeOpus4: () => ModelProvenance;
|
|
1961
2093
|
/**
|
|
1962
|
-
*
|
|
2094
|
+
* Qwen 3.5 via local inference (open weights, proprietary training)
|
|
1963
2095
|
*/
|
|
1964
|
-
|
|
2096
|
+
qwen35Local: () => ModelProvenance;
|
|
1965
2097
|
/**
|
|
1966
|
-
*
|
|
2098
|
+
* Llama 3.3 70B via local inference (open weights and code)
|
|
1967
2099
|
*/
|
|
1968
|
-
|
|
2100
|
+
llama33Local: () => ModelProvenance;
|
|
1969
2101
|
/**
|
|
1970
|
-
*
|
|
1971
|
-
* Strips potentially large values to keep the prompt readable.
|
|
2102
|
+
* Mistral 7B (open weights, open code, local inference)
|
|
1972
2103
|
*/
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
getBaseline(): BaselineTracker;
|
|
1976
|
-
/** Get the injection detector for stats/configuration access */
|
|
1977
|
-
getInjectionDetector(): InjectionDetector;
|
|
1978
|
-
}
|
|
1979
|
-
|
|
1980
|
-
/**
|
|
1981
|
-
* Sanctuary MCP Server — Tool Router
|
|
1982
|
-
*
|
|
1983
|
-
* Routes sanctuary/* tool calls to their layer-specific handlers.
|
|
1984
|
-
* Every tool call passes through schema validation and the ApprovalGate
|
|
1985
|
-
* (if configured) before execution. Neither can be bypassed.
|
|
1986
|
-
*
|
|
1987
|
-
* This module is the abstraction boundary for MCP SDK version migration —
|
|
1988
|
-
* if the SDK API changes, only this module needs updating.
|
|
1989
|
-
*/
|
|
1990
|
-
|
|
1991
|
-
/** Tool handler function signature */
|
|
1992
|
-
type ToolHandler = (args: Record<string, unknown>) => Promise<{
|
|
1993
|
-
content: Array<{
|
|
1994
|
-
type: "text";
|
|
1995
|
-
text: string;
|
|
1996
|
-
}>;
|
|
1997
|
-
}>;
|
|
1998
|
-
/** Tool definition for registration */
|
|
1999
|
-
interface ToolDefinition {
|
|
2000
|
-
name: string;
|
|
2001
|
-
description: string;
|
|
2002
|
-
inputSchema: Record<string, unknown>;
|
|
2003
|
-
handler: ToolHandler;
|
|
2004
|
-
}
|
|
2104
|
+
mistral7bLocal: () => ModelProvenance;
|
|
2105
|
+
};
|
|
2005
2106
|
|
|
2006
2107
|
/**
|
|
2007
2108
|
* Sanctuary MCP Server — L2 Context Gating: Automatic Enforcer
|
|
@@ -2620,37 +2721,6 @@ declare class FilesystemStorage implements StorageBackend {
|
|
|
2620
2721
|
*/
|
|
2621
2722
|
declare function loadPrincipalPolicy(storagePath: string): Promise<PrincipalPolicy>;
|
|
2622
2723
|
|
|
2623
|
-
/**
|
|
2624
|
-
* Sanctuary MCP Server — L1 Cognitive Sovereignty: Tool Definitions
|
|
2625
|
-
*
|
|
2626
|
-
* MCP tool wrappers for StateStore and IdentityRoot operations.
|
|
2627
|
-
* These tools are the public API that agents interact with.
|
|
2628
|
-
*/
|
|
2629
|
-
|
|
2630
|
-
/** Manages all identities — provides storage and retrieval */
|
|
2631
|
-
declare class IdentityManager {
|
|
2632
|
-
private storage;
|
|
2633
|
-
private masterKey;
|
|
2634
|
-
private identities;
|
|
2635
|
-
private primaryIdentityId;
|
|
2636
|
-
constructor(storage: StorageBackend, masterKey: Uint8Array);
|
|
2637
|
-
private get encryptionKey();
|
|
2638
|
-
/** Load identities from storage on startup.
|
|
2639
|
-
* Returns { total: number of encrypted files found, loaded: number successfully decrypted }.
|
|
2640
|
-
* A mismatch (total > 0, loaded === 0) indicates a wrong master key / missing passphrase.
|
|
2641
|
-
*/
|
|
2642
|
-
load(): Promise<{
|
|
2643
|
-
total: number;
|
|
2644
|
-
loaded: number;
|
|
2645
|
-
failed: number;
|
|
2646
|
-
}>;
|
|
2647
|
-
/** Save an identity to storage */
|
|
2648
|
-
save(identity: StoredIdentity): Promise<void>;
|
|
2649
|
-
get(id: string): StoredIdentity | undefined;
|
|
2650
|
-
getDefault(): StoredIdentity | undefined;
|
|
2651
|
-
list(): PublicIdentity[];
|
|
2652
|
-
}
|
|
2653
|
-
|
|
2654
2724
|
/**
|
|
2655
2725
|
* Sanctuary MCP Server — SHR Generator
|
|
2656
2726
|
*
|
|
@@ -2658,12 +2728,56 @@ declare class IdentityManager {
|
|
|
2658
2728
|
* signs it with a specified identity, and returns the complete signed SHR.
|
|
2659
2729
|
*/
|
|
2660
2730
|
|
|
2731
|
+
/**
|
|
2732
|
+
* Observed L4 reputation state used by the emitter. Callers gather these
|
|
2733
|
+
* facts from the reputation store + audit log; the emitter derives
|
|
2734
|
+
* degradations from them. Keeping evidence as plain data keeps the
|
|
2735
|
+
* generator synchronous and easy to test.
|
|
2736
|
+
*/
|
|
2737
|
+
interface L4Evidence {
|
|
2738
|
+
/** Total attestations attributed to the signing identity */
|
|
2739
|
+
attestation_count: number;
|
|
2740
|
+
/** Count of attestations at each sovereignty tier */
|
|
2741
|
+
tier_distribution: Record<SovereigntyTier, number>;
|
|
2742
|
+
/** ISO timestamp of most recent attestation, or null when none exist */
|
|
2743
|
+
most_recent_attestation_at: string | null;
|
|
2744
|
+
/** Count of attestations with outcome_result === "disputed" */
|
|
2745
|
+
dispute_count: number;
|
|
2746
|
+
/** Attestation count per context label (optional; used by dashboard) */
|
|
2747
|
+
context_breakdown?: Record<string, number>;
|
|
2748
|
+
/**
|
|
2749
|
+
* True iff the `reputation_publish` tool has been successfully invoked
|
|
2750
|
+
* for this identity (i.e., there is at least one success audit entry).
|
|
2751
|
+
*/
|
|
2752
|
+
verascore_linked: boolean;
|
|
2753
|
+
/**
|
|
2754
|
+
* Optional overrides for the emitter thresholds. Defaults apply when
|
|
2755
|
+
* omitted or when a field is missing.
|
|
2756
|
+
*/
|
|
2757
|
+
thresholds?: {
|
|
2758
|
+
freshness_window_days?: number;
|
|
2759
|
+
low_tier_dominance_threshold?: number;
|
|
2760
|
+
};
|
|
2761
|
+
}
|
|
2661
2762
|
interface SHRGeneratorOptions {
|
|
2662
2763
|
config: SanctuaryConfig;
|
|
2663
2764
|
identityManager: IdentityManager;
|
|
2664
2765
|
masterKey: Uint8Array;
|
|
2665
2766
|
/** Override validity window (milliseconds). Default: 1 hour. */
|
|
2666
2767
|
validityMs?: number;
|
|
2768
|
+
/**
|
|
2769
|
+
* Optional L4 reputation evidence. When provided, the generator emits
|
|
2770
|
+
* L4 degradations (NO_REPUTATION_HISTORY, LOW_TIER_DOMINANCE,
|
|
2771
|
+
* STALE_REPUTATION, DISPUTE_ON_RECORD, NO_VERASCORE_LINK) accordingly
|
|
2772
|
+
* and downgrades `layers.l4.status` to `degraded` when any fire.
|
|
2773
|
+
* When omitted, L4 is left at "active" (backward-compatible).
|
|
2774
|
+
*/
|
|
2775
|
+
l4Evidence?: L4Evidence;
|
|
2776
|
+
/**
|
|
2777
|
+
* Clock override for deterministic testing of staleness behavior.
|
|
2778
|
+
* Defaults to the current wall clock.
|
|
2779
|
+
*/
|
|
2780
|
+
now?: Date;
|
|
2667
2781
|
}
|
|
2668
2782
|
/**
|
|
2669
2783
|
* Generate and sign a Sovereignty Health Report.
|
|
@@ -3358,6 +3472,279 @@ declare function createBridgeCommitment(outcome: ConcordiaOutcome, identity: Sto
|
|
|
3358
3472
|
*/
|
|
3359
3473
|
declare function verifyBridgeCommitment(commitment: BridgeCommitment, outcome: ConcordiaOutcome, committerPublicKey: Uint8Array): BridgeVerificationResult;
|
|
3360
3474
|
|
|
3475
|
+
/**
|
|
3476
|
+
* Sanctuary Dashboard — Protection Snapshot Aggregator
|
|
3477
|
+
*
|
|
3478
|
+
* Pulls unified protection state from the existing subsystems
|
|
3479
|
+
* (IdentityManager, AuditLog, ClientManager, BaselineTracker, policy)
|
|
3480
|
+
* and returns a single typed snapshot consumed by the API + HTML.
|
|
3481
|
+
*
|
|
3482
|
+
* The aggregator is the single source of truth for dashboard state.
|
|
3483
|
+
* It is pure (no I/O beyond what the injected sources already do) and
|
|
3484
|
+
* safe to call repeatedly — callers control freshness.
|
|
3485
|
+
*/
|
|
3486
|
+
|
|
3487
|
+
type LayerState = "full" | "degraded" | "compromised";
|
|
3488
|
+
type OverallStatus = "healthy" | "degraded" | "compromised";
|
|
3489
|
+
interface AgentInfo {
|
|
3490
|
+
display_name: string;
|
|
3491
|
+
did: string | null;
|
|
3492
|
+
did_fingerprint: string | null;
|
|
3493
|
+
identity_count: number;
|
|
3494
|
+
primary_identity_id: string | null;
|
|
3495
|
+
}
|
|
3496
|
+
interface L1Status {
|
|
3497
|
+
label: string;
|
|
3498
|
+
state: LayerState;
|
|
3499
|
+
headline: string;
|
|
3500
|
+
encryption: string;
|
|
3501
|
+
injection_blocked_today: number;
|
|
3502
|
+
memory_attest_ready: boolean;
|
|
3503
|
+
}
|
|
3504
|
+
interface L2Status {
|
|
3505
|
+
label: string;
|
|
3506
|
+
state: LayerState;
|
|
3507
|
+
headline: string;
|
|
3508
|
+
isolation_type: string;
|
|
3509
|
+
tee_available: boolean;
|
|
3510
|
+
tee_status: string;
|
|
3511
|
+
sandbox_status: string;
|
|
3512
|
+
}
|
|
3513
|
+
interface L3Status {
|
|
3514
|
+
label: string;
|
|
3515
|
+
state: LayerState;
|
|
3516
|
+
headline: string;
|
|
3517
|
+
did_active: boolean;
|
|
3518
|
+
vc_count: number;
|
|
3519
|
+
proofs_today: number;
|
|
3520
|
+
}
|
|
3521
|
+
/** A single L4 degradation surfaced to the dashboard widget. */
|
|
3522
|
+
interface L4ActiveDegradation {
|
|
3523
|
+
code: string;
|
|
3524
|
+
severity: "info" | "warning" | "critical";
|
|
3525
|
+
description: string;
|
|
3526
|
+
mitigation?: string;
|
|
3527
|
+
}
|
|
3528
|
+
interface L4Status {
|
|
3529
|
+
label: string;
|
|
3530
|
+
state: LayerState;
|
|
3531
|
+
headline: string;
|
|
3532
|
+
score: number | null;
|
|
3533
|
+
profile_url: string | null;
|
|
3534
|
+
claim_cta: string | null;
|
|
3535
|
+
/**
|
|
3536
|
+
* Evidence surfaced under the L4 tile so users can tell what underlies
|
|
3537
|
+
* the reputation state. Null when no reputation store is wired in
|
|
3538
|
+
* (standalone mode, some tests).
|
|
3539
|
+
*/
|
|
3540
|
+
evidence?: {
|
|
3541
|
+
attestation_count: number;
|
|
3542
|
+
tier_distribution: Record<SovereigntyTier, number>;
|
|
3543
|
+
most_recent_attestation_at: string | null;
|
|
3544
|
+
dispute_count: number;
|
|
3545
|
+
context_breakdown: Record<string, number>;
|
|
3546
|
+
verascore_linked: boolean;
|
|
3547
|
+
};
|
|
3548
|
+
/**
|
|
3549
|
+
* SHR-aligned L4 layer score (0-100) when evidence is available.
|
|
3550
|
+
* Computed with the same scoring model the gateway adapter uses so
|
|
3551
|
+
* counterparties and the dashboard agree on the number.
|
|
3552
|
+
*/
|
|
3553
|
+
layer_score?: number;
|
|
3554
|
+
/** Active L4 degradations rendered under the widget. */
|
|
3555
|
+
active_degradations?: L4ActiveDegradation[];
|
|
3556
|
+
}
|
|
3557
|
+
interface ActivityEntry {
|
|
3558
|
+
timestamp: string;
|
|
3559
|
+
tool: string;
|
|
3560
|
+
server: string;
|
|
3561
|
+
tier: 1 | 2 | 3;
|
|
3562
|
+
result: "allowed" | "denied" | "approved" | "pending";
|
|
3563
|
+
}
|
|
3564
|
+
interface PendingApproval {
|
|
3565
|
+
id: string;
|
|
3566
|
+
operation: string;
|
|
3567
|
+
tier: 1 | 2;
|
|
3568
|
+
reason: string;
|
|
3569
|
+
created_at: string;
|
|
3570
|
+
}
|
|
3571
|
+
interface UpstreamServerStatus {
|
|
3572
|
+
name: string;
|
|
3573
|
+
state: string;
|
|
3574
|
+
tool_count: number;
|
|
3575
|
+
error?: string;
|
|
3576
|
+
}
|
|
3577
|
+
interface ProtectionSnapshot {
|
|
3578
|
+
overall: {
|
|
3579
|
+
status: OverallStatus;
|
|
3580
|
+
light: "green" | "yellow" | "red";
|
|
3581
|
+
headline: string;
|
|
3582
|
+
};
|
|
3583
|
+
agent: AgentInfo;
|
|
3584
|
+
layers: {
|
|
3585
|
+
l1: L1Status;
|
|
3586
|
+
l2: L2Status;
|
|
3587
|
+
l3: L3Status;
|
|
3588
|
+
l4: L4Status;
|
|
3589
|
+
};
|
|
3590
|
+
activity: ActivityEntry[];
|
|
3591
|
+
pending_approvals: PendingApproval[];
|
|
3592
|
+
audit: AuditEntry[];
|
|
3593
|
+
upstream_servers: UpstreamServerStatus[];
|
|
3594
|
+
mode: "co-located" | "standalone";
|
|
3595
|
+
server_version: string;
|
|
3596
|
+
generated_at: string;
|
|
3597
|
+
}
|
|
3598
|
+
interface ReputationLookup {
|
|
3599
|
+
score: number | null;
|
|
3600
|
+
profile_url: string | null;
|
|
3601
|
+
}
|
|
3602
|
+
interface AggregatorSources {
|
|
3603
|
+
mode: "co-located" | "standalone";
|
|
3604
|
+
server_version: string;
|
|
3605
|
+
identityManager?: IdentityManager;
|
|
3606
|
+
auditLog?: AuditLog;
|
|
3607
|
+
clientManager?: ClientManager;
|
|
3608
|
+
baseline?: BaselineTracker;
|
|
3609
|
+
policy?: PrincipalPolicy;
|
|
3610
|
+
activity?: ActivityEntry[];
|
|
3611
|
+
pendingApprovals?: PendingApproval[];
|
|
3612
|
+
reputation?: ReputationLookup;
|
|
3613
|
+
teeAvailable?: boolean;
|
|
3614
|
+
/**
|
|
3615
|
+
* Pre-computed L4 reputation evidence for the primary identity. When
|
|
3616
|
+
* present the dashboard renders the evidence widget under the L4 tile
|
|
3617
|
+
* and computes an SHR-aligned L4 layer score. Providers build this
|
|
3618
|
+
* via `gatherL4Evidence` from `shr/tools.ts`.
|
|
3619
|
+
*/
|
|
3620
|
+
l4Evidence?: L4Evidence;
|
|
3621
|
+
/** Clock override for deterministic staleness rendering in tests. */
|
|
3622
|
+
l4Now?: Date;
|
|
3623
|
+
}
|
|
3624
|
+
/**
|
|
3625
|
+
* Pull a unified protection snapshot from the injected sources.
|
|
3626
|
+
*
|
|
3627
|
+
* Any missing source degrades gracefully — standalone mode may have
|
|
3628
|
+
* no ClientManager or live activity feed, for example, and the
|
|
3629
|
+
* aggregator returns a coherent snapshot with empty arrays rather
|
|
3630
|
+
* than throwing.
|
|
3631
|
+
*/
|
|
3632
|
+
declare function getProtectionSnapshot(sources: AggregatorSources): Promise<ProtectionSnapshot>;
|
|
3633
|
+
|
|
3634
|
+
/**
|
|
3635
|
+
* Sanctuary Dashboard — HTTP API + SSE
|
|
3636
|
+
*
|
|
3637
|
+
* Request router for the unified dashboard. Pure functions that
|
|
3638
|
+
* take a request + sources and produce a response so the transport
|
|
3639
|
+
* layer (node:http) and tests can exercise the same code paths.
|
|
3640
|
+
*/
|
|
3641
|
+
|
|
3642
|
+
interface ApprovalHandlers {
|
|
3643
|
+
allow: (id: string) => Promise<boolean>;
|
|
3644
|
+
deny: (id: string) => Promise<boolean>;
|
|
3645
|
+
}
|
|
3646
|
+
interface StreamEvent {
|
|
3647
|
+
type: "snapshot" | "activity" | "approval";
|
|
3648
|
+
data: unknown;
|
|
3649
|
+
}
|
|
3650
|
+
|
|
3651
|
+
/**
|
|
3652
|
+
* Sanctuary Dashboard — HTTP Server
|
|
3653
|
+
*
|
|
3654
|
+
* Thin wrapper around node:http that wires the request handler
|
|
3655
|
+
* from api.ts. No Express. Listens on 127.0.0.1 by default.
|
|
3656
|
+
*
|
|
3657
|
+
* Exposes a minimal event emitter (publish / subscribe) so callers
|
|
3658
|
+
* can push live activity + approval events to SSE clients without
|
|
3659
|
+
* the server layer needing to know about aggregator internals.
|
|
3660
|
+
*/
|
|
3661
|
+
|
|
3662
|
+
interface DashboardServerOptions {
|
|
3663
|
+
port?: number;
|
|
3664
|
+
host?: string;
|
|
3665
|
+
authToken?: string;
|
|
3666
|
+
mode: "co-located" | "standalone";
|
|
3667
|
+
sources: AggregatorSources;
|
|
3668
|
+
approvals?: ApprovalHandlers;
|
|
3669
|
+
}
|
|
3670
|
+
interface DashboardHandle {
|
|
3671
|
+
url: string;
|
|
3672
|
+
port: number;
|
|
3673
|
+
host: string;
|
|
3674
|
+
stop: () => Promise<void>;
|
|
3675
|
+
/** Push an event to all connected SSE clients. */
|
|
3676
|
+
publish: (event: StreamEvent) => void;
|
|
3677
|
+
/**
|
|
3678
|
+
* Push a fresh activity entry. Exposes a simple shortcut so callers
|
|
3679
|
+
* (e.g. the Sanctuary proxy / upstream clients) can report tool calls
|
|
3680
|
+
* without constructing a StreamEvent themselves.
|
|
3681
|
+
*/
|
|
3682
|
+
publishActivity: (entry: ActivityEntry) => void;
|
|
3683
|
+
/** Push a new pending approval (already added by the approval channel). */
|
|
3684
|
+
publishApproval: (approval: PendingApproval) => void;
|
|
3685
|
+
}
|
|
3686
|
+
declare function startDashboardServer(options: DashboardServerOptions): Promise<DashboardHandle>;
|
|
3687
|
+
|
|
3688
|
+
/**
|
|
3689
|
+
* Sanctuary Dashboard — Single-Page HTML
|
|
3690
|
+
*
|
|
3691
|
+
* Hero shield + four layer cards + live activity feed + approval queue +
|
|
3692
|
+
* audit trail. Vanilla HTML/CSS/JS in one string, matching the convention
|
|
3693
|
+
* established by server/src/cocoon/fortress-view.ts.
|
|
3694
|
+
*
|
|
3695
|
+
* The initial snapshot is embedded server-side so the page renders
|
|
3696
|
+
* correctly without JavaScript. Live updates layer on via SSE + REST.
|
|
3697
|
+
*/
|
|
3698
|
+
|
|
3699
|
+
/** Hero copy. Change here if we ever A/B test. */
|
|
3700
|
+
declare const HERO_COPY = "Your agent is protected.";
|
|
3701
|
+
interface DashboardHTMLOptions {
|
|
3702
|
+
snapshot: ProtectionSnapshot;
|
|
3703
|
+
authToken?: string;
|
|
3704
|
+
}
|
|
3705
|
+
declare function renderDashboardHTML(options: DashboardHTMLOptions): string;
|
|
3706
|
+
|
|
3707
|
+
/**
|
|
3708
|
+
* Sanctuary Sovereignty Dashboard — public surface.
|
|
3709
|
+
*
|
|
3710
|
+
* Consumers import `startDashboard` to bring up the hero-shield UI
|
|
3711
|
+
* on port 3501 (default). The rest of the exports are types + utilities
|
|
3712
|
+
* for tests and callers that want to wire in live events.
|
|
3713
|
+
*/
|
|
3714
|
+
|
|
3715
|
+
interface StartDashboardOptions {
|
|
3716
|
+
port?: number;
|
|
3717
|
+
host?: string;
|
|
3718
|
+
authToken?: string;
|
|
3719
|
+
mode: "co-located" | "standalone";
|
|
3720
|
+
serverVersion: string;
|
|
3721
|
+
auditLog?: AuditLog;
|
|
3722
|
+
identityManager?: IdentityManager;
|
|
3723
|
+
clientManager?: ClientManager;
|
|
3724
|
+
baseline?: BaselineTracker;
|
|
3725
|
+
policy?: PrincipalPolicy;
|
|
3726
|
+
reputation?: ReputationLookup;
|
|
3727
|
+
teeAvailable?: boolean;
|
|
3728
|
+
approvals?: ApprovalHandlers;
|
|
3729
|
+
/** Seed activity entries (most recent first). Runtime entries arrive via publishActivity. */
|
|
3730
|
+
initialActivity?: ActivityEntry[];
|
|
3731
|
+
/** Seed pending approvals. Runtime approvals arrive via publishApproval. */
|
|
3732
|
+
initialPendingApprovals?: PendingApproval[];
|
|
3733
|
+
/**
|
|
3734
|
+
* Pre-computed L4 reputation evidence. When provided the dashboard
|
|
3735
|
+
* renders the L4 evidence widget (attestation count, tier distribution,
|
|
3736
|
+
* disputes, freshness, active degradations). Typically supplied by the
|
|
3737
|
+
* server after L4 tools are constructed.
|
|
3738
|
+
*/
|
|
3739
|
+
l4Evidence?: L4Evidence;
|
|
3740
|
+
}
|
|
3741
|
+
/**
|
|
3742
|
+
* High-level entry point used by callers (CLI, standalone service).
|
|
3743
|
+
* Returns a DashboardHandle that exposes `stop()` and `publish*`
|
|
3744
|
+
* helpers for driving live updates.
|
|
3745
|
+
*/
|
|
3746
|
+
declare function startDashboard(options: StartDashboardOptions): Promise<DashboardHandle>;
|
|
3747
|
+
|
|
3361
3748
|
/**
|
|
3362
3749
|
* Sanctuary MCP Server — Main Entry Point
|
|
3363
3750
|
*
|
|
@@ -3368,6 +3755,16 @@ declare function verifyBridgeCommitment(commitment: BridgeCommitment, outcome: C
|
|
|
3368
3755
|
interface SanctuaryServer {
|
|
3369
3756
|
server: Server;
|
|
3370
3757
|
config: SanctuaryConfig;
|
|
3758
|
+
/**
|
|
3759
|
+
* Runtime dependencies exposed for embedding callers that need
|
|
3760
|
+
* direct access to the Sanctuary substrate (e.g., the EU AI Act
|
|
3761
|
+
* compliance CLI subcommand). Most callers only use `server` and
|
|
3762
|
+
* `config`; these are optional-usage extras.
|
|
3763
|
+
*/
|
|
3764
|
+
identityManager: IdentityManager;
|
|
3765
|
+
masterKey: Uint8Array;
|
|
3766
|
+
auditLog: AuditLog;
|
|
3767
|
+
policy: PrincipalPolicy;
|
|
3371
3768
|
}
|
|
3372
3769
|
/**
|
|
3373
3770
|
* Initialize the Sanctuary MCP Server.
|
|
@@ -3381,4 +3778,4 @@ declare function createSanctuaryServer(options?: {
|
|
|
3381
3778
|
storage?: StorageBackend;
|
|
3382
3779
|
}): Promise<SanctuaryServer>;
|
|
3383
3780
|
|
|
3384
|
-
export { ATTESTATION_VERSION, ApprovalGate, type AttestationBody, type AttestationVerificationResult, AuditLog, AutoApproveChannel, BaselineTracker, type BridgeAttestationRequest, type BridgeAttestationResult, type BridgeCommitment, type BridgeVerificationResult, TEMPLATES as CONTEXT_GATE_TEMPLATES, CallbackApprovalChannel, ClientManager, CommitmentStore, type ConcordiaOutcome, type ConnectionState, type ContextAction, type ContextFilterResult, ContextGateEnforcer, type ContextGatePolicy, ContextGatePolicyStore, type ContextGateRule, type ContextGateTemplate, DashboardApprovalChannel, type DashboardConfig, type DetectionResult, type EnforcerConfig, type FederationCapabilities, type FederationPeer, FederationRegistry, type FieldClassification, type FieldFilterResult, FilesystemStorage, type GateResult, type HandshakeChallenge, type HandshakeCompletion, type HandshakeResponse, type HandshakeResult, InMemoryModelProvenanceStore, InjectionDetector, type InjectionDetectorConfig, type InjectionSignal, MODEL_PRESETS, MemoryStorage, type ModelProvenance, type ModelProvenanceStore, type PedersenCommitment, type PeerTrustEvaluation, type PolicyRecommendation, PolicyStore, type PrincipalPolicy, type ProviderCategory, ProxyRouter, type ProxyRouterOptions, ReputationStore, type SHRBody, type SHRGeneratorOptions, type SHRVerificationResult, type SanctuaryConfig, type SanctuaryServer, type SignedAttestation, type SignedSHR, type SovereigntyProfile, SovereigntyProfileStore, type SovereigntyProfileUpdate, type SovereigntyTier, StateStore, StderrApprovalChannel, TIER_WEIGHTS, type TierMetadata, type TieredAttestation, type UpstreamConnection, type UpstreamServer, type UpstreamTool, WebhookApprovalChannel, type WebhookCallbackPayload, type WebhookConfig, type WebhookPayload, type ZKProofOfKnowledge, type ZKRangeProof, canonicalize, classifyField, completeHandshake, computeWeightedScore, createBridgeCommitment, createDefaultProfile, createPedersenCommitment, createProofOfKnowledge, createRangeProof, createSanctuaryServer, evaluateField, filterContext, generateAttestation, generateSHR, generateSystemPrompt, getTemplate, initiateHandshake, listTemplateIds, loadConfig, loadPrincipalPolicy, recommendPolicy, resolveTier, respondToHandshake, signPayload, tierDistribution, verifyAttestation, verifyBridgeCommitment, verifyCompletion, verifyPedersenCommitment, verifyProofOfKnowledge, verifyRangeProof, verifySHR, verifySignature };
|
|
3781
|
+
export { ATTESTATION_VERSION, type ActivityEntry, type AggregatorSources, ApprovalGate, type ApprovalHandlers, type AttestationBody, type AttestationVerificationResult, AuditLog, AutoApproveChannel, BaselineTracker, type BridgeAttestationRequest, type BridgeAttestationResult, type BridgeCommitment, type BridgeVerificationResult, TEMPLATES as CONTEXT_GATE_TEMPLATES, CallbackApprovalChannel, ClientManager, CommitmentStore, type ConcordiaOutcome, type ConnectionState, type ContextAction, type ContextFilterResult, ContextGateEnforcer, type ContextGatePolicy, ContextGatePolicyStore, type ContextGateRule, type ContextGateTemplate, DashboardApprovalChannel, type DashboardConfig, type DashboardHandle, type DashboardServerOptions, type DetectionResult, type EnforcerConfig, type FederationCapabilities, type FederationPeer, FederationRegistry, type FieldClassification, type FieldFilterResult, FilesystemStorage, type GateResult, HERO_COPY, type HandshakeChallenge, type HandshakeCompletion, type HandshakeResponse, type HandshakeResult, InMemoryModelProvenanceStore, InjectionDetector, type InjectionDetectorConfig, type InjectionSignal, type L1Status, type L2Status, type L3Status, type L4Status, MODEL_PRESETS, MemoryStorage, type ModelProvenance, type ModelProvenanceStore, type PedersenCommitment, type PeerTrustEvaluation, type PendingApproval, type PolicyRecommendation, PolicyStore, type PrincipalPolicy, type ProtectionSnapshot, type ProviderCategory, ProxyRouter, type ProxyRouterOptions, type ReputationLookup, ReputationStore, type SHRBody, type SHRGeneratorOptions, type SHRVerificationResult, type SanctuaryConfig, type SanctuaryServer, type SignedAttestation, type SignedSHR, type SovereigntyProfile, SovereigntyProfileStore, type SovereigntyProfileUpdate, type SovereigntyTier, type StartDashboardOptions, StateStore, StderrApprovalChannel, type StreamEvent, TIER_WEIGHTS, type TierMetadata, type TieredAttestation, type UpstreamConnection, type UpstreamServer, type UpstreamTool, WebhookApprovalChannel, type WebhookCallbackPayload, type WebhookConfig, type WebhookPayload, type ZKProofOfKnowledge, type ZKRangeProof, canonicalize, classifyField, completeHandshake, computeWeightedScore, createBridgeCommitment, createDefaultProfile, createPedersenCommitment, createProofOfKnowledge, createRangeProof, createSanctuaryServer, evaluateField, filterContext, generateAttestation, generateSHR, generateSystemPrompt, getProtectionSnapshot, getTemplate, initiateHandshake, listTemplateIds, loadConfig, loadPrincipalPolicy, recommendPolicy, renderDashboardHTML, resolveTier, respondToHandshake, signPayload, startDashboard, startDashboardServer, tierDistribution, verifyAttestation, verifyBridgeCommitment, verifyCompletion, verifyPedersenCommitment, verifyProofOfKnowledge, verifyRangeProof, verifySHR, verifySignature };
|