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