@sanctuary-framework/mcp-server 0.5.6 → 0.5.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.cjs CHANGED
@@ -9,6 +9,7 @@ var crypto = require('crypto');
9
9
  var aes_js = require('@noble/ciphers/aes.js');
10
10
  var sha256 = require('@noble/hashes/sha256');
11
11
  var hmac = require('@noble/hashes/hmac');
12
+ var ed25519 = require('@noble/curves/ed25519');
12
13
  var hashWasm = require('hash-wasm');
13
14
  var hkdf = require('@noble/hashes/hkdf');
14
15
  var http = require('http');
@@ -16,7 +17,6 @@ var https = require('https');
16
17
  var fs = require('fs');
17
18
  var child_process = require('child_process');
18
19
  var stdio_js = require('@modelcontextprotocol/sdk/server/stdio.js');
19
- var ed25519 = require('@noble/curves/ed25519');
20
20
  var index_js = require('@modelcontextprotocol/sdk/server/index.js');
21
21
  var types_js = require('@modelcontextprotocol/sdk/types.js');
22
22
 
@@ -560,6 +560,111 @@ var init_hashing = __esm({
560
560
  init_encoding();
561
561
  }
562
562
  });
563
+ function generateKeypair() {
564
+ const privateKey = randomBytes(32);
565
+ const publicKey = ed25519.ed25519.getPublicKey(privateKey);
566
+ return { publicKey, privateKey };
567
+ }
568
+ function publicKeyToDid(publicKey) {
569
+ const multicodec = new Uint8Array([237, 1, ...publicKey]);
570
+ return `did:key:z${toBase64url(multicodec)}`;
571
+ }
572
+ function generateIdentityId(publicKey) {
573
+ const keyHash = hash(publicKey);
574
+ return Array.from(keyHash.slice(0, 16)).map((b) => b.toString(16).padStart(2, "0")).join("");
575
+ }
576
+ function createIdentity(label, encryptionKey, keyProtection) {
577
+ const { publicKey, privateKey } = generateKeypair();
578
+ const identityId = generateIdentityId(publicKey);
579
+ const did = publicKeyToDid(publicKey);
580
+ const now = (/* @__PURE__ */ new Date()).toISOString();
581
+ const encryptedPrivateKey = encrypt(privateKey, encryptionKey);
582
+ privateKey.fill(0);
583
+ const publicIdentity = {
584
+ identity_id: identityId,
585
+ label,
586
+ public_key: toBase64url(publicKey),
587
+ did,
588
+ created_at: now,
589
+ key_type: "ed25519",
590
+ key_protection: keyProtection
591
+ };
592
+ const storedIdentity = {
593
+ ...publicIdentity,
594
+ encrypted_private_key: encryptedPrivateKey,
595
+ rotation_history: []
596
+ };
597
+ return { publicIdentity, storedIdentity };
598
+ }
599
+ function sign(payload, encryptedPrivateKey, encryptionKey) {
600
+ const privateKey = decrypt(encryptedPrivateKey, encryptionKey);
601
+ try {
602
+ return ed25519.ed25519.sign(payload, privateKey);
603
+ } finally {
604
+ privateKey.fill(0);
605
+ }
606
+ }
607
+ function verify(payload, signature, publicKey) {
608
+ try {
609
+ return ed25519.ed25519.verify(signature, payload, publicKey);
610
+ } catch {
611
+ return false;
612
+ }
613
+ }
614
+ function rotateKeys(storedIdentity, encryptionKey, reason) {
615
+ const { publicKey: newPublicKey, privateKey: newPrivateKey } = generateKeypair();
616
+ const newIdentityDid = publicKeyToDid(newPublicKey);
617
+ const now = (/* @__PURE__ */ new Date()).toISOString();
618
+ const eventData = JSON.stringify({
619
+ old_public_key: storedIdentity.public_key,
620
+ new_public_key: toBase64url(newPublicKey),
621
+ identity_id: storedIdentity.identity_id,
622
+ reason,
623
+ rotated_at: now
624
+ });
625
+ const eventBytes = new TextEncoder().encode(eventData);
626
+ const signature = sign(
627
+ eventBytes,
628
+ storedIdentity.encrypted_private_key,
629
+ encryptionKey
630
+ );
631
+ const rotationEvent = {
632
+ old_public_key: storedIdentity.public_key,
633
+ new_public_key: toBase64url(newPublicKey),
634
+ identity_id: storedIdentity.identity_id,
635
+ reason,
636
+ rotated_at: now,
637
+ signature: toBase64url(signature)
638
+ };
639
+ const encryptedNewPrivateKey = encrypt(newPrivateKey, encryptionKey);
640
+ newPrivateKey.fill(0);
641
+ const updatedIdentity = {
642
+ ...storedIdentity,
643
+ public_key: toBase64url(newPublicKey),
644
+ did: newIdentityDid,
645
+ encrypted_private_key: encryptedNewPrivateKey,
646
+ rotation_history: [
647
+ ...storedIdentity.rotation_history,
648
+ {
649
+ old_public_key: storedIdentity.public_key,
650
+ new_public_key: toBase64url(newPublicKey),
651
+ rotation_event: toBase64url(
652
+ new TextEncoder().encode(JSON.stringify(rotationEvent))
653
+ ),
654
+ rotated_at: now
655
+ }
656
+ ]
657
+ };
658
+ return { updatedIdentity, rotationEvent };
659
+ }
660
+ var init_identity = __esm({
661
+ "src/core/identity.ts"() {
662
+ init_encoding();
663
+ init_encryption();
664
+ init_hashing();
665
+ init_random();
666
+ }
667
+ });
563
668
  async function deriveMasterKey(passphrase, existingParams) {
564
669
  const salt = existingParams ? fromBase64url(existingParams.salt) : generateSalt();
565
670
  const params = existingParams ?? {
@@ -1164,6 +1269,120 @@ var init_baseline = __esm({
1164
1269
  }
1165
1270
  });
1166
1271
 
1272
+ // src/shr/types.ts
1273
+ function deepSortKeys(obj) {
1274
+ if (obj === null || typeof obj !== "object") return obj;
1275
+ if (Array.isArray(obj)) return obj.map(deepSortKeys);
1276
+ const sorted = {};
1277
+ for (const key of Object.keys(obj).sort()) {
1278
+ sorted[key] = deepSortKeys(obj[key]);
1279
+ }
1280
+ return sorted;
1281
+ }
1282
+ function canonicalizeForSigning(body) {
1283
+ return JSON.stringify(deepSortKeys(body));
1284
+ }
1285
+ var init_types = __esm({
1286
+ "src/shr/types.ts"() {
1287
+ }
1288
+ });
1289
+
1290
+ // src/shr/generator.ts
1291
+ function generateSHR(identityId, opts) {
1292
+ const { config, identityManager, masterKey, validityMs } = opts;
1293
+ const identity = identityId ? identityManager.get(identityId) : identityManager.getDefault();
1294
+ if (!identity) {
1295
+ return "No identity available for signing. Create an identity first.";
1296
+ }
1297
+ const now = /* @__PURE__ */ new Date();
1298
+ const expiresAt = new Date(now.getTime() + (validityMs ?? DEFAULT_VALIDITY_MS));
1299
+ const degradations = [];
1300
+ if (config.execution.environment === "local-process") {
1301
+ degradations.push({
1302
+ layer: "l2",
1303
+ code: "PROCESS_ISOLATION_ONLY",
1304
+ severity: "warning",
1305
+ description: "Process-level isolation only (no TEE)",
1306
+ mitigation: "TEE support planned for a future release"
1307
+ });
1308
+ degradations.push({
1309
+ layer: "l2",
1310
+ code: "SELF_REPORTED_ATTESTATION",
1311
+ severity: "warning",
1312
+ description: "Attestation is self-reported (no hardware root of trust)",
1313
+ mitigation: "TEE attestation planned for a future release"
1314
+ });
1315
+ }
1316
+ const body = {
1317
+ shr_version: "1.0",
1318
+ implementation: {
1319
+ sanctuary_version: config.version,
1320
+ node_version: process.versions.node,
1321
+ generated_by: "sanctuary-mcp-server"
1322
+ },
1323
+ instance_id: identity.identity_id,
1324
+ generated_at: now.toISOString(),
1325
+ expires_at: expiresAt.toISOString(),
1326
+ layers: {
1327
+ l1: {
1328
+ status: "active",
1329
+ encryption: config.state.encryption,
1330
+ key_custody: "self",
1331
+ integrity: config.state.integrity,
1332
+ identity_type: config.state.identity_provider,
1333
+ state_portable: true
1334
+ },
1335
+ l2: {
1336
+ status: config.execution.environment === "local-process" ? "degraded" : "active",
1337
+ isolation_type: config.execution.environment,
1338
+ attestation_available: config.execution.attestation
1339
+ },
1340
+ l3: {
1341
+ status: "active",
1342
+ proof_system: config.disclosure.proof_system,
1343
+ selective_disclosure: true
1344
+ },
1345
+ l4: {
1346
+ status: "active",
1347
+ reputation_mode: config.reputation.mode,
1348
+ attestation_format: config.reputation.attestation_format,
1349
+ reputation_portable: true
1350
+ }
1351
+ },
1352
+ capabilities: {
1353
+ handshake: true,
1354
+ shr_exchange: true,
1355
+ reputation_verify: true,
1356
+ encrypted_channel: false
1357
+ // Not yet implemented
1358
+ },
1359
+ degradations
1360
+ };
1361
+ const canonical = canonicalizeForSigning(body);
1362
+ const payload = stringToBytes(canonical);
1363
+ const encryptionKey = derivePurposeKey(masterKey, "identity-encryption");
1364
+ const signatureBytes = sign(
1365
+ payload,
1366
+ identity.encrypted_private_key,
1367
+ encryptionKey
1368
+ );
1369
+ return {
1370
+ body,
1371
+ signed_by: identity.public_key,
1372
+ signature: toBase64url(signatureBytes)
1373
+ };
1374
+ }
1375
+ var DEFAULT_VALIDITY_MS;
1376
+ var init_generator = __esm({
1377
+ "src/shr/generator.ts"() {
1378
+ init_types();
1379
+ init_identity();
1380
+ init_encoding();
1381
+ init_key_derivation();
1382
+ DEFAULT_VALIDITY_MS = 60 * 60 * 1e3;
1383
+ }
1384
+ });
1385
+
1167
1386
  // src/principal-policy/dashboard-html.ts
1168
1387
  function generateLoginHTML(options) {
1169
1388
  return `<!DOCTYPE html>
@@ -1171,7 +1390,7 @@ function generateLoginHTML(options) {
1171
1390
  <head>
1172
1391
  <meta charset="UTF-8">
1173
1392
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
1174
- <title>Sanctuary Dashboard</title>
1393
+ <title>Sanctuary \u2014 Principal Dashboard</title>
1175
1394
  <style>
1176
1395
  :root {
1177
1396
  --bg: #0d1117;
@@ -1342,7 +1561,7 @@ function generateLoginHTML(options) {
1342
1561
 
1343
1562
  <form id="login-form">
1344
1563
  <div class="form-group">
1345
- <label for="auth-token">Bearer Token</label>
1564
+ <label for="auth-token">Auth Token</label>
1346
1565
  <input
1347
1566
  type="text"
1348
1567
  id="auth-token"
@@ -1427,7 +1646,7 @@ function generateDashboardHTML(options) {
1427
1646
  <head>
1428
1647
  <meta charset="UTF-8">
1429
1648
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
1430
- <title>Sanctuary Dashboard</title>
1649
+ <title>Sanctuary \u2014 Principal Dashboard</title>
1431
1650
  <style>
1432
1651
  :root {
1433
1652
  --bg: #0d1117;
@@ -3078,6 +3297,7 @@ var SESSION_TTL_REMOTE_MS, SESSION_TTL_LOCAL_MS, MAX_SESSIONS, RATE_LIMIT_WINDOW
3078
3297
  var init_dashboard = __esm({
3079
3298
  "src/principal-policy/dashboard.ts"() {
3080
3299
  init_config();
3300
+ init_generator();
3081
3301
  init_dashboard_html();
3082
3302
  SESSION_TTL_REMOTE_MS = 5 * 60 * 1e3;
3083
3303
  SESSION_TTL_LOCAL_MS = 24 * 60 * 60 * 1e3;
@@ -3094,6 +3314,10 @@ var init_dashboard = __esm({
3094
3314
  policy = null;
3095
3315
  baseline = null;
3096
3316
  auditLog = null;
3317
+ identityManager = null;
3318
+ handshakeResults = null;
3319
+ shrOpts = null;
3320
+ _sanctuaryConfig = null;
3097
3321
  dashboardHTML;
3098
3322
  loginHTML;
3099
3323
  authToken;
@@ -3127,6 +3351,10 @@ var init_dashboard = __esm({
3127
3351
  this.policy = deps.policy;
3128
3352
  this.baseline = deps.baseline;
3129
3353
  this.auditLog = deps.auditLog;
3354
+ if (deps.identityManager) this.identityManager = deps.identityManager;
3355
+ if (deps.handshakeResults) this.handshakeResults = deps.handshakeResults;
3356
+ if (deps.shrOpts) this.shrOpts = deps.shrOpts;
3357
+ if (deps.sanctuaryConfig) this._sanctuaryConfig = deps.sanctuaryConfig;
3130
3358
  }
3131
3359
  /**
3132
3360
  * Start the HTTP(S) server for the dashboard.
@@ -3459,6 +3687,14 @@ var init_dashboard = __esm({
3459
3687
  this.handlePendingList(res);
3460
3688
  } else if (method === "GET" && url.pathname === "/api/audit-log") {
3461
3689
  this.handleAuditLog(url, res);
3690
+ } else if (method === "GET" && url.pathname === "/api/sovereignty") {
3691
+ this.handleSovereignty(res);
3692
+ } else if (method === "GET" && url.pathname === "/api/identity") {
3693
+ this.handleIdentity(res);
3694
+ } else if (method === "GET" && url.pathname === "/api/handshakes") {
3695
+ this.handleHandshakes(res);
3696
+ } else if (method === "GET" && url.pathname === "/api/shr") {
3697
+ this.handleSHR(res);
3462
3698
  } else if (method === "POST" && url.pathname.startsWith("/api/approve/")) {
3463
3699
  if (!this.checkRateLimit(req, res, "decisions")) return;
3464
3700
  const id = url.pathname.slice("/api/approve/".length);
@@ -3648,6 +3884,107 @@ data: ${JSON.stringify(initData)}
3648
3884
  res.writeHead(200, { "Content-Type": "application/json" });
3649
3885
  res.end(JSON.stringify({ success: true, decision }));
3650
3886
  }
3887
+ // ── Sovereignty Data Routes ─────────────────────────────────────────
3888
+ handleSovereignty(res) {
3889
+ if (!this.shrOpts) {
3890
+ res.writeHead(200, { "Content-Type": "application/json" });
3891
+ res.end(JSON.stringify({ error: "SHR generator not available" }));
3892
+ return;
3893
+ }
3894
+ const shr = generateSHR(void 0, this.shrOpts);
3895
+ if (typeof shr === "string") {
3896
+ res.writeHead(200, { "Content-Type": "application/json" });
3897
+ res.end(JSON.stringify({ error: shr }));
3898
+ return;
3899
+ }
3900
+ const layers = shr.body.layers;
3901
+ let score = 0;
3902
+ for (const layer of [layers.l1, layers.l2, layers.l3, layers.l4]) {
3903
+ if (layer.status === "active") score += 25;
3904
+ else if (layer.status === "degraded") score += 15;
3905
+ }
3906
+ const overallLevel = score === 100 ? "full" : score >= 65 ? "degraded" : score >= 25 ? "minimal" : "unverified";
3907
+ res.writeHead(200, { "Content-Type": "application/json" });
3908
+ res.end(JSON.stringify({
3909
+ score,
3910
+ overall_level: overallLevel,
3911
+ layers: {
3912
+ l1: { status: layers.l1.status, detail: layers.l1.encryption, key_custody: layers.l1.key_custody },
3913
+ l2: { status: layers.l2.status, detail: layers.l2.isolation_type, attestation: layers.l2.attestation_available },
3914
+ l3: { status: layers.l3.status, detail: layers.l3.proof_system, selective_disclosure: layers.l3.selective_disclosure },
3915
+ l4: { status: layers.l4.status, detail: layers.l4.attestation_format, reputation_portable: layers.l4.reputation_portable }
3916
+ },
3917
+ degradations: shr.body.degradations,
3918
+ capabilities: shr.body.capabilities,
3919
+ config_loaded: this._sanctuaryConfig != null
3920
+ }));
3921
+ }
3922
+ handleIdentity(res) {
3923
+ if (!this.identityManager) {
3924
+ res.writeHead(200, { "Content-Type": "application/json" });
3925
+ res.end(JSON.stringify({ identities: [], count: 0 }));
3926
+ return;
3927
+ }
3928
+ const identities = this.identityManager.list().map((id) => ({
3929
+ identity_id: id.identity_id,
3930
+ label: id.label,
3931
+ public_key: id.public_key,
3932
+ did: id.did,
3933
+ created_at: id.created_at,
3934
+ key_type: id.key_type,
3935
+ key_protection: id.key_protection,
3936
+ rotation_count: id.rotation_history?.length ?? 0
3937
+ }));
3938
+ const primary = this.identityManager.getDefault();
3939
+ res.writeHead(200, { "Content-Type": "application/json" });
3940
+ res.end(JSON.stringify({
3941
+ identities,
3942
+ count: identities.length,
3943
+ primary_id: primary?.identity_id ?? null
3944
+ }));
3945
+ }
3946
+ handleHandshakes(res) {
3947
+ if (!this.handshakeResults) {
3948
+ res.writeHead(200, { "Content-Type": "application/json" });
3949
+ res.end(JSON.stringify({ handshakes: [], count: 0 }));
3950
+ return;
3951
+ }
3952
+ const handshakes = Array.from(this.handshakeResults.values()).map((h) => ({
3953
+ counterparty_id: h.counterparty_id,
3954
+ verified: h.verified,
3955
+ sovereignty_level: h.sovereignty_level,
3956
+ trust_tier: h.trust_tier,
3957
+ completed_at: h.completed_at,
3958
+ expires_at: h.expires_at,
3959
+ errors: h.errors
3960
+ }));
3961
+ handshakes.sort((a, b) => new Date(b.completed_at).getTime() - new Date(a.completed_at).getTime());
3962
+ res.writeHead(200, { "Content-Type": "application/json" });
3963
+ res.end(JSON.stringify({
3964
+ handshakes,
3965
+ count: handshakes.length,
3966
+ tier_distribution: {
3967
+ verified_sovereign: handshakes.filter((h) => h.trust_tier === "verified-sovereign").length,
3968
+ verified_degraded: handshakes.filter((h) => h.trust_tier === "verified-degraded").length,
3969
+ unverified: handshakes.filter((h) => h.trust_tier === "unverified").length
3970
+ }
3971
+ }));
3972
+ }
3973
+ handleSHR(res) {
3974
+ if (!this.shrOpts) {
3975
+ res.writeHead(200, { "Content-Type": "application/json" });
3976
+ res.end(JSON.stringify({ error: "SHR generator not available" }));
3977
+ return;
3978
+ }
3979
+ const shr = generateSHR(void 0, this.shrOpts);
3980
+ if (typeof shr === "string") {
3981
+ res.writeHead(200, { "Content-Type": "application/json" });
3982
+ res.end(JSON.stringify({ error: shr }));
3983
+ return;
3984
+ }
3985
+ res.writeHead(200, { "Content-Type": "application/json" });
3986
+ res.end(JSON.stringify(shr));
3987
+ }
3651
3988
  // ── SSE Broadcasting ────────────────────────────────────────────────
3652
3989
  broadcastSSE(event, data) {
3653
3990
  const message = `event: ${event}
@@ -3889,111 +4226,7 @@ init_filesystem();
3889
4226
  // src/l1-cognitive/state-store.ts
3890
4227
  init_encryption();
3891
4228
  init_hashing();
3892
-
3893
- // src/core/identity.ts
3894
- init_encoding();
3895
- init_encryption();
3896
- init_hashing();
3897
- init_random();
3898
- function generateKeypair() {
3899
- const privateKey = randomBytes(32);
3900
- const publicKey = ed25519.ed25519.getPublicKey(privateKey);
3901
- return { publicKey, privateKey };
3902
- }
3903
- function publicKeyToDid(publicKey) {
3904
- const multicodec = new Uint8Array([237, 1, ...publicKey]);
3905
- return `did:key:z${toBase64url(multicodec)}`;
3906
- }
3907
- function generateIdentityId(publicKey) {
3908
- const keyHash = hash(publicKey);
3909
- return Array.from(keyHash.slice(0, 16)).map((b) => b.toString(16).padStart(2, "0")).join("");
3910
- }
3911
- function createIdentity(label, encryptionKey, keyProtection) {
3912
- const { publicKey, privateKey } = generateKeypair();
3913
- const identityId = generateIdentityId(publicKey);
3914
- const did = publicKeyToDid(publicKey);
3915
- const now = (/* @__PURE__ */ new Date()).toISOString();
3916
- const encryptedPrivateKey = encrypt(privateKey, encryptionKey);
3917
- privateKey.fill(0);
3918
- const publicIdentity = {
3919
- identity_id: identityId,
3920
- label,
3921
- public_key: toBase64url(publicKey),
3922
- did,
3923
- created_at: now,
3924
- key_type: "ed25519",
3925
- key_protection: keyProtection
3926
- };
3927
- const storedIdentity = {
3928
- ...publicIdentity,
3929
- encrypted_private_key: encryptedPrivateKey,
3930
- rotation_history: []
3931
- };
3932
- return { publicIdentity, storedIdentity };
3933
- }
3934
- function sign(payload, encryptedPrivateKey, encryptionKey) {
3935
- const privateKey = decrypt(encryptedPrivateKey, encryptionKey);
3936
- try {
3937
- return ed25519.ed25519.sign(payload, privateKey);
3938
- } finally {
3939
- privateKey.fill(0);
3940
- }
3941
- }
3942
- function verify(payload, signature, publicKey) {
3943
- try {
3944
- return ed25519.ed25519.verify(signature, payload, publicKey);
3945
- } catch {
3946
- return false;
3947
- }
3948
- }
3949
- function rotateKeys(storedIdentity, encryptionKey, reason) {
3950
- const { publicKey: newPublicKey, privateKey: newPrivateKey } = generateKeypair();
3951
- const newIdentityDid = publicKeyToDid(newPublicKey);
3952
- const now = (/* @__PURE__ */ new Date()).toISOString();
3953
- const eventData = JSON.stringify({
3954
- old_public_key: storedIdentity.public_key,
3955
- new_public_key: toBase64url(newPublicKey),
3956
- identity_id: storedIdentity.identity_id,
3957
- reason,
3958
- rotated_at: now
3959
- });
3960
- const eventBytes = new TextEncoder().encode(eventData);
3961
- const signature = sign(
3962
- eventBytes,
3963
- storedIdentity.encrypted_private_key,
3964
- encryptionKey
3965
- );
3966
- const rotationEvent = {
3967
- old_public_key: storedIdentity.public_key,
3968
- new_public_key: toBase64url(newPublicKey),
3969
- identity_id: storedIdentity.identity_id,
3970
- reason,
3971
- rotated_at: now,
3972
- signature: toBase64url(signature)
3973
- };
3974
- const encryptedNewPrivateKey = encrypt(newPrivateKey, encryptionKey);
3975
- newPrivateKey.fill(0);
3976
- const updatedIdentity = {
3977
- ...storedIdentity,
3978
- public_key: toBase64url(newPublicKey),
3979
- did: newIdentityDid,
3980
- encrypted_private_key: encryptedNewPrivateKey,
3981
- rotation_history: [
3982
- ...storedIdentity.rotation_history,
3983
- {
3984
- old_public_key: storedIdentity.public_key,
3985
- new_public_key: toBase64url(newPublicKey),
3986
- rotation_event: toBase64url(
3987
- new TextEncoder().encode(JSON.stringify(rotationEvent))
3988
- ),
3989
- rotated_at: now
3990
- }
3991
- ]
3992
- };
3993
- return { updatedIdentity, rotationEvent };
3994
- }
3995
-
3996
- // src/l1-cognitive/state-store.ts
4229
+ init_identity();
3997
4230
  init_key_derivation();
3998
4231
  init_encoding();
3999
4232
  var RESERVED_NAMESPACE_PREFIXES = [
@@ -4533,6 +4766,7 @@ function toolResult(data) {
4533
4766
  }
4534
4767
 
4535
4768
  // src/l1-cognitive/tools.ts
4769
+ init_identity();
4536
4770
  init_key_derivation();
4537
4771
  init_encoding();
4538
4772
  init_encryption();
@@ -5942,6 +6176,7 @@ init_encryption();
5942
6176
  init_key_derivation();
5943
6177
  init_encoding();
5944
6178
  init_random();
6179
+ init_identity();
5945
6180
  function computeMedian(values) {
5946
6181
  if (values.length === 0) return 0;
5947
6182
  const sorted = [...values].sort((a, b) => a - b);
@@ -7914,110 +8149,12 @@ function createPrincipalPolicyTools(policy, baseline, auditLog) {
7914
8149
  ];
7915
8150
  }
7916
8151
 
7917
- // src/shr/types.ts
7918
- function deepSortKeys(obj) {
7919
- if (obj === null || typeof obj !== "object") return obj;
7920
- if (Array.isArray(obj)) return obj.map(deepSortKeys);
7921
- const sorted = {};
7922
- for (const key of Object.keys(obj).sort()) {
7923
- sorted[key] = deepSortKeys(obj[key]);
7924
- }
7925
- return sorted;
7926
- }
7927
- function canonicalizeForSigning(body) {
7928
- return JSON.stringify(deepSortKeys(body));
7929
- }
7930
-
7931
- // src/shr/generator.ts
7932
- init_encoding();
7933
- init_key_derivation();
7934
- var DEFAULT_VALIDITY_MS = 60 * 60 * 1e3;
7935
- function generateSHR(identityId, opts) {
7936
- const { config, identityManager, masterKey, validityMs } = opts;
7937
- const identity = identityId ? identityManager.get(identityId) : identityManager.getDefault();
7938
- if (!identity) {
7939
- return "No identity available for signing. Create an identity first.";
7940
- }
7941
- const now = /* @__PURE__ */ new Date();
7942
- const expiresAt = new Date(now.getTime() + (validityMs ?? DEFAULT_VALIDITY_MS));
7943
- const degradations = [];
7944
- if (config.execution.environment === "local-process") {
7945
- degradations.push({
7946
- layer: "l2",
7947
- code: "PROCESS_ISOLATION_ONLY",
7948
- severity: "warning",
7949
- description: "Process-level isolation only (no TEE)",
7950
- mitigation: "TEE support planned for a future release"
7951
- });
7952
- degradations.push({
7953
- layer: "l2",
7954
- code: "SELF_REPORTED_ATTESTATION",
7955
- severity: "warning",
7956
- description: "Attestation is self-reported (no hardware root of trust)",
7957
- mitigation: "TEE attestation planned for a future release"
7958
- });
7959
- }
7960
- const body = {
7961
- shr_version: "1.0",
7962
- implementation: {
7963
- sanctuary_version: config.version,
7964
- node_version: process.versions.node,
7965
- generated_by: "sanctuary-mcp-server"
7966
- },
7967
- instance_id: identity.identity_id,
7968
- generated_at: now.toISOString(),
7969
- expires_at: expiresAt.toISOString(),
7970
- layers: {
7971
- l1: {
7972
- status: "active",
7973
- encryption: config.state.encryption,
7974
- key_custody: "self",
7975
- integrity: config.state.integrity,
7976
- identity_type: config.state.identity_provider,
7977
- state_portable: true
7978
- },
7979
- l2: {
7980
- status: config.execution.environment === "local-process" ? "degraded" : "active",
7981
- isolation_type: config.execution.environment,
7982
- attestation_available: config.execution.attestation
7983
- },
7984
- l3: {
7985
- status: "active",
7986
- proof_system: config.disclosure.proof_system,
7987
- selective_disclosure: true
7988
- },
7989
- l4: {
7990
- status: "active",
7991
- reputation_mode: config.reputation.mode,
7992
- attestation_format: config.reputation.attestation_format,
7993
- reputation_portable: true
7994
- }
7995
- },
7996
- capabilities: {
7997
- handshake: true,
7998
- shr_exchange: true,
7999
- reputation_verify: true,
8000
- encrypted_channel: false
8001
- // Not yet implemented
8002
- },
8003
- degradations
8004
- };
8005
- const canonical = canonicalizeForSigning(body);
8006
- const payload = stringToBytes(canonical);
8007
- const encryptionKey = derivePurposeKey(masterKey, "identity-encryption");
8008
- const signatureBytes = sign(
8009
- payload,
8010
- identity.encrypted_private_key,
8011
- encryptionKey
8012
- );
8013
- return {
8014
- body,
8015
- signed_by: identity.public_key,
8016
- signature: toBase64url(signatureBytes)
8017
- };
8018
- }
8152
+ // src/shr/tools.ts
8153
+ init_generator();
8019
8154
 
8020
8155
  // src/shr/verifier.ts
8156
+ init_types();
8157
+ init_identity();
8021
8158
  init_encoding();
8022
8159
  function verifySHR(shr, now) {
8023
8160
  const errors = [];
@@ -8439,7 +8576,11 @@ function createSHRTools(config, identityManager, masterKey, auditLog) {
8439
8576
  return { tools };
8440
8577
  }
8441
8578
 
8579
+ // src/handshake/tools.ts
8580
+ init_generator();
8581
+
8442
8582
  // src/handshake/protocol.ts
8583
+ init_identity();
8443
8584
  init_encoding();
8444
8585
  init_random();
8445
8586
  init_key_derivation();
@@ -8609,8 +8750,11 @@ function deriveTrustTier(level) {
8609
8750
  }
8610
8751
 
8611
8752
  // src/handshake/attestation.ts
8753
+ init_types();
8754
+ init_identity();
8612
8755
  init_encoding();
8613
8756
  init_key_derivation();
8757
+ init_identity();
8614
8758
  init_encoding();
8615
8759
  var ATTESTATION_VERSION = "1.0";
8616
8760
  function deriveTrustTier2(level) {
@@ -9408,6 +9552,7 @@ init_encryption();
9408
9552
  init_encoding();
9409
9553
 
9410
9554
  // src/bridge/bridge.ts
9555
+ init_identity();
9411
9556
  init_encoding();
9412
9557
  init_random();
9413
9558
  init_hashing();
@@ -12496,6 +12641,7 @@ init_filesystem();
12496
12641
  init_baseline();
12497
12642
  init_loader();
12498
12643
  init_dashboard();
12644
+ init_generator();
12499
12645
  async function createSanctuaryServer(options) {
12500
12646
  const config = await loadConfig(options?.configPath);
12501
12647
  await promises.mkdir(config.storage_path, { recursive: true, mode: 448 });
@@ -12849,7 +12995,15 @@ async function createSanctuaryServer(options) {
12849
12995
  tls: config.dashboard.tls,
12850
12996
  auto_open: config.dashboard.auto_open
12851
12997
  });
12852
- dashboard.setDependencies({ policy, baseline, auditLog });
12998
+ dashboard.setDependencies({
12999
+ policy,
13000
+ baseline,
13001
+ auditLog,
13002
+ identityManager,
13003
+ handshakeResults,
13004
+ shrOpts: { config, identityManager, masterKey },
13005
+ sanctuaryConfig: config
13006
+ });
12853
13007
  await dashboard.start();
12854
13008
  approvalChannel = dashboard;
12855
13009
  } else if (config.webhook.enabled && config.webhook.url && config.webhook.secret) {