@sanctuary-framework/mcp-server 1.0.0-rc.1 → 1.1.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/dist/cli.cjs +4762 -1491
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +4763 -1492
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +3033 -223
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +907 -3
- package/dist/index.d.ts +907 -3
- package/dist/index.js +3030 -227
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
|
2
2
|
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
3
3
|
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
4
4
|
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
|
|
5
|
+
import { Writable } from 'node:stream';
|
|
5
6
|
|
|
6
7
|
interface SanctuaryConfig {
|
|
7
8
|
version: string;
|
|
@@ -68,6 +69,12 @@ interface SanctuaryConfig {
|
|
|
68
69
|
/** Whether to auto-publish on successful handshake_respond calls. */
|
|
69
70
|
auto_publish_handshakes: boolean;
|
|
70
71
|
};
|
|
72
|
+
privacy_filter: {
|
|
73
|
+
mode: "local" | "opf" | "off";
|
|
74
|
+
fail_mode: "closed" | "fallback";
|
|
75
|
+
command: string;
|
|
76
|
+
timeout_ms: number;
|
|
77
|
+
};
|
|
71
78
|
}
|
|
72
79
|
/**
|
|
73
80
|
* Load configuration from file, falling back to defaults.
|
|
@@ -761,6 +768,28 @@ interface EncryptedPayload {
|
|
|
761
768
|
* - Secure deletion overwrites before unlinking
|
|
762
769
|
*/
|
|
763
770
|
|
|
771
|
+
/** On-disk format for an encrypted state entry */
|
|
772
|
+
interface StateEntry {
|
|
773
|
+
/** Format version */
|
|
774
|
+
v: number;
|
|
775
|
+
/** Encrypted payload */
|
|
776
|
+
payload: EncryptedPayload;
|
|
777
|
+
/** Version number (monotonically increasing) */
|
|
778
|
+
ver: number;
|
|
779
|
+
/** Signature over ciphertext by the writing identity (base64url) */
|
|
780
|
+
sig: string;
|
|
781
|
+
/** Identity that wrote this entry */
|
|
782
|
+
kid: string;
|
|
783
|
+
/** SHA-256 of the plaintext value (base64url, for client-side verification) */
|
|
784
|
+
integrity_hash: string;
|
|
785
|
+
/** Metadata */
|
|
786
|
+
metadata: {
|
|
787
|
+
content_type?: string;
|
|
788
|
+
ttl_seconds?: number;
|
|
789
|
+
tags?: string[];
|
|
790
|
+
written_at: string;
|
|
791
|
+
};
|
|
792
|
+
}
|
|
764
793
|
/** Result of a state write operation */
|
|
765
794
|
interface WriteResult {
|
|
766
795
|
key: string;
|
|
@@ -2122,6 +2151,109 @@ declare const MODEL_PRESETS: {
|
|
|
2122
2151
|
mistral7bLocal: () => ModelProvenance;
|
|
2123
2152
|
};
|
|
2124
2153
|
|
|
2154
|
+
/**
|
|
2155
|
+
* Signature scheme identifier embedded on every signed v1.1 record.
|
|
2156
|
+
*
|
|
2157
|
+
* v1.1 only accepts "ed25519-v1". Mirrors the mesh module: this field is the
|
|
2158
|
+
* forward-compat hinge for v1.4+ post-quantum migration. Verifiers MUST reject
|
|
2159
|
+
* unknown schemes. Do not optimize this field away.
|
|
2160
|
+
*
|
|
2161
|
+
* Mirror of: server/src/mesh/constants.ts SignatureScheme.
|
|
2162
|
+
*/
|
|
2163
|
+
type SignatureScheme = "ed25519-v1";
|
|
2164
|
+
/**
|
|
2165
|
+
* Detector classes for the privacy filter. Workstreams MUST use this enum so
|
|
2166
|
+
* the dashboard privacy panel and audit consumers can group consistently.
|
|
2167
|
+
*
|
|
2168
|
+
* "custom" is reserved for operator-defined detectors via policy.
|
|
2169
|
+
*/
|
|
2170
|
+
declare const PRIVACY_DETECTOR_CLASSES: readonly ["person", "client", "project", "secret", "credential", "account", "file_path", "domain_term", "custom"];
|
|
2171
|
+
type PrivacyDetectorClass = (typeof PRIVACY_DETECTOR_CLASSES)[number];
|
|
2172
|
+
/**
|
|
2173
|
+
* Outbound destination categories. The privacy filter and the remote-bound
|
|
2174
|
+
* enforcement workstream agree on this enum so events compose end-to-end.
|
|
2175
|
+
*
|
|
2176
|
+
* Categories deliberately mirror the L2 `ProviderCategory` taxonomy in
|
|
2177
|
+
* `server/src/l2-operational/context-gate.ts` (hyphen form) so JSON-stable
|
|
2178
|
+
* strings flow through both layers without translation. If the L2 category
|
|
2179
|
+
* set grows, keep this v1.1 list in lockstep through coordinator review.
|
|
2180
|
+
*/
|
|
2181
|
+
declare const PRIVACY_DESTINATION_CATEGORIES: readonly ["inference", "tool-api", "logging", "analytics", "peer-agent", "custom"];
|
|
2182
|
+
type PrivacyDestinationCategory = (typeof PRIVACY_DESTINATION_CATEGORIES)[number];
|
|
2183
|
+
/**
|
|
2184
|
+
* Privacy actions taken on a single field. Uses the L2 vocabulary.
|
|
2185
|
+
*
|
|
2186
|
+
* "rehydrate" is v1.1-new and applies to inbound responses, not outbound calls.
|
|
2187
|
+
*/
|
|
2188
|
+
declare const PRIVACY_ACTIONS: readonly ["allow", "redact", "hash", "summarize", "deny", "rehydrate"];
|
|
2189
|
+
type PrivacyAction = (typeof PRIVACY_ACTIONS)[number];
|
|
2190
|
+
/**
|
|
2191
|
+
* Hash algorithm identifier embedded in every privacy event content_hash.
|
|
2192
|
+
*
|
|
2193
|
+
* v1.1 ships ONLY `hmac-sha256-fortress-keyed-v1`: HMAC-SHA-256 over the
|
|
2194
|
+
* raw field value, using a per-fortress secret derived from the master key
|
|
2195
|
+
* via HKDF info string `sanctuary-v1.1-privacy-content-hmac`. Plain SHA-256
|
|
2196
|
+
* is NOT permitted because privacy field values (PII, project names, client
|
|
2197
|
+
* names, file paths) are low-entropy and dictionary-attackable. The keyed
|
|
2198
|
+
* hash makes content hashes meaningful for equality checks across events
|
|
2199
|
+
* within a fortress while remaining opaque to anyone without the per-
|
|
2200
|
+
* fortress key.
|
|
2201
|
+
*
|
|
2202
|
+
* Forward-compat: a future v1.x privacy hardening pass may add ML-DSA-keyed
|
|
2203
|
+
* variants. Verifiers MUST reject unknown algorithms.
|
|
2204
|
+
*/
|
|
2205
|
+
declare const PRIVACY_HASH_ALGS: readonly ["hmac-sha256-fortress-keyed-v1"];
|
|
2206
|
+
type PrivacyHashAlg = (typeof PRIVACY_HASH_ALGS)[number];
|
|
2207
|
+
/**
|
|
2208
|
+
* Exit-bundle manifest version. v1 is the only valid value at v1.1 ship.
|
|
2209
|
+
* v1.x bumps require coordinator-approved manifest amendment.
|
|
2210
|
+
*/
|
|
2211
|
+
declare const EXIT_BUNDLE_MANIFEST_VERSION: "SANCTUARY_EXIT_BUNDLE_V1";
|
|
2212
|
+
type ExitBundleManifestVersion = typeof EXIT_BUNDLE_MANIFEST_VERSION;
|
|
2213
|
+
/**
|
|
2214
|
+
* Artifact kinds enumerated by the exit-bundle manifest. The export command
|
|
2215
|
+
* MUST list every included artifact under one of these kinds. The verifier
|
|
2216
|
+
* CLI rejects unknown kinds.
|
|
2217
|
+
*/
|
|
2218
|
+
declare const EXIT_BUNDLE_ARTIFACT_KINDS: readonly ["public_identity", "encrypted_state", "policy_set", "audit_receipts", "reputation_bundle", "commitments", "placeholder_vault_metadata"];
|
|
2219
|
+
type ExitBundleArtifactKind = (typeof EXIT_BUNDLE_ARTIFACT_KINDS)[number];
|
|
2220
|
+
|
|
2221
|
+
/**
|
|
2222
|
+
* Lightweight local privacy filter for outbound context.
|
|
2223
|
+
*
|
|
2224
|
+
* This is not a replacement for a full detector such as OpenAI privacy-filter.
|
|
2225
|
+
* It gives Sanctuary a deterministic baseline that catches common high-risk
|
|
2226
|
+
* spans inside otherwise-allowed fields, so policy gates are not limited to
|
|
2227
|
+
* top-level field names.
|
|
2228
|
+
*/
|
|
2229
|
+
|
|
2230
|
+
type PrivacySpanClass = "email" | "phone" | "ssn" | "credit_card" | "secret_assignment" | "secret" | "credential" | "account_number" | "address" | "person" | "client" | "project" | "file_path" | "domain_term" | "url" | "date" | "custom";
|
|
2231
|
+
declare class PrivacyPlaceholderVault {
|
|
2232
|
+
private storage;
|
|
2233
|
+
private encryptionKey;
|
|
2234
|
+
private lookupKey;
|
|
2235
|
+
private cache;
|
|
2236
|
+
private pathCache;
|
|
2237
|
+
constructor(storage: StorageBackend, masterKey: Uint8Array);
|
|
2238
|
+
placeholderFor(spanClass: PrivacySpanClass, rawValue: string, scope?: string): Promise<string>;
|
|
2239
|
+
resolvePlaceholder(placeholder: string, scope?: string): Promise<string | null>;
|
|
2240
|
+
aliasForFieldPath(path: string, scope?: string): Promise<string>;
|
|
2241
|
+
resolveFieldPathAlias(alias: string, scope?: string): Promise<string | null>;
|
|
2242
|
+
private recordKey;
|
|
2243
|
+
private indexKey;
|
|
2244
|
+
private pathRecordKey;
|
|
2245
|
+
private pathIndexKey;
|
|
2246
|
+
private readIndex;
|
|
2247
|
+
private writeIndex;
|
|
2248
|
+
private readRecord;
|
|
2249
|
+
private writeRecord;
|
|
2250
|
+
private readPathIndex;
|
|
2251
|
+
private writePathIndex;
|
|
2252
|
+
private readPathRecord;
|
|
2253
|
+
private writePathRecord;
|
|
2254
|
+
private hmacString;
|
|
2255
|
+
}
|
|
2256
|
+
|
|
2125
2257
|
/**
|
|
2126
2258
|
* Sanctuary MCP Server — L2 Context Gating: Automatic Enforcer
|
|
2127
2259
|
*
|
|
@@ -2170,9 +2302,10 @@ interface EnforcerStatus {
|
|
|
2170
2302
|
declare class ContextGateEnforcer {
|
|
2171
2303
|
private policyStore;
|
|
2172
2304
|
private auditLog;
|
|
2305
|
+
private privacyVault?;
|
|
2173
2306
|
private config;
|
|
2174
2307
|
private stats;
|
|
2175
|
-
constructor(policyStore: ContextGatePolicyStore, auditLog: AuditLog, config: EnforcerConfig);
|
|
2308
|
+
constructor(policyStore: ContextGatePolicyStore, auditLog: AuditLog, config: EnforcerConfig, privacyVault?: PrivacyPlaceholderVault);
|
|
2176
2309
|
/**
|
|
2177
2310
|
* Wrap a tool handler to apply automatic context gating.
|
|
2178
2311
|
*
|
|
@@ -2274,6 +2407,9 @@ interface UpstreamServer {
|
|
|
2274
2407
|
tool_overrides?: Record<string, {
|
|
2275
2408
|
tier: 1 | 2 | 3;
|
|
2276
2409
|
}>;
|
|
2410
|
+
destination_category?: "inference" | "tool-api" | "logging" | "analytics" | "peer-agent" | "custom";
|
|
2411
|
+
privacy_policy_id?: string;
|
|
2412
|
+
privacy_identity_id?: string;
|
|
2277
2413
|
}
|
|
2278
2414
|
interface SovereigntyProfile {
|
|
2279
2415
|
version: 1;
|
|
@@ -2581,6 +2717,483 @@ declare class CallGovernor {
|
|
|
2581
2717
|
private pruneDuplicateCache;
|
|
2582
2718
|
}
|
|
2583
2719
|
|
|
2720
|
+
/**
|
|
2721
|
+
* Sanctuary v1.1 — Privacy Audit Payload Contracts
|
|
2722
|
+
*
|
|
2723
|
+
* Shared payload shapes emitted by the privacy core (Prompt 3) and consumed by
|
|
2724
|
+
* the remote-bound enforcement workstream (Prompt 4), the operator hub API
|
|
2725
|
+
* (Prompt 5), and the dashboard privacy panel (Prompt 8).
|
|
2726
|
+
*
|
|
2727
|
+
* Local-only invariant:
|
|
2728
|
+
* Payloads describe outbound traffic from a single fortress on a single
|
|
2729
|
+
* operator's machine. v1.1 ships local-only, single-operator scope.
|
|
2730
|
+
*
|
|
2731
|
+
* Enclosure-and-signing model:
|
|
2732
|
+
* Privacy events are NOT signed objects on their own. They are payloads
|
|
2733
|
+
* carried inside an enclosing audit-chain entry (`l2-operational/audit-log`
|
|
2734
|
+
* AuditEntry encrypted-at-rest under L1, plus `mesh/audit-batch`
|
|
2735
|
+
* SignedAuditBatch where federation propagation applies). The enclosing
|
|
2736
|
+
* audit entry carries the signature scheme; this file deliberately does not
|
|
2737
|
+
* declare a signature field on any payload type.
|
|
2738
|
+
*
|
|
2739
|
+
* When an enforcement path emits a privacy event:
|
|
2740
|
+
* 1. Build a `PrivacyAuditPayload` from this file.
|
|
2741
|
+
* 2. Append it as the `details` (or equivalent payload field) of an
|
|
2742
|
+
* `AuditEntry` in the L2 audit log.
|
|
2743
|
+
* 3. The mesh-layer batch envelope (`SIGNATURE_SCHEME_V1`) signs the
|
|
2744
|
+
* batch that carries this entry.
|
|
2745
|
+
*
|
|
2746
|
+
* Safe-metadata invariant:
|
|
2747
|
+
* Raw sensitive content MUST NEVER appear in any field of any payload defined
|
|
2748
|
+
* in this file. Only safe metadata is permitted: detector class, field path,
|
|
2749
|
+
* action, content hash, policy id, destination category, identity id,
|
|
2750
|
+
* placeholder labels.
|
|
2751
|
+
*
|
|
2752
|
+
* If a future workstream needs to surface a sensitive value to the operator,
|
|
2753
|
+
* it MUST go through the encrypted placeholder vault — not through these
|
|
2754
|
+
* payload shapes.
|
|
2755
|
+
*/
|
|
2756
|
+
|
|
2757
|
+
/**
|
|
2758
|
+
* Common metadata header on every v1.1 privacy audit payload.
|
|
2759
|
+
*
|
|
2760
|
+
* `event_id` is the audit-chain id assigned by the enclosing AuditEntry.
|
|
2761
|
+
* `policy_id` is the bound privacy policy that produced the decision.
|
|
2762
|
+
* `identity_id` is the operator identity the policy is bound to.
|
|
2763
|
+
*/
|
|
2764
|
+
interface PrivacyAuditPayloadHeader {
|
|
2765
|
+
/** v1.1 payload-shape version. */
|
|
2766
|
+
version: "1.1";
|
|
2767
|
+
/** Unique event id; SHOULD match the enclosing audit-chain id. */
|
|
2768
|
+
event_id: string;
|
|
2769
|
+
/** ISO8601 timestamp of the decision. */
|
|
2770
|
+
emitted_at: string;
|
|
2771
|
+
/** Policy id that produced this decision. */
|
|
2772
|
+
policy_id: string;
|
|
2773
|
+
/** Identity the policy is bound to. */
|
|
2774
|
+
identity_id: string;
|
|
2775
|
+
/** Wrapped agent the outbound traffic originates from. */
|
|
2776
|
+
agent_id: string;
|
|
2777
|
+
/** Destination category for the outbound payload. */
|
|
2778
|
+
destination_category: PrivacyDestinationCategory;
|
|
2779
|
+
}
|
|
2780
|
+
/**
|
|
2781
|
+
* Per-field decision recorded inside a privacy audit payload. Field-level
|
|
2782
|
+
* decisions bubble up into the rolled-up payload kinds below.
|
|
2783
|
+
*
|
|
2784
|
+
* Path-and-hash safety:
|
|
2785
|
+
* `field_path` MUST be sanitized — see `PRIVACY_FIELD_PATH_PATTERN` in
|
|
2786
|
+
* constants.ts. Raw object keys (which can themselves leak sensitive
|
|
2787
|
+
* information) MUST NOT appear on the wire. `content_hash` MUST use a keyed
|
|
2788
|
+
* hash algorithm (`hmac-sha256-fortress-keyed-v1` at v1.1) to defeat
|
|
2789
|
+
* dictionary attacks against low-entropy field values.
|
|
2790
|
+
*/
|
|
2791
|
+
interface PrivacyFieldDecision {
|
|
2792
|
+
/**
|
|
2793
|
+
* Sanitized field path. Conforms to `PRIVACY_FIELD_PATH_PATTERN`:
|
|
2794
|
+
* positional references like "$0" / "$1.$2" or typed positional like
|
|
2795
|
+
* "obj:0" / "key:1.val:0". The fortress-local mapping back to the real
|
|
2796
|
+
* path is held in the placeholder vault. Real object keys MUST NOT
|
|
2797
|
+
* appear here.
|
|
2798
|
+
*/
|
|
2799
|
+
field_path: string;
|
|
2800
|
+
/** Detector class that fired on this field. */
|
|
2801
|
+
detector_class: PrivacyDetectorClass;
|
|
2802
|
+
/** Action taken on this field. */
|
|
2803
|
+
action: PrivacyAction;
|
|
2804
|
+
/**
|
|
2805
|
+
* Keyed hash of the original field value. Hex-encoded.
|
|
2806
|
+
* Algorithm pinned via `hash_alg`; v1.1 only accepts
|
|
2807
|
+
* `hmac-sha256-fortress-keyed-v1`. The HMAC key is fortress-local
|
|
2808
|
+
* (HKDF-derived from the master key); equality of two `content_hash`
|
|
2809
|
+
* values within the same fortress means equal field values, but the
|
|
2810
|
+
* hash is opaque to any verifier outside the fortress and resists
|
|
2811
|
+
* dictionary attacks against low-entropy values. Plain SHA-256 is NOT
|
|
2812
|
+
* permitted. The original value MUST NOT appear anywhere in the payload.
|
|
2813
|
+
*/
|
|
2814
|
+
content_hash: string;
|
|
2815
|
+
/** Hash algorithm identifier. v1.1 only accepts the keyed HMAC variant. */
|
|
2816
|
+
hash_alg: PrivacyHashAlg;
|
|
2817
|
+
/**
|
|
2818
|
+
* Stable placeholder label this field was substituted with on the outbound
|
|
2819
|
+
* payload, if applicable. Examples: "PERSON_1", "CLIENT_3", "SECRET_2".
|
|
2820
|
+
*/
|
|
2821
|
+
placeholder_label?: string;
|
|
2822
|
+
}
|
|
2823
|
+
/**
|
|
2824
|
+
* Outbound payload was filtered. At least one field was redacted, hashed, or
|
|
2825
|
+
* substituted with a placeholder, and the call proceeded.
|
|
2826
|
+
*/
|
|
2827
|
+
interface PrivacyFilteredPayload extends PrivacyAuditPayloadHeader {
|
|
2828
|
+
kind: "filtered";
|
|
2829
|
+
field_decisions: PrivacyFieldDecision[];
|
|
2830
|
+
/**
|
|
2831
|
+
* Keyed hash of the canonicalized outbound payload after filtering.
|
|
2832
|
+
* Same `hash_alg` constraint as `PrivacyFieldDecision.content_hash`.
|
|
2833
|
+
*/
|
|
2834
|
+
outbound_payload_hash: string;
|
|
2835
|
+
/** Hash algorithm. v1.1 only accepts `hmac-sha256-fortress-keyed-v1`. */
|
|
2836
|
+
payload_hash_alg: PrivacyHashAlg;
|
|
2837
|
+
}
|
|
2838
|
+
/**
|
|
2839
|
+
* Outbound payload was allowed unchanged. No detector fired, or every fired
|
|
2840
|
+
* detector resolved to "allow" under the bound policy.
|
|
2841
|
+
*/
|
|
2842
|
+
interface PrivacyAllowedPayload extends PrivacyAuditPayloadHeader {
|
|
2843
|
+
kind: "allowed";
|
|
2844
|
+
/**
|
|
2845
|
+
* Keyed hash of the canonicalized outbound payload.
|
|
2846
|
+
* Same `hash_alg` constraint as `PrivacyFieldDecision.content_hash`.
|
|
2847
|
+
*/
|
|
2848
|
+
outbound_payload_hash: string;
|
|
2849
|
+
/** Hash algorithm. v1.1 only accepts `hmac-sha256-fortress-keyed-v1`. */
|
|
2850
|
+
payload_hash_alg: PrivacyHashAlg;
|
|
2851
|
+
}
|
|
2852
|
+
/**
|
|
2853
|
+
* Outbound payload was denied. Either a "deny" rule fired on a field, or the
|
|
2854
|
+
* fail-closed default applied because the policy or vault was unavailable.
|
|
2855
|
+
*
|
|
2856
|
+
* The `denial_reason_class` is a machine-friendly label, NOT a free-text
|
|
2857
|
+
* explanation. Operator-facing UIs may render a generic message keyed by this
|
|
2858
|
+
* label; raw policy-rule details MUST NOT be revealed.
|
|
2859
|
+
*/
|
|
2860
|
+
interface PrivacyDeniedPayload extends PrivacyAuditPayloadHeader {
|
|
2861
|
+
kind: "denied";
|
|
2862
|
+
/**
|
|
2863
|
+
* Coarse denial reason class. Permitted values:
|
|
2864
|
+
* - "policy_deny_rule" — at least one field had a deny rule
|
|
2865
|
+
* - "fail_closed_no_policy" — fail-closed because policy missing
|
|
2866
|
+
* - "fail_closed_filter_error" — fail-closed because filter raised
|
|
2867
|
+
* - "fail_closed_vault_error" — fail-closed because vault unavailable
|
|
2868
|
+
* - "operator_override_denied" — explicit operator override path failed
|
|
2869
|
+
*/
|
|
2870
|
+
denial_reason_class: "policy_deny_rule" | "fail_closed_no_policy" | "fail_closed_filter_error" | "fail_closed_vault_error" | "operator_override_denied";
|
|
2871
|
+
}
|
|
2872
|
+
/**
|
|
2873
|
+
* Privacy filter raised an unrecoverable error and outbound traffic failed
|
|
2874
|
+
* closed. Distinct from PrivacyDeniedPayload because the operator may want to
|
|
2875
|
+
* surface error events as alerts rather than as policy decisions.
|
|
2876
|
+
*/
|
|
2877
|
+
interface PrivacyErrorPayload extends PrivacyAuditPayloadHeader {
|
|
2878
|
+
kind: "error";
|
|
2879
|
+
/** Stable error code. Implementation-specific catalog. No raw stack traces. */
|
|
2880
|
+
error_code: string;
|
|
2881
|
+
}
|
|
2882
|
+
/**
|
|
2883
|
+
* Inbound provider response was rehydrated using the placeholder vault. Only
|
|
2884
|
+
* fires when the bound policy permits rehydration for the destination category.
|
|
2885
|
+
*/
|
|
2886
|
+
interface PrivacyRehydratedPayload extends PrivacyAuditPayloadHeader {
|
|
2887
|
+
kind: "rehydrated";
|
|
2888
|
+
/**
|
|
2889
|
+
* Number of placeholders successfully rehydrated. The placeholders themselves
|
|
2890
|
+
* are NOT logged.
|
|
2891
|
+
*/
|
|
2892
|
+
rehydrated_count: number;
|
|
2893
|
+
/** Number of placeholders that could not be rehydrated (e.g., vault entry expired). */
|
|
2894
|
+
unresolvable_count: number;
|
|
2895
|
+
/**
|
|
2896
|
+
* Keyed hash of the canonicalized rehydrated response.
|
|
2897
|
+
* Same `hash_alg` constraint as `PrivacyFieldDecision.content_hash`.
|
|
2898
|
+
*/
|
|
2899
|
+
response_hash: string;
|
|
2900
|
+
/** Hash algorithm. v1.1 only accepts `hmac-sha256-fortress-keyed-v1`. */
|
|
2901
|
+
response_hash_alg: PrivacyHashAlg;
|
|
2902
|
+
}
|
|
2903
|
+
/**
|
|
2904
|
+
* Discriminated union of every v1.1 privacy audit payload. The hub API and
|
|
2905
|
+
* dashboard privacy panel switch on `kind`. Integrity of these payloads
|
|
2906
|
+
* derives from the enclosing audit entry (encrypted-at-rest, plus signed at
|
|
2907
|
+
* the mesh-batch layer where applicable). No payload in this file carries a
|
|
2908
|
+
* self-signature.
|
|
2909
|
+
*/
|
|
2910
|
+
type PrivacyAuditPayload = PrivacyFilteredPayload | PrivacyAllowedPayload | PrivacyDeniedPayload | PrivacyErrorPayload | PrivacyRehydratedPayload;
|
|
2911
|
+
|
|
2912
|
+
/**
|
|
2913
|
+
* Sanctuary v1.1 — Exit Bundle Manifest Contract
|
|
2914
|
+
*
|
|
2915
|
+
* `SANCTUARY_EXIT_BUNDLE_V1` is the canonical manifest produced by the v1.1
|
|
2916
|
+
* exit-bundle workstream (Prompt 7) and consumed by the standalone verifier
|
|
2917
|
+
* CLI plus the import command.
|
|
2918
|
+
*
|
|
2919
|
+
* Local-only invariant:
|
|
2920
|
+
* The bundle is produced by a single fortress on a single operator's machine
|
|
2921
|
+
* and consumed by another single-operator destination. v1.1 ships local-only,
|
|
2922
|
+
* single-operator scope. Cross-operator transfer is deferred to v1.3.
|
|
2923
|
+
*
|
|
2924
|
+
* Identity-binding invariant:
|
|
2925
|
+
* The manifest is signed by the operator's fortress-master identity. The
|
|
2926
|
+
* verifier MUST refuse to activate any artifact whose hash chain does not
|
|
2927
|
+
* match the manifest, and MUST refuse to activate any manifest whose
|
|
2928
|
+
* signature does not verify against the bound public identity.
|
|
2929
|
+
*
|
|
2930
|
+
* Public-only invariant:
|
|
2931
|
+
* The bundle MUST NOT contain private keys, raw passphrases, or recovery
|
|
2932
|
+
* seeds. Encrypted state may travel inside the bundle, but the master key
|
|
2933
|
+
* MUST NOT. Re-keying happens on import using new operator-supplied
|
|
2934
|
+
* material.
|
|
2935
|
+
*
|
|
2936
|
+
* Manifest-version invariant:
|
|
2937
|
+
* v1.1 ships only "SANCTUARY_EXIT_BUNDLE_V1". Future versions land through
|
|
2938
|
+
* coordinator-approved spec amendments. v1.1 verifiers MUST reject unknown
|
|
2939
|
+
* manifest versions rather than silently accept.
|
|
2940
|
+
*/
|
|
2941
|
+
|
|
2942
|
+
/**
|
|
2943
|
+
* Hashing algorithm identifier embedded in every artifact entry. v1.1 uses
|
|
2944
|
+
* SHA-256. Forward-compat: a future bundle version may add SHA-3 or BLAKE3.
|
|
2945
|
+
*/
|
|
2946
|
+
type ExitBundleHashAlg = "sha256";
|
|
2947
|
+
/**
|
|
2948
|
+
* One artifact entry inside the manifest. Each artifact lives at a relative
|
|
2949
|
+
* path inside the bundle archive. The verifier reads the file at that path
|
|
2950
|
+
* and confirms its hash. See `EXIT_BUNDLE_PATH_PATTERN` and the safe-path
|
|
2951
|
+
* rules block above for the full set of constraints.
|
|
2952
|
+
*/
|
|
2953
|
+
interface ExitBundleArtifactEntry {
|
|
2954
|
+
/** Coarse artifact kind. */
|
|
2955
|
+
kind: ExitBundleArtifactKind;
|
|
2956
|
+
/**
|
|
2957
|
+
* Relative path inside the bundle, POSIX-style. MUST satisfy
|
|
2958
|
+
* `EXIT_BUNDLE_PATH_PATTERN` and the safe-path rules block above.
|
|
2959
|
+
* The verifier rejects any entry whose path is absolute, contains "..",
|
|
2960
|
+
* contains backslashes, or duplicates another entry's path. The verifier
|
|
2961
|
+
* does NOT follow symlinks or hardlinks during extraction.
|
|
2962
|
+
*/
|
|
2963
|
+
path: string;
|
|
2964
|
+
/** Hash algorithm. v1.1 ships only "sha256". */
|
|
2965
|
+
hash_alg: ExitBundleHashAlg;
|
|
2966
|
+
/** Hex-encoded artifact hash. */
|
|
2967
|
+
hash: string;
|
|
2968
|
+
/** Size in bytes. Verifier MAY independently re-size and reject on mismatch. */
|
|
2969
|
+
size_bytes: number;
|
|
2970
|
+
/**
|
|
2971
|
+
* Optional discriminator inside the kind, e.g., "audit-receipt-2026-Q2".
|
|
2972
|
+
* Verifier does not interpret this; the import command may use it to order
|
|
2973
|
+
* artifacts. Same path-pattern constraints DO NOT apply to subkind, but
|
|
2974
|
+
* subkind MUST NOT contain control characters.
|
|
2975
|
+
*/
|
|
2976
|
+
subkind?: string;
|
|
2977
|
+
}
|
|
2978
|
+
/**
|
|
2979
|
+
* Identity binding embedded in the manifest. Carries only public material.
|
|
2980
|
+
*/
|
|
2981
|
+
interface ExitBundleIdentityBinding {
|
|
2982
|
+
/** Operator identity id. */
|
|
2983
|
+
identity_id: string;
|
|
2984
|
+
/** Fortress id. */
|
|
2985
|
+
fortress_id: string;
|
|
2986
|
+
/** Base64url-encoded Ed25519 public key of the fortress-master. */
|
|
2987
|
+
fortress_master_pubkey: string;
|
|
2988
|
+
/** Optional DID, when one is bound to this identity. */
|
|
2989
|
+
did?: string;
|
|
2990
|
+
}
|
|
2991
|
+
/**
|
|
2992
|
+
* v1 manifest body — what the operator's fortress-master signs.
|
|
2993
|
+
*
|
|
2994
|
+
* `signature_scheme` lives INSIDE the body deliberately so the scheme is
|
|
2995
|
+
* covered by the fortress-master signature. Without this, an attacker who
|
|
2996
|
+
* substituted both `signature` and `signature_scheme` on the wrapper could
|
|
2997
|
+
* present a valid-looking manifest with a different scheme. Pinning the
|
|
2998
|
+
* scheme inside the signed bytes makes the crypto-agility hinge non-
|
|
2999
|
+
* substitutable.
|
|
3000
|
+
*/
|
|
3001
|
+
interface ExitBundleManifestBody {
|
|
3002
|
+
/** Manifest version constant. */
|
|
3003
|
+
manifest_version: ExitBundleManifestVersion;
|
|
3004
|
+
/** ISO8601 timestamp at export time. */
|
|
3005
|
+
exported_at: string;
|
|
3006
|
+
/** Source fortress / operator identity binding. */
|
|
3007
|
+
identity_binding: ExitBundleIdentityBinding;
|
|
3008
|
+
/**
|
|
3009
|
+
* Sanctuary version string at export time. Verifier surfaces version skew
|
|
3010
|
+
* to the operator if the destination fortress is older.
|
|
3011
|
+
*/
|
|
3012
|
+
source_sanctuary_version: string;
|
|
3013
|
+
/** Every artifact carried in the bundle. */
|
|
3014
|
+
artifacts: ExitBundleArtifactEntry[];
|
|
3015
|
+
/**
|
|
3016
|
+
* Aggregate hash over canonicalize(artifacts[]). Lets the verifier perform
|
|
3017
|
+
* a fast sanity check before walking each entry.
|
|
3018
|
+
*/
|
|
3019
|
+
artifacts_aggregate_hash: string;
|
|
3020
|
+
/** Aggregate hash algorithm. v1.1 ships only "sha256". */
|
|
3021
|
+
artifacts_aggregate_hash_alg: ExitBundleHashAlg;
|
|
3022
|
+
/**
|
|
3023
|
+
* Tier 1 audit-event id that captured the export approval. Consumers MAY
|
|
3024
|
+
* cross-reference with the source fortress audit chain.
|
|
3025
|
+
*/
|
|
3026
|
+
export_approval_audit_id: string;
|
|
3027
|
+
/**
|
|
3028
|
+
* Signature scheme covering the wrapper's `signature` field. v1.1 ships
|
|
3029
|
+
* only "ed25519-v1". Embedded inside the signed body so the scheme cannot
|
|
3030
|
+
* be substituted independently of the signature.
|
|
3031
|
+
*/
|
|
3032
|
+
signature_scheme: SignatureScheme;
|
|
3033
|
+
}
|
|
3034
|
+
/**
|
|
3035
|
+
* Full signed manifest. Top-level shape that ships in the bundle archive.
|
|
3036
|
+
*
|
|
3037
|
+
* The wrapper carries only the `signature` and a pointer to the body. The
|
|
3038
|
+
* scheme that produced the signature lives inside `body.signature_scheme`,
|
|
3039
|
+
* so the signature itself attests to which scheme produced it.
|
|
3040
|
+
*/
|
|
3041
|
+
interface ExitBundleManifest {
|
|
3042
|
+
/** Body — what the signature covers. */
|
|
3043
|
+
body: ExitBundleManifestBody;
|
|
3044
|
+
/**
|
|
3045
|
+
* Base64url-encoded Ed25519 signature over canonicalize(body) by the
|
|
3046
|
+
* fortress-master private key. The bundle archive is otherwise unsigned;
|
|
3047
|
+
* artifact integrity comes from artifact hashes inside the body. The
|
|
3048
|
+
* signing scheme is `body.signature_scheme`.
|
|
3049
|
+
*/
|
|
3050
|
+
signature: string;
|
|
3051
|
+
}
|
|
3052
|
+
/**
|
|
3053
|
+
* Verifier output shape. The standalone verifier CLI emits this structure on
|
|
3054
|
+
* stdout (or as JSON for tool consumers) so import commands can branch
|
|
3055
|
+
* cleanly. v1.1 ships one VerifierResult shape; future versions extend.
|
|
3056
|
+
*/
|
|
3057
|
+
interface ExitBundleVerifierResult {
|
|
3058
|
+
version: "1.1";
|
|
3059
|
+
/** True iff manifest signature, every artifact hash, and the aggregate hash all verify. */
|
|
3060
|
+
passed: boolean;
|
|
3061
|
+
/** ISO8601 timestamp of verification. */
|
|
3062
|
+
verified_at: string;
|
|
3063
|
+
/** Reference to the verified manifest body. */
|
|
3064
|
+
manifest_summary: {
|
|
3065
|
+
manifest_version: ExitBundleManifestVersion;
|
|
3066
|
+
fortress_id: string;
|
|
3067
|
+
identity_id: string;
|
|
3068
|
+
exported_at: string;
|
|
3069
|
+
artifact_count: number;
|
|
3070
|
+
};
|
|
3071
|
+
/**
|
|
3072
|
+
* Per-artifact verification result. Order matches `manifest.body.artifacts`.
|
|
3073
|
+
*/
|
|
3074
|
+
artifact_results: Array<{
|
|
3075
|
+
path: string;
|
|
3076
|
+
kind: ExitBundleArtifactKind;
|
|
3077
|
+
hash_passed: boolean;
|
|
3078
|
+
size_passed: boolean;
|
|
3079
|
+
}>;
|
|
3080
|
+
/**
|
|
3081
|
+
* Coarse failure-class enum, when `passed` is false. Distinct from a free-text
|
|
3082
|
+
* error message so import commands can branch.
|
|
3083
|
+
*/
|
|
3084
|
+
failure_class?: "manifest_signature_invalid" | "manifest_unknown_version" | "manifest_signature_scheme_invalid" | "artifact_hash_mismatch" | "artifact_missing" | "artifact_size_mismatch" | "aggregate_hash_mismatch" | "artifact_path_unsafe" | "artifact_path_duplicate" | "artifact_path_escapes_root" | "archive_contains_symlink" | "private_material_present" | "other";
|
|
3085
|
+
}
|
|
3086
|
+
|
|
3087
|
+
/**
|
|
3088
|
+
* Sanctuary v1.1 — local query privacy core.
|
|
3089
|
+
*
|
|
3090
|
+
* This module is intentionally independent of dashboard UI and transport
|
|
3091
|
+
* enforcement. Enforcement paths call it with a payload, destination category,
|
|
3092
|
+
* identity-bound policy, and encrypted placeholder vault; the module returns a
|
|
3093
|
+
* filtered payload or a fail-closed denial plus a shared privacy audit payload.
|
|
3094
|
+
*/
|
|
3095
|
+
|
|
3096
|
+
type PrivacyPolicyAction = "placeholder" | Extract<PrivacyAction, "allow" | "redact" | "hash" | "deny">;
|
|
3097
|
+
interface PrivacyPolicy {
|
|
3098
|
+
version: 1;
|
|
3099
|
+
policy_id: string;
|
|
3100
|
+
policy_name?: string;
|
|
3101
|
+
identity_id: string;
|
|
3102
|
+
detector_actions?: Partial<Record<PrivacyDetectorClass, PrivacyPolicyAction>>;
|
|
3103
|
+
destination_detector_actions?: Partial<Record<PrivacyDestinationCategory, Partial<Record<PrivacyDetectorClass, PrivacyPolicyAction>>>>;
|
|
3104
|
+
client_names?: string[];
|
|
3105
|
+
project_names?: string[];
|
|
3106
|
+
domain_terms?: string[];
|
|
3107
|
+
person_names?: string[];
|
|
3108
|
+
placeholder_scope?: "identity" | "policy";
|
|
3109
|
+
rehydration?: {
|
|
3110
|
+
default_action?: "allow" | "deny";
|
|
3111
|
+
allowed_destinations?: PrivacyDestinationCategory[];
|
|
3112
|
+
denied_destinations?: PrivacyDestinationCategory[];
|
|
3113
|
+
};
|
|
3114
|
+
max_depth?: number;
|
|
3115
|
+
max_payload_bytes?: number;
|
|
3116
|
+
max_string_bytes?: number;
|
|
3117
|
+
operator_override?: {
|
|
3118
|
+
allow_on_policy_error?: boolean;
|
|
3119
|
+
allow_on_filter_error?: boolean;
|
|
3120
|
+
allow_on_vault_error?: boolean;
|
|
3121
|
+
allow_on_detector_error?: boolean;
|
|
3122
|
+
};
|
|
3123
|
+
created_at: string;
|
|
3124
|
+
updated_at: string;
|
|
3125
|
+
}
|
|
3126
|
+
interface PrivacyCoreFinding {
|
|
3127
|
+
raw_path: string;
|
|
3128
|
+
detector_class: PrivacyDetectorClass;
|
|
3129
|
+
span_class: PrivacySpanClass;
|
|
3130
|
+
action: PrivacyAction;
|
|
3131
|
+
content_hash: string;
|
|
3132
|
+
placeholder_label?: string;
|
|
3133
|
+
}
|
|
3134
|
+
interface PrivacyFilterRequest {
|
|
3135
|
+
payload: unknown;
|
|
3136
|
+
policy: PrivacyPolicy | null;
|
|
3137
|
+
identity_id?: string;
|
|
3138
|
+
agent_id: string;
|
|
3139
|
+
destination_category: PrivacyDestinationCategory;
|
|
3140
|
+
audit_log?: AuditLog;
|
|
3141
|
+
event_id?: string;
|
|
3142
|
+
}
|
|
3143
|
+
type PrivacyFilterDecision = {
|
|
3144
|
+
status: "allowed";
|
|
3145
|
+
payload: unknown;
|
|
3146
|
+
findings: [];
|
|
3147
|
+
audit_payload: PrivacyAuditPayload;
|
|
3148
|
+
} | {
|
|
3149
|
+
status: "filtered";
|
|
3150
|
+
payload: unknown;
|
|
3151
|
+
findings: PrivacyCoreFinding[];
|
|
3152
|
+
audit_payload: PrivacyAuditPayload;
|
|
3153
|
+
} | {
|
|
3154
|
+
status: "denied";
|
|
3155
|
+
payload: undefined;
|
|
3156
|
+
findings: PrivacyCoreFinding[];
|
|
3157
|
+
audit_payload: PrivacyDeniedPayload;
|
|
3158
|
+
};
|
|
3159
|
+
interface PrivacyRehydrationRequest {
|
|
3160
|
+
response: unknown;
|
|
3161
|
+
policy: PrivacyPolicy | null;
|
|
3162
|
+
identity_id?: string;
|
|
3163
|
+
agent_id: string;
|
|
3164
|
+
destination_category: PrivacyDestinationCategory;
|
|
3165
|
+
audit_log?: AuditLog;
|
|
3166
|
+
event_id?: string;
|
|
3167
|
+
}
|
|
3168
|
+
type PrivacyRehydrationDecision = {
|
|
3169
|
+
status: "rehydrated";
|
|
3170
|
+
response: unknown;
|
|
3171
|
+
rehydrated_count: number;
|
|
3172
|
+
unresolvable_count: number;
|
|
3173
|
+
audit_payload: PrivacyAuditPayload;
|
|
3174
|
+
} | {
|
|
3175
|
+
status: "denied";
|
|
3176
|
+
response: unknown;
|
|
3177
|
+
rehydrated_count: 0;
|
|
3178
|
+
unresolvable_count: 0;
|
|
3179
|
+
audit_payload: PrivacyDeniedPayload;
|
|
3180
|
+
};
|
|
3181
|
+
declare class LocalPrivacyEngine {
|
|
3182
|
+
private vault;
|
|
3183
|
+
private hmacKey;
|
|
3184
|
+
constructor(vault: PrivacyPlaceholderVault, masterKey: Uint8Array);
|
|
3185
|
+
filterOutbound(request: PrivacyFilterRequest): Promise<PrivacyFilterDecision>;
|
|
3186
|
+
rehydrateResponse(request: PrivacyRehydrationRequest): Promise<PrivacyRehydrationDecision>;
|
|
3187
|
+
private filterNode;
|
|
3188
|
+
private filterString;
|
|
3189
|
+
private fieldDecisionsForFindings;
|
|
3190
|
+
private rehydrateNode;
|
|
3191
|
+
private rehydrateString;
|
|
3192
|
+
private assertPayloadWithinBounds;
|
|
3193
|
+
private deniedPayload;
|
|
3194
|
+
private keyedHash;
|
|
3195
|
+
}
|
|
3196
|
+
|
|
2584
3197
|
/**
|
|
2585
3198
|
* Sanctuary MCP Server — Proxy Router
|
|
2586
3199
|
*
|
|
@@ -2603,6 +3216,27 @@ interface ProxyRouterOptions {
|
|
|
2603
3216
|
contextGateFilter?: (toolName: string, args: Record<string, unknown>) => Promise<Record<string, unknown>>;
|
|
2604
3217
|
/** Optional call governor for runtime governance */
|
|
2605
3218
|
governor?: CallGovernor;
|
|
3219
|
+
/**
|
|
3220
|
+
* Optional v1.1 remote-bound privacy enforcement.
|
|
3221
|
+
*
|
|
3222
|
+
* When set, every proxied tool call is routed through
|
|
3223
|
+
* `engine.filterOutbound` before the upstream forward. The bound
|
|
3224
|
+
* `PrivacyPolicy` is resolved per-server via `policyResolver`, and the
|
|
3225
|
+
* destination category comes from the server's `destination_category`
|
|
3226
|
+
* field (defaulting to `tool-api` when absent).
|
|
3227
|
+
*
|
|
3228
|
+
* Fail-closed semantics:
|
|
3229
|
+
* - `policyResolver` returns null when no policy is bound for the server;
|
|
3230
|
+
* the privacy engine treats that as `fail_closed_no_policy` and denies.
|
|
3231
|
+
* - `policyResolver` rejecting (vault unreachable, decrypt failure, etc.)
|
|
3232
|
+
* is treated as `fail_closed_filter_error` and denies.
|
|
3233
|
+
* - Operator overrides on the policy (`operator_override.allow_on_*`)
|
|
3234
|
+
* are honored by the engine itself.
|
|
3235
|
+
*/
|
|
3236
|
+
privacyEnforcement?: {
|
|
3237
|
+
engine: LocalPrivacyEngine;
|
|
3238
|
+
policyResolver: (server: string, identityId: string | undefined) => Promise<PrivacyPolicy | null>;
|
|
3239
|
+
};
|
|
2606
3240
|
/** Optional callback after each proxy call decision (for dashboard feed) */
|
|
2607
3241
|
onProxyCall?: (data: {
|
|
2608
3242
|
tool: string;
|
|
@@ -2720,6 +3354,246 @@ declare class FilesystemStorage implements StorageBackend {
|
|
|
2720
3354
|
totalSize(): Promise<number>;
|
|
2721
3355
|
}
|
|
2722
3356
|
|
|
3357
|
+
/**
|
|
3358
|
+
* Sanctuary MCP Server — Key Derivation
|
|
3359
|
+
*
|
|
3360
|
+
* Two-tier key derivation:
|
|
3361
|
+
* 1. Master key from passphrase via Argon2id (memory-hard, GPU-resistant)
|
|
3362
|
+
* 2. Namespace keys from master key via HKDF-SHA256
|
|
3363
|
+
*
|
|
3364
|
+
* This ensures:
|
|
3365
|
+
* - Passphrase brute-force is expensive (Argon2id)
|
|
3366
|
+
* - Compromise of one namespace key doesn't expose others (HKDF domain separation)
|
|
3367
|
+
*/
|
|
3368
|
+
/** Stored key derivation parameters (for re-deriving the master key) */
|
|
3369
|
+
interface KeyDerivationParams {
|
|
3370
|
+
/** Algorithm */
|
|
3371
|
+
alg: "argon2id";
|
|
3372
|
+
/** Salt (base64url) */
|
|
3373
|
+
salt: string;
|
|
3374
|
+
/** Memory cost in KiB */
|
|
3375
|
+
m: number;
|
|
3376
|
+
/** Time cost (iterations) */
|
|
3377
|
+
t: number;
|
|
3378
|
+
/** Parallelism */
|
|
3379
|
+
p: number;
|
|
3380
|
+
/** Output length in bytes */
|
|
3381
|
+
l: number;
|
|
3382
|
+
}
|
|
3383
|
+
|
|
3384
|
+
/**
|
|
3385
|
+
* Sanctuary v1.1 exit-bundle export/import implementation.
|
|
3386
|
+
*
|
|
3387
|
+
* The public bundle is a directory containing `manifest.json` and hashed JSON
|
|
3388
|
+
* artifacts. Private keys and passphrases are never emitted. Encrypted user
|
|
3389
|
+
* state can be re-keyed on import when the operator supplies source key
|
|
3390
|
+
* material and the destination has a signing identity.
|
|
3391
|
+
*/
|
|
3392
|
+
|
|
3393
|
+
interface ExitEncryptedStateBundle {
|
|
3394
|
+
format: "SANCTUARY_EXIT_ENCRYPTED_STATE_V1";
|
|
3395
|
+
exported_at: string;
|
|
3396
|
+
key_source: "passphrase" | "recovery-key" | "unknown";
|
|
3397
|
+
source_key_derivation?: KeyDerivationParams;
|
|
3398
|
+
namespaces: string[];
|
|
3399
|
+
total_keys: number;
|
|
3400
|
+
contains_reserved_namespaces: false;
|
|
3401
|
+
entries: Array<{
|
|
3402
|
+
namespace: string;
|
|
3403
|
+
key: string;
|
|
3404
|
+
entry: StateEntry;
|
|
3405
|
+
}>;
|
|
3406
|
+
}
|
|
3407
|
+
interface ExitPublicIdentityArtifact {
|
|
3408
|
+
bundle: {
|
|
3409
|
+
format: "SANCTUARY_IDENTITY_BUNDLE_V1";
|
|
3410
|
+
publicKey: string;
|
|
3411
|
+
did: string;
|
|
3412
|
+
identity_id: string;
|
|
3413
|
+
label: string;
|
|
3414
|
+
key_type: "ed25519";
|
|
3415
|
+
key_protection: string;
|
|
3416
|
+
rotation_history: StoredIdentity["rotation_history"];
|
|
3417
|
+
exported_at: string;
|
|
3418
|
+
};
|
|
3419
|
+
signature: string;
|
|
3420
|
+
signed_by: string;
|
|
3421
|
+
}
|
|
3422
|
+
interface ExitPolicySetArtifact {
|
|
3423
|
+
format: "SANCTUARY_EXIT_POLICY_SET_V1";
|
|
3424
|
+
exported_at: string;
|
|
3425
|
+
principal_policy: PrincipalPolicy;
|
|
3426
|
+
config_summary: {
|
|
3427
|
+
version: string;
|
|
3428
|
+
state: SanctuaryConfig["state"];
|
|
3429
|
+
execution: SanctuaryConfig["execution"];
|
|
3430
|
+
disclosure: SanctuaryConfig["disclosure"];
|
|
3431
|
+
reputation: SanctuaryConfig["reputation"];
|
|
3432
|
+
privacy_filter: SanctuaryConfig["privacy_filter"];
|
|
3433
|
+
};
|
|
3434
|
+
}
|
|
3435
|
+
interface ExitAuditReceiptsArtifact {
|
|
3436
|
+
format: "SANCTUARY_AUDIT_RECEIPTS_V1";
|
|
3437
|
+
exported_at: string;
|
|
3438
|
+
total: number;
|
|
3439
|
+
individual_entry_signatures: false;
|
|
3440
|
+
entries: AuditEntry[];
|
|
3441
|
+
}
|
|
3442
|
+
interface ExitCommitmentsArtifact {
|
|
3443
|
+
format: "SANCTUARY_EXIT_COMMITMENTS_V1";
|
|
3444
|
+
exported_at: string;
|
|
3445
|
+
public_commitments: Array<{
|
|
3446
|
+
commitment_id: string;
|
|
3447
|
+
commitment: string;
|
|
3448
|
+
committed_at: string;
|
|
3449
|
+
revealed: boolean;
|
|
3450
|
+
revealed_at?: string;
|
|
3451
|
+
}>;
|
|
3452
|
+
unreadable_count: number;
|
|
3453
|
+
redacted_fields: ["value", "blinding_factor"];
|
|
3454
|
+
}
|
|
3455
|
+
interface ExitPlaceholderVaultMetadataArtifact {
|
|
3456
|
+
format: "SANCTUARY_PLACEHOLDER_VAULT_METADATA_V1";
|
|
3457
|
+
exported_at: string;
|
|
3458
|
+
entries: Array<Record<string, unknown>>;
|
|
3459
|
+
unreadable_count: number;
|
|
3460
|
+
redacted_fields: ["raw_value", "raw_path"];
|
|
3461
|
+
}
|
|
3462
|
+
interface ExportExitBundleOptions {
|
|
3463
|
+
bundleDir: string;
|
|
3464
|
+
storage: StorageBackend;
|
|
3465
|
+
masterKey: Uint8Array;
|
|
3466
|
+
identityManager: IdentityManager;
|
|
3467
|
+
auditLog: AuditLog;
|
|
3468
|
+
policy: PrincipalPolicy;
|
|
3469
|
+
config?: SanctuaryConfig;
|
|
3470
|
+
reputationStore?: ReputationStore;
|
|
3471
|
+
stateStoragePath?: string;
|
|
3472
|
+
stateNamespaces?: string[];
|
|
3473
|
+
keySource?: "passphrase" | "recovery-key" | "unknown";
|
|
3474
|
+
/**
|
|
3475
|
+
* When the export is gated by a Tier 1 approval flow (e.g. the hub's
|
|
3476
|
+
* fortress-scope export endpoint), the caller supplies the approval's
|
|
3477
|
+
* audit id here. The value is embedded in the manifest's
|
|
3478
|
+
* `export_approval_audit_id` field and as the `approval_id` of the L1
|
|
3479
|
+
* "exit_bundle_export" audit entry, tying the manifest to the operator's
|
|
3480
|
+
* actual approval rather than an internally-generated id (v1.0.2 (j)).
|
|
3481
|
+
* When omitted, the export self-generates an id.
|
|
3482
|
+
*/
|
|
3483
|
+
exportApprovalAuditId?: string;
|
|
3484
|
+
}
|
|
3485
|
+
interface ExportExitBundleResult {
|
|
3486
|
+
bundle_dir: string;
|
|
3487
|
+
manifest: ExitBundleManifest;
|
|
3488
|
+
manifest_hash: string;
|
|
3489
|
+
artifact_count: number;
|
|
3490
|
+
unsupported_artifacts: string[];
|
|
3491
|
+
}
|
|
3492
|
+
interface ImportExitBundleOptions {
|
|
3493
|
+
bundleDir: string;
|
|
3494
|
+
storage: StorageBackend;
|
|
3495
|
+
masterKey: Uint8Array;
|
|
3496
|
+
identityManager: IdentityManager;
|
|
3497
|
+
auditLog: AuditLog;
|
|
3498
|
+
reputationStore?: ReputationStore;
|
|
3499
|
+
activate?: boolean;
|
|
3500
|
+
conflictResolution?: "skip" | "overwrite" | "version";
|
|
3501
|
+
sourcePassphrase?: string;
|
|
3502
|
+
sourceRecoveryKey?: string;
|
|
3503
|
+
sourceMasterKey?: Uint8Array;
|
|
3504
|
+
destinationSignerIdentityId?: string;
|
|
3505
|
+
}
|
|
3506
|
+
interface ExitBundleConflictReport {
|
|
3507
|
+
public_identity_exists: boolean;
|
|
3508
|
+
state_conflicts: Array<{
|
|
3509
|
+
namespace: string;
|
|
3510
|
+
key: string;
|
|
3511
|
+
}>;
|
|
3512
|
+
reputation_conflicts: string[];
|
|
3513
|
+
policy_set_exists: boolean;
|
|
3514
|
+
audit_receipts_exist: boolean;
|
|
3515
|
+
}
|
|
3516
|
+
interface ImportExitBundleResult {
|
|
3517
|
+
verified: boolean;
|
|
3518
|
+
activated: boolean;
|
|
3519
|
+
conflicts: ExitBundleConflictReport;
|
|
3520
|
+
state: {
|
|
3521
|
+
status: "not_requested" | "rekeyed" | "staged_requires_source_key" | "skipped_no_destination_signer";
|
|
3522
|
+
imported_keys: number;
|
|
3523
|
+
skipped_keys: number;
|
|
3524
|
+
skipped_invalid_sig: number;
|
|
3525
|
+
skipped_unknown_kid: number;
|
|
3526
|
+
conflicts: number;
|
|
3527
|
+
};
|
|
3528
|
+
reputation: {
|
|
3529
|
+
imported_attestations: number;
|
|
3530
|
+
invalid_attestations: number;
|
|
3531
|
+
unverifiable_attestations: number;
|
|
3532
|
+
};
|
|
3533
|
+
staged_artifacts: string[];
|
|
3534
|
+
warnings: string[];
|
|
3535
|
+
unsupported_artifacts: string[];
|
|
3536
|
+
}
|
|
3537
|
+
declare function exportExitBundle(opts: ExportExitBundleOptions): Promise<ExportExitBundleResult>;
|
|
3538
|
+
declare function importExitBundle(opts: ImportExitBundleOptions): Promise<ImportExitBundleResult>;
|
|
3539
|
+
declare function exitBundleManifestShape(): Record<string, unknown>;
|
|
3540
|
+
|
|
3541
|
+
/**
|
|
3542
|
+
* Sanctuary v1.1 exit-bundle verifier.
|
|
3543
|
+
*
|
|
3544
|
+
* Verifies the signed SANCTUARY_EXIT_BUNDLE_V1 manifest, every artifact hash,
|
|
3545
|
+
* and the exported identity / reputation signatures that are independently
|
|
3546
|
+
* verifiable from public material in the bundle.
|
|
3547
|
+
*/
|
|
3548
|
+
|
|
3549
|
+
interface ExitBundleDetailedVerifierResult extends ExitBundleVerifierResult {
|
|
3550
|
+
manifest_path: string;
|
|
3551
|
+
manifest_hash: string | null;
|
|
3552
|
+
warnings: string[];
|
|
3553
|
+
unsupported_artifacts: string[];
|
|
3554
|
+
identity?: {
|
|
3555
|
+
signature_valid: boolean;
|
|
3556
|
+
identity_id?: string;
|
|
3557
|
+
did?: string;
|
|
3558
|
+
};
|
|
3559
|
+
audit?: {
|
|
3560
|
+
receipt_count: number;
|
|
3561
|
+
individual_signatures_verified: boolean;
|
|
3562
|
+
};
|
|
3563
|
+
reputation?: {
|
|
3564
|
+
bundle_signature_valid: boolean | "unverifiable";
|
|
3565
|
+
attestation_count: number;
|
|
3566
|
+
verified_attestations: number;
|
|
3567
|
+
invalid_attestations: number;
|
|
3568
|
+
unverifiable_attestations: number;
|
|
3569
|
+
};
|
|
3570
|
+
}
|
|
3571
|
+
interface LoadedExitArtifact<T = unknown> {
|
|
3572
|
+
entry: ExitBundleArtifactEntry;
|
|
3573
|
+
path: string;
|
|
3574
|
+
json: T;
|
|
3575
|
+
bytes: Uint8Array;
|
|
3576
|
+
}
|
|
3577
|
+
declare function readManifest(bundleDir: string): Promise<ExitBundleManifest>;
|
|
3578
|
+
declare function loadExitArtifact<T = unknown>(bundleDir: string, manifest: ExitBundleManifest, kind: ExitBundleArtifactKind): Promise<LoadedExitArtifact<T> | null>;
|
|
3579
|
+
declare function verifyExitBundle(bundleDir: string): Promise<ExitBundleDetailedVerifierResult>;
|
|
3580
|
+
|
|
3581
|
+
/**
|
|
3582
|
+
* `sanctuary exit` CLI.
|
|
3583
|
+
*
|
|
3584
|
+
* Operator-facing export/import/verifier path for SANCTUARY_EXIT_BUNDLE_V1.
|
|
3585
|
+
* Dashboard wizard work consumes the same module APIs later.
|
|
3586
|
+
*/
|
|
3587
|
+
|
|
3588
|
+
interface ExitCommandArgs {
|
|
3589
|
+
argv: string[];
|
|
3590
|
+
out?: Writable;
|
|
3591
|
+
err?: Writable;
|
|
3592
|
+
stdin?: NodeJS.ReadableStream;
|
|
3593
|
+
env?: NodeJS.ProcessEnv;
|
|
3594
|
+
}
|
|
3595
|
+
declare function runExitCommand(args: ExitCommandArgs): Promise<number>;
|
|
3596
|
+
|
|
2723
3597
|
/**
|
|
2724
3598
|
* Sanctuary MCP Server — Principal Policy Loader
|
|
2725
3599
|
*
|
|
@@ -3631,6 +4505,12 @@ interface UpstreamServerStatus {
|
|
|
3631
4505
|
tool_count: number;
|
|
3632
4506
|
error?: string;
|
|
3633
4507
|
}
|
|
4508
|
+
interface PrivacySummary {
|
|
4509
|
+
filtered_events: number;
|
|
4510
|
+
filtered_spans: number;
|
|
4511
|
+
classes: Record<string, number>;
|
|
4512
|
+
last_filtered_at: string | null;
|
|
4513
|
+
}
|
|
3634
4514
|
interface ProtectionSnapshot {
|
|
3635
4515
|
overall: {
|
|
3636
4516
|
status: OverallStatus;
|
|
@@ -3647,6 +4527,7 @@ interface ProtectionSnapshot {
|
|
|
3647
4527
|
activity: ActivityEntry[];
|
|
3648
4528
|
pending_approvals: PendingApproval[];
|
|
3649
4529
|
audit: AuditEntry[];
|
|
4530
|
+
privacy: PrivacySummary;
|
|
3650
4531
|
upstream_servers: UpstreamServerStatus[];
|
|
3651
4532
|
mode: "co-located" | "standalone";
|
|
3652
4533
|
server_version: string;
|
|
@@ -3700,8 +4581,19 @@ interface ApprovalHandlers {
|
|
|
3700
4581
|
allow: (id: string) => Promise<boolean>;
|
|
3701
4582
|
deny: (id: string) => Promise<boolean>;
|
|
3702
4583
|
}
|
|
4584
|
+
/**
|
|
4585
|
+
* SSE event taxonomy.
|
|
4586
|
+
*
|
|
4587
|
+
* v1.0 event names: `snapshot` (initial hydration), `activity` (audit feed
|
|
4588
|
+
* append), `approval` (pending approval surfaced).
|
|
4589
|
+
*
|
|
4590
|
+
* v1.1 added: `inbox` (HubInboxItem replace-or-prepend by item_id) and
|
|
4591
|
+
* `agent_status` (HubAgentStatusSnapshot replace by agent_id). The hub
|
|
4592
|
+
* service emits these via the existing `publish` interface; the producer
|
|
4593
|
+
* wires every name verbatim through `event: <type>` SSE frames.
|
|
4594
|
+
*/
|
|
3703
4595
|
interface StreamEvent {
|
|
3704
|
-
type: "snapshot" | "activity" | "approval";
|
|
4596
|
+
type: "snapshot" | "activity" | "approval" | "inbox" | "agent_status";
|
|
3705
4597
|
data: unknown;
|
|
3706
4598
|
}
|
|
3707
4599
|
|
|
@@ -3739,6 +4631,18 @@ interface DashboardHandle {
|
|
|
3739
4631
|
publishActivity: (entry: ActivityEntry) => void;
|
|
3740
4632
|
/** Push a new pending approval (already added by the approval channel). */
|
|
3741
4633
|
publishApproval: (approval: PendingApproval) => void;
|
|
4634
|
+
/**
|
|
4635
|
+
* Push a v1.1 hub inbox item update. Producers (HubService) call this
|
|
4636
|
+
* on inbox writes (Tier 1 enqueue, Tier 1 resolve, source-pulled item
|
|
4637
|
+
* surfaced). Consumers replace-or-prepend by `item_id`.
|
|
4638
|
+
*/
|
|
4639
|
+
publishInbox: (item: unknown) => void;
|
|
4640
|
+
/**
|
|
4641
|
+
* Push a v1.1 per-agent status update. Producers call this when the
|
|
4642
|
+
* agent registry's `updateStatus` transitions. Consumers replace by
|
|
4643
|
+
* `agent_id`.
|
|
4644
|
+
*/
|
|
4645
|
+
publishAgentStatus: (snapshot: unknown) => void;
|
|
3742
4646
|
}
|
|
3743
4647
|
declare function startDashboardServer(options: DashboardServerOptions): Promise<DashboardHandle>;
|
|
3744
4648
|
|
|
@@ -3835,4 +4739,4 @@ declare function createSanctuaryServer(options?: {
|
|
|
3835
4739
|
storage?: StorageBackend;
|
|
3836
4740
|
}): Promise<SanctuaryServer>;
|
|
3837
4741
|
|
|
3838
|
-
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 };
|
|
4742
|
+
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 ExitAuditReceiptsArtifact, type ExitBundleDetailedVerifierResult, type ExitCommandArgs, type ExitCommitmentsArtifact, type ExitEncryptedStateBundle, type ExitPlaceholderVaultMetadataArtifact, type ExitPolicySetArtifact, type ExitPublicIdentityArtifact, type ExportExitBundleOptions, type ExportExitBundleResult, type FederationCapabilities, type FederationPeer, FederationRegistry, type FieldClassification, type FieldFilterResult, FilesystemStorage, type GateResult, HERO_COPY, type HandshakeChallenge, type HandshakeCompletion, type HandshakeResponse, type HandshakeResult, type ImportExitBundleOptions, type ImportExitBundleResult, InMemoryModelProvenanceStore, InjectionDetector, type InjectionDetectorConfig, type InjectionSignal, type L1Status, type L2Status, type L3Status, type L4Status, type LoadedExitArtifact, 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, exitBundleManifestShape, exportExitBundle, filterContext, generateAttestation, generateSHR, generateSystemPrompt, getProtectionSnapshot, getTemplate, importExitBundle, initiateHandshake, listTemplateIds, loadConfig, loadExitArtifact, loadPrincipalPolicy, readManifest, recommendPolicy, renderDashboardHTML, resolveTier, respondToHandshake, runExitCommand, signPayload, startDashboard, startDashboardServer, tierDistribution, verifyAttestation, verifyBridgeCommitment, verifyCompletion, verifyExitBundle, verifyPedersenCommitment, verifyProofOfKnowledge, verifyRangeProof, verifySHR, verifySignature };
|