@sanctuary-framework/mcp-server 0.5.6 → 0.5.8
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 +366 -212
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +366 -212
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +231 -106
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +60 -48
- package/dist/index.d.ts +60 -48
- package/dist/index.js +231 -106
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4064,6 +4064,108 @@ var AutoApproveChannel = class {
|
|
|
4064
4064
|
}
|
|
4065
4065
|
};
|
|
4066
4066
|
|
|
4067
|
+
// src/shr/types.ts
|
|
4068
|
+
function deepSortKeys(obj) {
|
|
4069
|
+
if (obj === null || typeof obj !== "object") return obj;
|
|
4070
|
+
if (Array.isArray(obj)) return obj.map(deepSortKeys);
|
|
4071
|
+
const sorted = {};
|
|
4072
|
+
for (const key of Object.keys(obj).sort()) {
|
|
4073
|
+
sorted[key] = deepSortKeys(obj[key]);
|
|
4074
|
+
}
|
|
4075
|
+
return sorted;
|
|
4076
|
+
}
|
|
4077
|
+
function canonicalizeForSigning(body) {
|
|
4078
|
+
return JSON.stringify(deepSortKeys(body));
|
|
4079
|
+
}
|
|
4080
|
+
|
|
4081
|
+
// src/shr/generator.ts
|
|
4082
|
+
init_encoding();
|
|
4083
|
+
var DEFAULT_VALIDITY_MS = 60 * 60 * 1e3;
|
|
4084
|
+
function generateSHR(identityId, opts) {
|
|
4085
|
+
const { config, identityManager, masterKey, validityMs } = opts;
|
|
4086
|
+
const identity = identityId ? identityManager.get(identityId) : identityManager.getDefault();
|
|
4087
|
+
if (!identity) {
|
|
4088
|
+
return "No identity available for signing. Create an identity first.";
|
|
4089
|
+
}
|
|
4090
|
+
const now = /* @__PURE__ */ new Date();
|
|
4091
|
+
const expiresAt = new Date(now.getTime() + (validityMs ?? DEFAULT_VALIDITY_MS));
|
|
4092
|
+
const degradations = [];
|
|
4093
|
+
if (config.execution.environment === "local-process") {
|
|
4094
|
+
degradations.push({
|
|
4095
|
+
layer: "l2",
|
|
4096
|
+
code: "PROCESS_ISOLATION_ONLY",
|
|
4097
|
+
severity: "warning",
|
|
4098
|
+
description: "Process-level isolation only (no TEE)",
|
|
4099
|
+
mitigation: "TEE support planned for a future release"
|
|
4100
|
+
});
|
|
4101
|
+
degradations.push({
|
|
4102
|
+
layer: "l2",
|
|
4103
|
+
code: "SELF_REPORTED_ATTESTATION",
|
|
4104
|
+
severity: "warning",
|
|
4105
|
+
description: "Attestation is self-reported (no hardware root of trust)",
|
|
4106
|
+
mitigation: "TEE attestation planned for a future release"
|
|
4107
|
+
});
|
|
4108
|
+
}
|
|
4109
|
+
const body = {
|
|
4110
|
+
shr_version: "1.0",
|
|
4111
|
+
implementation: {
|
|
4112
|
+
sanctuary_version: config.version,
|
|
4113
|
+
node_version: process.versions.node,
|
|
4114
|
+
generated_by: "sanctuary-mcp-server"
|
|
4115
|
+
},
|
|
4116
|
+
instance_id: identity.identity_id,
|
|
4117
|
+
generated_at: now.toISOString(),
|
|
4118
|
+
expires_at: expiresAt.toISOString(),
|
|
4119
|
+
layers: {
|
|
4120
|
+
l1: {
|
|
4121
|
+
status: "active",
|
|
4122
|
+
encryption: config.state.encryption,
|
|
4123
|
+
key_custody: "self",
|
|
4124
|
+
integrity: config.state.integrity,
|
|
4125
|
+
identity_type: config.state.identity_provider,
|
|
4126
|
+
state_portable: true
|
|
4127
|
+
},
|
|
4128
|
+
l2: {
|
|
4129
|
+
status: config.execution.environment === "local-process" ? "degraded" : "active",
|
|
4130
|
+
isolation_type: config.execution.environment,
|
|
4131
|
+
attestation_available: config.execution.attestation
|
|
4132
|
+
},
|
|
4133
|
+
l3: {
|
|
4134
|
+
status: "active",
|
|
4135
|
+
proof_system: config.disclosure.proof_system,
|
|
4136
|
+
selective_disclosure: true
|
|
4137
|
+
},
|
|
4138
|
+
l4: {
|
|
4139
|
+
status: "active",
|
|
4140
|
+
reputation_mode: config.reputation.mode,
|
|
4141
|
+
attestation_format: config.reputation.attestation_format,
|
|
4142
|
+
reputation_portable: true
|
|
4143
|
+
}
|
|
4144
|
+
},
|
|
4145
|
+
capabilities: {
|
|
4146
|
+
handshake: true,
|
|
4147
|
+
shr_exchange: true,
|
|
4148
|
+
reputation_verify: true,
|
|
4149
|
+
encrypted_channel: false
|
|
4150
|
+
// Not yet implemented
|
|
4151
|
+
},
|
|
4152
|
+
degradations
|
|
4153
|
+
};
|
|
4154
|
+
const canonical = canonicalizeForSigning(body);
|
|
4155
|
+
const payload = stringToBytes(canonical);
|
|
4156
|
+
const encryptionKey = derivePurposeKey(masterKey, "identity-encryption");
|
|
4157
|
+
const signatureBytes = sign(
|
|
4158
|
+
payload,
|
|
4159
|
+
identity.encrypted_private_key,
|
|
4160
|
+
encryptionKey
|
|
4161
|
+
);
|
|
4162
|
+
return {
|
|
4163
|
+
body,
|
|
4164
|
+
signed_by: identity.public_key,
|
|
4165
|
+
signature: toBase64url(signatureBytes)
|
|
4166
|
+
};
|
|
4167
|
+
}
|
|
4168
|
+
|
|
4067
4169
|
// src/principal-policy/dashboard-html.ts
|
|
4068
4170
|
function generateLoginHTML(options) {
|
|
4069
4171
|
return `<!DOCTYPE html>
|
|
@@ -4071,7 +4173,7 @@ function generateLoginHTML(options) {
|
|
|
4071
4173
|
<head>
|
|
4072
4174
|
<meta charset="UTF-8">
|
|
4073
4175
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
4074
|
-
<title>Sanctuary Dashboard</title>
|
|
4176
|
+
<title>Sanctuary \u2014 Principal Dashboard</title>
|
|
4075
4177
|
<style>
|
|
4076
4178
|
:root {
|
|
4077
4179
|
--bg: #0d1117;
|
|
@@ -4242,7 +4344,7 @@ function generateLoginHTML(options) {
|
|
|
4242
4344
|
|
|
4243
4345
|
<form id="login-form">
|
|
4244
4346
|
<div class="form-group">
|
|
4245
|
-
<label for="auth-token">
|
|
4347
|
+
<label for="auth-token">Auth Token</label>
|
|
4246
4348
|
<input
|
|
4247
4349
|
type="text"
|
|
4248
4350
|
id="auth-token"
|
|
@@ -4327,7 +4429,7 @@ function generateDashboardHTML(options) {
|
|
|
4327
4429
|
<head>
|
|
4328
4430
|
<meta charset="UTF-8">
|
|
4329
4431
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
4330
|
-
<title>Sanctuary Dashboard</title>
|
|
4432
|
+
<title>Sanctuary \u2014 Principal Dashboard</title>
|
|
4331
4433
|
<style>
|
|
4332
4434
|
:root {
|
|
4333
4435
|
--bg: #0d1117;
|
|
@@ -5987,6 +6089,10 @@ var DashboardApprovalChannel = class {
|
|
|
5987
6089
|
policy = null;
|
|
5988
6090
|
baseline = null;
|
|
5989
6091
|
auditLog = null;
|
|
6092
|
+
identityManager = null;
|
|
6093
|
+
handshakeResults = null;
|
|
6094
|
+
shrOpts = null;
|
|
6095
|
+
_sanctuaryConfig = null;
|
|
5990
6096
|
dashboardHTML;
|
|
5991
6097
|
loginHTML;
|
|
5992
6098
|
authToken;
|
|
@@ -6020,6 +6126,10 @@ var DashboardApprovalChannel = class {
|
|
|
6020
6126
|
this.policy = deps.policy;
|
|
6021
6127
|
this.baseline = deps.baseline;
|
|
6022
6128
|
this.auditLog = deps.auditLog;
|
|
6129
|
+
if (deps.identityManager) this.identityManager = deps.identityManager;
|
|
6130
|
+
if (deps.handshakeResults) this.handshakeResults = deps.handshakeResults;
|
|
6131
|
+
if (deps.shrOpts) this.shrOpts = deps.shrOpts;
|
|
6132
|
+
if (deps.sanctuaryConfig) this._sanctuaryConfig = deps.sanctuaryConfig;
|
|
6023
6133
|
}
|
|
6024
6134
|
/**
|
|
6025
6135
|
* Start the HTTP(S) server for the dashboard.
|
|
@@ -6352,6 +6462,14 @@ var DashboardApprovalChannel = class {
|
|
|
6352
6462
|
this.handlePendingList(res);
|
|
6353
6463
|
} else if (method === "GET" && url.pathname === "/api/audit-log") {
|
|
6354
6464
|
this.handleAuditLog(url, res);
|
|
6465
|
+
} else if (method === "GET" && url.pathname === "/api/sovereignty") {
|
|
6466
|
+
this.handleSovereignty(res);
|
|
6467
|
+
} else if (method === "GET" && url.pathname === "/api/identity") {
|
|
6468
|
+
this.handleIdentity(res);
|
|
6469
|
+
} else if (method === "GET" && url.pathname === "/api/handshakes") {
|
|
6470
|
+
this.handleHandshakes(res);
|
|
6471
|
+
} else if (method === "GET" && url.pathname === "/api/shr") {
|
|
6472
|
+
this.handleSHR(res);
|
|
6355
6473
|
} else if (method === "POST" && url.pathname.startsWith("/api/approve/")) {
|
|
6356
6474
|
if (!this.checkRateLimit(req, res, "decisions")) return;
|
|
6357
6475
|
const id = url.pathname.slice("/api/approve/".length);
|
|
@@ -6541,6 +6659,107 @@ data: ${JSON.stringify(initData)}
|
|
|
6541
6659
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
6542
6660
|
res.end(JSON.stringify({ success: true, decision }));
|
|
6543
6661
|
}
|
|
6662
|
+
// ── Sovereignty Data Routes ─────────────────────────────────────────
|
|
6663
|
+
handleSovereignty(res) {
|
|
6664
|
+
if (!this.shrOpts) {
|
|
6665
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
6666
|
+
res.end(JSON.stringify({ error: "SHR generator not available" }));
|
|
6667
|
+
return;
|
|
6668
|
+
}
|
|
6669
|
+
const shr = generateSHR(void 0, this.shrOpts);
|
|
6670
|
+
if (typeof shr === "string") {
|
|
6671
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
6672
|
+
res.end(JSON.stringify({ error: shr }));
|
|
6673
|
+
return;
|
|
6674
|
+
}
|
|
6675
|
+
const layers = shr.body.layers;
|
|
6676
|
+
let score = 0;
|
|
6677
|
+
for (const layer of [layers.l1, layers.l2, layers.l3, layers.l4]) {
|
|
6678
|
+
if (layer.status === "active") score += 25;
|
|
6679
|
+
else if (layer.status === "degraded") score += 15;
|
|
6680
|
+
}
|
|
6681
|
+
const overallLevel = score === 100 ? "full" : score >= 65 ? "degraded" : score >= 25 ? "minimal" : "unverified";
|
|
6682
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
6683
|
+
res.end(JSON.stringify({
|
|
6684
|
+
score,
|
|
6685
|
+
overall_level: overallLevel,
|
|
6686
|
+
layers: {
|
|
6687
|
+
l1: { status: layers.l1.status, detail: layers.l1.encryption, key_custody: layers.l1.key_custody },
|
|
6688
|
+
l2: { status: layers.l2.status, detail: layers.l2.isolation_type, attestation: layers.l2.attestation_available },
|
|
6689
|
+
l3: { status: layers.l3.status, detail: layers.l3.proof_system, selective_disclosure: layers.l3.selective_disclosure },
|
|
6690
|
+
l4: { status: layers.l4.status, detail: layers.l4.attestation_format, reputation_portable: layers.l4.reputation_portable }
|
|
6691
|
+
},
|
|
6692
|
+
degradations: shr.body.degradations,
|
|
6693
|
+
capabilities: shr.body.capabilities,
|
|
6694
|
+
config_loaded: this._sanctuaryConfig != null
|
|
6695
|
+
}));
|
|
6696
|
+
}
|
|
6697
|
+
handleIdentity(res) {
|
|
6698
|
+
if (!this.identityManager) {
|
|
6699
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
6700
|
+
res.end(JSON.stringify({ identities: [], count: 0 }));
|
|
6701
|
+
return;
|
|
6702
|
+
}
|
|
6703
|
+
const identities = this.identityManager.list().map((id) => ({
|
|
6704
|
+
identity_id: id.identity_id,
|
|
6705
|
+
label: id.label,
|
|
6706
|
+
public_key: id.public_key,
|
|
6707
|
+
did: id.did,
|
|
6708
|
+
created_at: id.created_at,
|
|
6709
|
+
key_type: id.key_type,
|
|
6710
|
+
key_protection: id.key_protection,
|
|
6711
|
+
rotation_count: id.rotation_history?.length ?? 0
|
|
6712
|
+
}));
|
|
6713
|
+
const primary = this.identityManager.getDefault();
|
|
6714
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
6715
|
+
res.end(JSON.stringify({
|
|
6716
|
+
identities,
|
|
6717
|
+
count: identities.length,
|
|
6718
|
+
primary_id: primary?.identity_id ?? null
|
|
6719
|
+
}));
|
|
6720
|
+
}
|
|
6721
|
+
handleHandshakes(res) {
|
|
6722
|
+
if (!this.handshakeResults) {
|
|
6723
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
6724
|
+
res.end(JSON.stringify({ handshakes: [], count: 0 }));
|
|
6725
|
+
return;
|
|
6726
|
+
}
|
|
6727
|
+
const handshakes = Array.from(this.handshakeResults.values()).map((h) => ({
|
|
6728
|
+
counterparty_id: h.counterparty_id,
|
|
6729
|
+
verified: h.verified,
|
|
6730
|
+
sovereignty_level: h.sovereignty_level,
|
|
6731
|
+
trust_tier: h.trust_tier,
|
|
6732
|
+
completed_at: h.completed_at,
|
|
6733
|
+
expires_at: h.expires_at,
|
|
6734
|
+
errors: h.errors
|
|
6735
|
+
}));
|
|
6736
|
+
handshakes.sort((a, b) => new Date(b.completed_at).getTime() - new Date(a.completed_at).getTime());
|
|
6737
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
6738
|
+
res.end(JSON.stringify({
|
|
6739
|
+
handshakes,
|
|
6740
|
+
count: handshakes.length,
|
|
6741
|
+
tier_distribution: {
|
|
6742
|
+
verified_sovereign: handshakes.filter((h) => h.trust_tier === "verified-sovereign").length,
|
|
6743
|
+
verified_degraded: handshakes.filter((h) => h.trust_tier === "verified-degraded").length,
|
|
6744
|
+
unverified: handshakes.filter((h) => h.trust_tier === "unverified").length
|
|
6745
|
+
}
|
|
6746
|
+
}));
|
|
6747
|
+
}
|
|
6748
|
+
handleSHR(res) {
|
|
6749
|
+
if (!this.shrOpts) {
|
|
6750
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
6751
|
+
res.end(JSON.stringify({ error: "SHR generator not available" }));
|
|
6752
|
+
return;
|
|
6753
|
+
}
|
|
6754
|
+
const shr = generateSHR(void 0, this.shrOpts);
|
|
6755
|
+
if (typeof shr === "string") {
|
|
6756
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
6757
|
+
res.end(JSON.stringify({ error: shr }));
|
|
6758
|
+
return;
|
|
6759
|
+
}
|
|
6760
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
6761
|
+
res.end(JSON.stringify(shr));
|
|
6762
|
+
}
|
|
6544
6763
|
// ── SSE Broadcasting ────────────────────────────────────────────────
|
|
6545
6764
|
broadcastSSE(event, data) {
|
|
6546
6765
|
const message = `event: ${event}
|
|
@@ -7707,108 +7926,6 @@ function createPrincipalPolicyTools(policy, baseline, auditLog) {
|
|
|
7707
7926
|
];
|
|
7708
7927
|
}
|
|
7709
7928
|
|
|
7710
|
-
// src/shr/types.ts
|
|
7711
|
-
function deepSortKeys(obj) {
|
|
7712
|
-
if (obj === null || typeof obj !== "object") return obj;
|
|
7713
|
-
if (Array.isArray(obj)) return obj.map(deepSortKeys);
|
|
7714
|
-
const sorted = {};
|
|
7715
|
-
for (const key of Object.keys(obj).sort()) {
|
|
7716
|
-
sorted[key] = deepSortKeys(obj[key]);
|
|
7717
|
-
}
|
|
7718
|
-
return sorted;
|
|
7719
|
-
}
|
|
7720
|
-
function canonicalizeForSigning(body) {
|
|
7721
|
-
return JSON.stringify(deepSortKeys(body));
|
|
7722
|
-
}
|
|
7723
|
-
|
|
7724
|
-
// src/shr/generator.ts
|
|
7725
|
-
init_encoding();
|
|
7726
|
-
var DEFAULT_VALIDITY_MS = 60 * 60 * 1e3;
|
|
7727
|
-
function generateSHR(identityId, opts) {
|
|
7728
|
-
const { config, identityManager, masterKey, validityMs } = opts;
|
|
7729
|
-
const identity = identityId ? identityManager.get(identityId) : identityManager.getDefault();
|
|
7730
|
-
if (!identity) {
|
|
7731
|
-
return "No identity available for signing. Create an identity first.";
|
|
7732
|
-
}
|
|
7733
|
-
const now = /* @__PURE__ */ new Date();
|
|
7734
|
-
const expiresAt = new Date(now.getTime() + (validityMs ?? DEFAULT_VALIDITY_MS));
|
|
7735
|
-
const degradations = [];
|
|
7736
|
-
if (config.execution.environment === "local-process") {
|
|
7737
|
-
degradations.push({
|
|
7738
|
-
layer: "l2",
|
|
7739
|
-
code: "PROCESS_ISOLATION_ONLY",
|
|
7740
|
-
severity: "warning",
|
|
7741
|
-
description: "Process-level isolation only (no TEE)",
|
|
7742
|
-
mitigation: "TEE support planned for a future release"
|
|
7743
|
-
});
|
|
7744
|
-
degradations.push({
|
|
7745
|
-
layer: "l2",
|
|
7746
|
-
code: "SELF_REPORTED_ATTESTATION",
|
|
7747
|
-
severity: "warning",
|
|
7748
|
-
description: "Attestation is self-reported (no hardware root of trust)",
|
|
7749
|
-
mitigation: "TEE attestation planned for a future release"
|
|
7750
|
-
});
|
|
7751
|
-
}
|
|
7752
|
-
const body = {
|
|
7753
|
-
shr_version: "1.0",
|
|
7754
|
-
implementation: {
|
|
7755
|
-
sanctuary_version: config.version,
|
|
7756
|
-
node_version: process.versions.node,
|
|
7757
|
-
generated_by: "sanctuary-mcp-server"
|
|
7758
|
-
},
|
|
7759
|
-
instance_id: identity.identity_id,
|
|
7760
|
-
generated_at: now.toISOString(),
|
|
7761
|
-
expires_at: expiresAt.toISOString(),
|
|
7762
|
-
layers: {
|
|
7763
|
-
l1: {
|
|
7764
|
-
status: "active",
|
|
7765
|
-
encryption: config.state.encryption,
|
|
7766
|
-
key_custody: "self",
|
|
7767
|
-
integrity: config.state.integrity,
|
|
7768
|
-
identity_type: config.state.identity_provider,
|
|
7769
|
-
state_portable: true
|
|
7770
|
-
},
|
|
7771
|
-
l2: {
|
|
7772
|
-
status: config.execution.environment === "local-process" ? "degraded" : "active",
|
|
7773
|
-
isolation_type: config.execution.environment,
|
|
7774
|
-
attestation_available: config.execution.attestation
|
|
7775
|
-
},
|
|
7776
|
-
l3: {
|
|
7777
|
-
status: "active",
|
|
7778
|
-
proof_system: config.disclosure.proof_system,
|
|
7779
|
-
selective_disclosure: true
|
|
7780
|
-
},
|
|
7781
|
-
l4: {
|
|
7782
|
-
status: "active",
|
|
7783
|
-
reputation_mode: config.reputation.mode,
|
|
7784
|
-
attestation_format: config.reputation.attestation_format,
|
|
7785
|
-
reputation_portable: true
|
|
7786
|
-
}
|
|
7787
|
-
},
|
|
7788
|
-
capabilities: {
|
|
7789
|
-
handshake: true,
|
|
7790
|
-
shr_exchange: true,
|
|
7791
|
-
reputation_verify: true,
|
|
7792
|
-
encrypted_channel: false
|
|
7793
|
-
// Not yet implemented
|
|
7794
|
-
},
|
|
7795
|
-
degradations
|
|
7796
|
-
};
|
|
7797
|
-
const canonical = canonicalizeForSigning(body);
|
|
7798
|
-
const payload = stringToBytes(canonical);
|
|
7799
|
-
const encryptionKey = derivePurposeKey(masterKey, "identity-encryption");
|
|
7800
|
-
const signatureBytes = sign(
|
|
7801
|
-
payload,
|
|
7802
|
-
identity.encrypted_private_key,
|
|
7803
|
-
encryptionKey
|
|
7804
|
-
);
|
|
7805
|
-
return {
|
|
7806
|
-
body,
|
|
7807
|
-
signed_by: identity.public_key,
|
|
7808
|
-
signature: toBase64url(signatureBytes)
|
|
7809
|
-
};
|
|
7810
|
-
}
|
|
7811
|
-
|
|
7812
7929
|
// src/shr/verifier.ts
|
|
7813
7930
|
init_encoding();
|
|
7814
7931
|
function verifySHR(shr, now) {
|
|
@@ -12679,7 +12796,15 @@ async function createSanctuaryServer(options) {
|
|
|
12679
12796
|
tls: config.dashboard.tls,
|
|
12680
12797
|
auto_open: config.dashboard.auto_open
|
|
12681
12798
|
});
|
|
12682
|
-
dashboard.setDependencies({
|
|
12799
|
+
dashboard.setDependencies({
|
|
12800
|
+
policy,
|
|
12801
|
+
baseline,
|
|
12802
|
+
auditLog,
|
|
12803
|
+
identityManager,
|
|
12804
|
+
handshakeResults,
|
|
12805
|
+
shrOpts: { config, identityManager, masterKey },
|
|
12806
|
+
sanctuaryConfig: config
|
|
12807
|
+
});
|
|
12683
12808
|
await dashboard.start();
|
|
12684
12809
|
approvalChannel = dashboard;
|
|
12685
12810
|
} else if (config.webhook.enabled && config.webhook.url && config.webhook.secret) {
|