enigma-memory 0.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/LICENSE +55 -0
- package/README.md +379 -0
- package/apps/cli/bin/enigma.mjs +1117 -0
- package/apps/desktop/src/app.js +1327 -0
- package/apps/desktop/src/index.html +1373 -0
- package/apps/desktop/src/styles.css +386 -0
- package/apps/gateway/bin/enigma-gateway.mjs +52 -0
- package/apps/gateway/src/server.mjs +1403 -0
- package/apps/native-host/README.md +265 -0
- package/apps/native-host/bin/enigma-native-host.mjs +499 -0
- package/apps/native-host/manifests/com.enigma.native_host.chrome.json +9 -0
- package/apps/native-host/manifests/com.enigma.native_host.edge.json +9 -0
- package/apps/native-host/manifests/com.enigma.native_host.firefox.json +9 -0
- package/apps/relay/bin/enigma-relay.mjs +52 -0
- package/apps/relay/src/server.mjs +1571 -0
- package/apps/verifier/bin/enigma-verify.mjs +240 -0
- package/deploy/docker-compose.production.example.yml +150 -0
- package/deploy/kubernetes/enigma-backend.example.yaml +580 -0
- package/package.json +196 -0
- package/packages/adapters/PACKAGE_CONTRACT.md +47 -0
- package/packages/adapters/src/index.js +183 -0
- package/packages/boundary/src/index.js +468 -0
- package/packages/connectors/src/index.js +533 -0
- package/packages/core/src/index.js +766 -0
- package/packages/enterprise/src/index.js +505 -0
- package/packages/importers/src/index.js +1083 -0
- package/packages/mcp-server/bin/enigma-mcp.mjs +19 -0
- package/packages/mcp-server/src/index.js +1185 -0
- package/packages/mesh/src/index.js +531 -0
- package/packages/metering/PACKAGE_CONTRACT.md +20 -0
- package/packages/metering/src/index.js +246 -0
- package/packages/optimizer/src/index.js +707 -0
- package/packages/passport/src/index.js +651 -0
- package/packages/settlement/PACKAGE_CONTRACT.md +28 -0
- package/packages/settlement/src/index.js +369 -0
- package/packages/storage/PACKAGE_CONTRACT.md +23 -0
- package/packages/storage/src/index.js +392 -0
- package/packages/vault/src/index.js +904 -0
- package/scripts/build-ai-orchestration-plan.mjs +248 -0
- package/scripts/build-cloudflare-pages-release-packet.mjs +287 -0
- package/scripts/build-cloudflare-token-policy.mjs +239 -0
- package/scripts/build-cloudflare-token-request.mjs +314 -0
- package/scripts/build-demo-assets.mjs +263 -0
- package/scripts/build-edge-backend-workers.mjs +353 -0
- package/scripts/build-goal-completion-audit.mjs +398 -0
- package/scripts/build-hosted-probe-worker.mjs +191 -0
- package/scripts/build-operator-acceptance-packet.mjs +254 -0
- package/scripts/build-operator-evidence-starter.mjs +525 -0
- package/scripts/build-production-backend-env-kit.mjs +384 -0
- package/scripts/build-production-dependency-report.mjs +369 -0
- package/scripts/build-production-handoff-packet.mjs +475 -0
- package/scripts/build-production-readiness-manifest.mjs +209 -0
- package/scripts/build-production-status-board.mjs +297 -0
- package/scripts/build-production-storage-migration.mjs +86 -0
- package/scripts/build-production-workplan.mjs +371 -0
- package/scripts/build-review-packet.mjs +594 -0
- package/scripts/check.mjs +419 -0
- package/scripts/cloudflare-ops.mjs +1672 -0
- package/scripts/cloudflare-secret-env.mjs +128 -0
- package/scripts/collect-hosted-backend-live-evidence.mjs +263 -0
- package/scripts/infrastructure-readiness.mjs +944 -0
- package/scripts/install-enigma-local.mjs +270 -0
- package/scripts/memory-optimization-benchmark.mjs +242 -0
- package/scripts/monitor-live-endpoints.mjs +358 -0
- package/scripts/release-audit.mjs +5588 -0
- package/scripts/release-provenance.mjs +250 -0
- package/scripts/run-backend-readiness-smoke.mjs +220 -0
- package/scripts/validate-backup-restore-drill.mjs +166 -0
- package/scripts/validate-cloudflare-credentials.mjs +112 -0
- package/scripts/validate-cloudflare-worker-inspect.mjs +179 -0
- package/scripts/validate-domain-tls.mjs +248 -0
- package/scripts/validate-hosted-backend-live.mjs +319 -0
- package/scripts/validate-incident-drill.mjs +221 -0
- package/scripts/validate-kms-custody.mjs +235 -0
- package/scripts/validate-legal-compliance-approval.mjs +274 -0
- package/scripts/validate-monitoring-alerting.mjs +263 -0
- package/scripts/validate-network-access-policy.mjs +285 -0
- package/scripts/validate-operator-acceptance.mjs +298 -0
- package/scripts/validate-production-manifests.mjs +325 -0
- package/scripts/validate-public-site-security.mjs +252 -0
- package/scripts/validate-security-threat-model.mjs +285 -0
- package/scripts/validate-service-settlement.mjs +256 -0
- package/scripts/validate-support-sla.mjs +190 -0
- package/scripts/validate-tenant-policy-approval.mjs +228 -0
- package/scripts/validate-usage-metering.mjs +224 -0
- package/scripts/validate-whitepaper-claims.mjs +166 -0
- package/specs/boundary-manifest-v1.schema.json +35 -0
- package/specs/capsule-v1.schema.json +55 -0
- package/specs/claim-boundary-manifest-v1.schema.json +22 -0
- package/specs/connector-profile-v1.schema.json +62 -0
- package/specs/deletion-tombstone-v1.schema.json +26 -0
- package/specs/enterprise-policy-v1.schema.json +59 -0
- package/specs/gateway-request-v1.schema.json +32 -0
- package/specs/goal-completion-audit-v1.schema.json +70 -0
- package/specs/hosted-backend-live-evidence-v1.schema.json +147 -0
- package/specs/import-report-v1.schema.json +214 -0
- package/specs/infrastructure-readiness-manifest-v1.schema.json +130 -0
- package/specs/memory-event-v1.schema.json +42 -0
- package/specs/mesh-node-v1.schema.json +126 -0
- package/specs/passport-v1.schema.json +50 -0
- package/specs/production-handoff-packet-v1.schema.json +149 -0
- package/specs/receipt-v1.schema.json +61 -0
- package/specs/relay-record-v1.schema.json +43 -0
- package/specs/state-checkpoint-v1.schema.json +37 -0
- package/specs/trust-bundle-v1.schema.json +56 -0
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
import { canonicalize, createMemoryAddress, sha256Hex } from '../../core/src/index.js';
|
|
2
|
+
|
|
3
|
+
const MANIFEST_SCHEMA = 'enigma.boundary_manifest.v1';
|
|
4
|
+
const DEFAULT_ACTION = 'fail_unknown';
|
|
5
|
+
const DEFAULT_CREATED_AT = '1970-01-01T00:00:00.000Z';
|
|
6
|
+
const DEFAULT_HMAC_KEY = 'enigma-boundary-local-proof-key';
|
|
7
|
+
const FACT_DOMAIN = 'enigma.boundary.fact.v1';
|
|
8
|
+
|
|
9
|
+
const SURFACES = Object.freeze([
|
|
10
|
+
'model_input',
|
|
11
|
+
'model_output',
|
|
12
|
+
'tool_args',
|
|
13
|
+
'tool_result',
|
|
14
|
+
'scratchpad',
|
|
15
|
+
'clipboard',
|
|
16
|
+
'memory_write',
|
|
17
|
+
'memory_read',
|
|
18
|
+
'rag_ingest',
|
|
19
|
+
'rag_retrieve',
|
|
20
|
+
'file_write',
|
|
21
|
+
'log',
|
|
22
|
+
'telemetry',
|
|
23
|
+
'browser_dom',
|
|
24
|
+
'mcp_resource',
|
|
25
|
+
'network',
|
|
26
|
+
'inter_agent',
|
|
27
|
+
'cache',
|
|
28
|
+
'human_approval'
|
|
29
|
+
]);
|
|
30
|
+
|
|
31
|
+
const CLASSIFICATIONS = Object.freeze([
|
|
32
|
+
'committed',
|
|
33
|
+
'blocked',
|
|
34
|
+
'declared_out_of_scope',
|
|
35
|
+
'broken',
|
|
36
|
+
'fail_closed'
|
|
37
|
+
]);
|
|
38
|
+
|
|
39
|
+
const SURFACE_SET = new Set(SURFACES);
|
|
40
|
+
const CLASSIFICATION_SET = new Set(CLASSIFICATIONS);
|
|
41
|
+
|
|
42
|
+
function assertPlainRecord(value, name) {
|
|
43
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
|
|
44
|
+
throw new TypeError(`${name} must be an object`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
function factCommitment(fact, { hmacKey = DEFAULT_HMAC_KEY, runId = 'boundary-sim', scenario = 'unspecified' } = {}) {
|
|
50
|
+
return createMemoryAddress({
|
|
51
|
+
secret: hmacKey,
|
|
52
|
+
namespace: FACT_DOMAIN,
|
|
53
|
+
subject_id: scenario,
|
|
54
|
+
value: { fact, runId },
|
|
55
|
+
prefix: 'boundary'
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function defaultBoundaryPaths() {
|
|
60
|
+
return [
|
|
61
|
+
{ path_id: 'model_input:committed', surface: 'model_input', classification: 'committed', coverage_receipt_required: true },
|
|
62
|
+
{ path_id: 'model_output:committed', surface: 'model_output', classification: 'committed', coverage_receipt_required: true },
|
|
63
|
+
{ path_id: 'tool_args:committed', surface: 'tool_args', classification: 'committed', coverage_receipt_required: true },
|
|
64
|
+
{ path_id: 'tool_result:raw', surface: 'tool_result', classification: 'broken', reason: 'Uninstrumented tool result can move exact facts without an Enigma receipt.' },
|
|
65
|
+
{ path_id: 'tool_result:committed', surface: 'tool_result', classification: 'committed', coverage_receipt_required: true },
|
|
66
|
+
{ path_id: 'scratchpad:raw', surface: 'scratchpad', classification: 'broken', reason: 'Uninstrumented scratchpad can carry exact facts outside the committed channel.' },
|
|
67
|
+
{ path_id: 'scratchpad:committed', surface: 'scratchpad', classification: 'committed', coverage_receipt_required: true },
|
|
68
|
+
{ path_id: 'clipboard:raw', surface: 'clipboard', classification: 'broken', reason: 'Uninstrumented clipboard can carry exact facts outside the committed channel.' },
|
|
69
|
+
{ path_id: 'clipboard:committed', surface: 'clipboard', classification: 'committed', coverage_receipt_required: true },
|
|
70
|
+
{ path_id: 'memory_write:committed', surface: 'memory_write', classification: 'committed', coverage_receipt_required: true },
|
|
71
|
+
{ path_id: 'memory_read:committed', surface: 'memory_read', classification: 'committed', coverage_receipt_required: true },
|
|
72
|
+
{ path_id: 'rag_ingest:blocked', surface: 'rag_ingest', classification: 'blocked', reason: 'Semantic/vector ingestion is not admitted by the exact boundary harness.' },
|
|
73
|
+
{ path_id: 'rag_retrieve:semantic', surface: 'rag_retrieve', classification: 'declared_out_of_scope', reason: 'Semantic/RAG paraphrase equivalence is outside exact CANP claims.' },
|
|
74
|
+
{ path_id: 'file_write:raw', surface: 'file_write', classification: 'broken', reason: 'File artifacts can leak exact facts unless routed through committed receipts.' },
|
|
75
|
+
{ path_id: 'log:raw', surface: 'log', classification: 'broken', reason: 'Logs can leak exact facts unless blocked or committed.' },
|
|
76
|
+
{ path_id: 'telemetry:blocked', surface: 'telemetry', classification: 'blocked', reason: 'Telemetry egress is denied for boundary canaries.' },
|
|
77
|
+
{ path_id: 'browser_dom:blocked', surface: 'browser_dom', classification: 'blocked', reason: 'Browser DOM injection is denied in the local harness.' },
|
|
78
|
+
{ path_id: 'mcp_resource:committed', surface: 'mcp_resource', classification: 'committed', coverage_receipt_required: true },
|
|
79
|
+
{ path_id: 'network:callback', surface: 'network', classification: 'broken', reason: 'Network callbacks can leak exact facts unless blocked or committed.' },
|
|
80
|
+
{ path_id: 'inter_agent:committed', surface: 'inter_agent', classification: 'committed', coverage_receipt_required: true },
|
|
81
|
+
{ path_id: 'cache:blocked', surface: 'cache', classification: 'blocked', reason: 'Cache side paths are denied in the local harness.' },
|
|
82
|
+
{ path_id: 'human_approval:committed', surface: 'human_approval', classification: 'committed', coverage_receipt_required: true }
|
|
83
|
+
];
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function normalizePath(path) {
|
|
87
|
+
assertPlainRecord(path, 'boundary path');
|
|
88
|
+
const out = {
|
|
89
|
+
path_id: String(path.path_id ?? ''),
|
|
90
|
+
surface: String(path.surface ?? ''),
|
|
91
|
+
classification: String(path.classification ?? '')
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
if (path.adapter !== undefined) out.adapter = String(path.adapter);
|
|
95
|
+
if (path.reason !== undefined) out.reason = String(path.reason);
|
|
96
|
+
if (path.coverage_receipt_required !== undefined) out.coverage_receipt_required = Boolean(path.coverage_receipt_required);
|
|
97
|
+
return out;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function createBoundaryManifest(options = {}) {
|
|
101
|
+
assertPlainRecord(options, 'options');
|
|
102
|
+
const systemId = String(options.systemId ?? options.system_id ?? 'local-boundary-sim');
|
|
103
|
+
const createdAt = String(options.createdAt ?? options.created_at ?? DEFAULT_CREATED_AT);
|
|
104
|
+
const paths = (options.paths ?? defaultBoundaryPaths()).map(normalizePath);
|
|
105
|
+
const manifestWithoutId = {
|
|
106
|
+
schema: MANIFEST_SCHEMA,
|
|
107
|
+
manifest_id: 'pending',
|
|
108
|
+
system_id: systemId,
|
|
109
|
+
created_at: createdAt,
|
|
110
|
+
paths,
|
|
111
|
+
default_action: DEFAULT_ACTION
|
|
112
|
+
};
|
|
113
|
+
const manifestId = String(options.manifestId ?? options.manifest_id ?? sha256Hex(canonicalize({ ...manifestWithoutId, manifest_id: '' })).slice(0, 24));
|
|
114
|
+
return { ...manifestWithoutId, manifest_id: manifestId };
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function verifyBoundaryManifest(manifest) {
|
|
118
|
+
const errors = [];
|
|
119
|
+
const warnings = [];
|
|
120
|
+
|
|
121
|
+
if (manifest === null || typeof manifest !== 'object' || Array.isArray(manifest)) {
|
|
122
|
+
return { ok: false, status: 'FAIL', errors: ['MANIFEST_NOT_OBJECT'], warnings, manifestHash: null };
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const allowedRoot = new Set(['schema', 'manifest_id', 'system_id', 'created_at', 'paths', 'default_action']);
|
|
126
|
+
for (const key of Object.keys(manifest)) {
|
|
127
|
+
if (!allowedRoot.has(key)) errors.push(`UNKNOWN_ROOT_PROPERTY:${key}`);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (manifest.schema !== MANIFEST_SCHEMA) errors.push('BAD_SCHEMA');
|
|
131
|
+
if (typeof manifest.manifest_id !== 'string' || manifest.manifest_id.length < 8) errors.push('BAD_MANIFEST_ID');
|
|
132
|
+
if (typeof manifest.system_id !== 'string' || manifest.system_id.length < 1) errors.push('BAD_SYSTEM_ID');
|
|
133
|
+
if (typeof manifest.created_at !== 'string' || Number.isNaN(Date.parse(manifest.created_at))) errors.push('BAD_CREATED_AT');
|
|
134
|
+
if (manifest.default_action !== DEFAULT_ACTION) errors.push('DEFAULT_ACTION_MUST_FAIL_UNKNOWN');
|
|
135
|
+
if (!Array.isArray(manifest.paths) || manifest.paths.length === 0) errors.push('PATHS_REQUIRED');
|
|
136
|
+
|
|
137
|
+
const seenIds = new Set();
|
|
138
|
+
const coveredSurfaces = new Set();
|
|
139
|
+
let hasBroken = false;
|
|
140
|
+
let hasOutOfScope = false;
|
|
141
|
+
|
|
142
|
+
if (Array.isArray(manifest.paths)) {
|
|
143
|
+
for (const [index, path] of manifest.paths.entries()) {
|
|
144
|
+
if (path === null || typeof path !== 'object' || Array.isArray(path)) {
|
|
145
|
+
errors.push(`PATH_NOT_OBJECT:${index}`);
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const allowedPath = new Set(['path_id', 'surface', 'classification', 'adapter', 'reason', 'coverage_receipt_required']);
|
|
150
|
+
for (const key of Object.keys(path)) {
|
|
151
|
+
if (!allowedPath.has(key)) errors.push(`UNKNOWN_PATH_PROPERTY:${index}:${key}`);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (typeof path.path_id !== 'string' || path.path_id.length < 1) errors.push(`BAD_PATH_ID:${index}`);
|
|
155
|
+
else if (seenIds.has(path.path_id)) errors.push(`DUPLICATE_PATH_ID:${path.path_id}`);
|
|
156
|
+
else seenIds.add(path.path_id);
|
|
157
|
+
|
|
158
|
+
if (!SURFACE_SET.has(path.surface)) errors.push(`UNKNOWN_SURFACE:${path.path_id ?? index}`);
|
|
159
|
+
else coveredSurfaces.add(path.surface);
|
|
160
|
+
|
|
161
|
+
if (!CLASSIFICATION_SET.has(path.classification)) errors.push(`UNKNOWN_CLASSIFICATION:${path.path_id ?? index}`);
|
|
162
|
+
if (path.classification === 'broken' || path.classification === 'fail_closed') hasBroken = true;
|
|
163
|
+
if (path.classification === 'declared_out_of_scope') hasOutOfScope = true;
|
|
164
|
+
if (path.coverage_receipt_required !== undefined && typeof path.coverage_receipt_required !== 'boolean') {
|
|
165
|
+
errors.push(`BAD_COVERAGE_RECEIPT_REQUIRED:${path.path_id ?? index}`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
for (const surface of SURFACES) {
|
|
171
|
+
if (!coveredSurfaces.has(surface)) errors.push(`MISSING_SURFACE:${surface}`);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (hasBroken) warnings.push('BROKEN_PATH_DECLARED');
|
|
175
|
+
if (hasOutOfScope) warnings.push('OUT_OF_SCOPE_PATH_DECLARED');
|
|
176
|
+
|
|
177
|
+
const manifestHash = errors.length === 0 ? sha256Hex(canonicalize(manifest)) : null;
|
|
178
|
+
const status = errors.length > 0 || hasBroken ? 'FAIL' : hasOutOfScope ? 'NARROW_GO' : 'PASS';
|
|
179
|
+
return { ok: errors.length === 0, status, errors, warnings, manifestHash };
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export function classifyBoundaryPath(manifest, pathRef) {
|
|
183
|
+
const verification = verifyBoundaryManifest(manifest);
|
|
184
|
+
if (!verification.ok) {
|
|
185
|
+
return {
|
|
186
|
+
known: false,
|
|
187
|
+
classification: 'fail_closed',
|
|
188
|
+
fail_closed: true,
|
|
189
|
+
canp: 'UNKNOWN_BOUNDARY',
|
|
190
|
+
verdict: 'FAIL',
|
|
191
|
+
reason: verification.errors.includes('MANIFEST_NOT_OBJECT') ? 'MISSING_OR_INVALID_MANIFEST' : 'INVALID_MANIFEST',
|
|
192
|
+
manifestErrors: verification.errors
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const ref = typeof pathRef === 'string' ? { path_id: pathRef } : pathRef;
|
|
197
|
+
if (ref === null || typeof ref !== 'object' || Array.isArray(ref)) {
|
|
198
|
+
return {
|
|
199
|
+
known: false,
|
|
200
|
+
classification: 'fail_closed',
|
|
201
|
+
fail_closed: true,
|
|
202
|
+
canp: 'UNKNOWN_BOUNDARY',
|
|
203
|
+
verdict: 'FAIL',
|
|
204
|
+
reason: 'BAD_PATH_REF'
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const hasPathId = typeof ref.path_id === 'string' && ref.path_id.length > 0;
|
|
209
|
+
const hasSurface = typeof ref.surface === 'string' && ref.surface.length > 0;
|
|
210
|
+
let matches = [];
|
|
211
|
+
|
|
212
|
+
if (hasPathId) {
|
|
213
|
+
matches = manifest.paths.filter((path) => path.path_id === ref.path_id);
|
|
214
|
+
if (matches.length !== 1) {
|
|
215
|
+
return {
|
|
216
|
+
known: false,
|
|
217
|
+
classification: 'fail_closed',
|
|
218
|
+
fail_closed: true,
|
|
219
|
+
canp: 'UNKNOWN_BOUNDARY',
|
|
220
|
+
verdict: 'FAIL',
|
|
221
|
+
reason: matches.length === 0 ? 'UNCLASSIFIED_PATH' : 'AMBIGUOUS_PATH'
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
if (hasSurface && matches[0].surface !== ref.surface) {
|
|
225
|
+
return {
|
|
226
|
+
known: false,
|
|
227
|
+
classification: 'fail_closed',
|
|
228
|
+
fail_closed: true,
|
|
229
|
+
canp: 'UNKNOWN_BOUNDARY',
|
|
230
|
+
verdict: 'FAIL',
|
|
231
|
+
reason: 'AMBIGUOUS_PATH'
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
} else if (hasSurface) {
|
|
235
|
+
matches = manifest.paths.filter((path) => path.surface === ref.surface);
|
|
236
|
+
if (matches.length !== 1) {
|
|
237
|
+
return {
|
|
238
|
+
known: false,
|
|
239
|
+
classification: 'fail_closed',
|
|
240
|
+
fail_closed: true,
|
|
241
|
+
canp: 'UNKNOWN_BOUNDARY',
|
|
242
|
+
verdict: 'FAIL',
|
|
243
|
+
reason: matches.length === 0 ? 'UNCLASSIFIED_PATH' : 'AMBIGUOUS_PATH'
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
} else {
|
|
247
|
+
return {
|
|
248
|
+
known: false,
|
|
249
|
+
classification: 'fail_closed',
|
|
250
|
+
fail_closed: true,
|
|
251
|
+
canp: 'UNKNOWN_BOUNDARY',
|
|
252
|
+
verdict: 'FAIL',
|
|
253
|
+
reason: 'BAD_PATH_REF'
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const [path] = matches;
|
|
258
|
+
const canpByClassification = {
|
|
259
|
+
committed: 'COMMITTED_PATH',
|
|
260
|
+
blocked: 'BLOCKED_PATH',
|
|
261
|
+
declared_out_of_scope: 'OUT_OF_SCOPE',
|
|
262
|
+
broken: 'BROKEN_PATH',
|
|
263
|
+
fail_closed: 'UNKNOWN_BOUNDARY'
|
|
264
|
+
};
|
|
265
|
+
const verdictByClassification = {
|
|
266
|
+
committed: 'PASS',
|
|
267
|
+
blocked: 'PASS',
|
|
268
|
+
declared_out_of_scope: 'NARROW_GO',
|
|
269
|
+
broken: 'FAIL',
|
|
270
|
+
fail_closed: 'FAIL'
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
return {
|
|
274
|
+
known: true,
|
|
275
|
+
fail_closed: path.classification === 'broken' || path.classification === 'fail_closed',
|
|
276
|
+
path,
|
|
277
|
+
classification: path.classification,
|
|
278
|
+
canp: canpByClassification[path.classification],
|
|
279
|
+
verdict: verdictByClassification[path.classification],
|
|
280
|
+
reason: path.reason ?? null
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function scenarioDefinitions() {
|
|
285
|
+
return [
|
|
286
|
+
{
|
|
287
|
+
scenario: 'control never sent',
|
|
288
|
+
pathId: 'model_input:committed',
|
|
289
|
+
fact: 'control-boundary-canary',
|
|
290
|
+
bGotVia: 'none',
|
|
291
|
+
committed: false
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
scenario: 'honest committed crossing',
|
|
295
|
+
pathId: 'model_input:committed',
|
|
296
|
+
fact: 'honest-committed-canary',
|
|
297
|
+
bGotVia: 'committed_channel',
|
|
298
|
+
committed: true
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
scenario: 'scratchpad leak',
|
|
302
|
+
pathId: 'scratchpad:raw',
|
|
303
|
+
fact: 'scratchpad-leak-canary',
|
|
304
|
+
bGotVia: 'scratchpad',
|
|
305
|
+
committed: false
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
scenario: 'tool-output leak',
|
|
309
|
+
pathId: 'tool_result:raw',
|
|
310
|
+
fact: 'tool-output-leak-canary',
|
|
311
|
+
bGotVia: 'tool_result',
|
|
312
|
+
committed: false
|
|
313
|
+
},
|
|
314
|
+
{
|
|
315
|
+
scenario: 'clipboard leak',
|
|
316
|
+
pathId: 'clipboard:raw',
|
|
317
|
+
fact: 'clipboard-leak-canary',
|
|
318
|
+
bGotVia: 'clipboard',
|
|
319
|
+
committed: false
|
|
320
|
+
},
|
|
321
|
+
{
|
|
322
|
+
scenario: 'log leak',
|
|
323
|
+
pathId: 'log:raw',
|
|
324
|
+
fact: 'log-leak-canary',
|
|
325
|
+
bGotVia: 'log',
|
|
326
|
+
committed: false
|
|
327
|
+
},
|
|
328
|
+
{
|
|
329
|
+
scenario: 'file artifact leak',
|
|
330
|
+
pathId: 'file_write:raw',
|
|
331
|
+
fact: 'file-artifact-leak-canary',
|
|
332
|
+
bGotVia: 'file_artifact',
|
|
333
|
+
committed: false
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
scenario: 'network callback leak',
|
|
337
|
+
pathId: 'network:callback',
|
|
338
|
+
fact: 'network-callback-leak-canary',
|
|
339
|
+
bGotVia: 'network_callback',
|
|
340
|
+
committed: false
|
|
341
|
+
},
|
|
342
|
+
{
|
|
343
|
+
scenario: 'mitigated scratchpad route-through-channel',
|
|
344
|
+
pathId: 'scratchpad:committed',
|
|
345
|
+
fact: 'mitigated-scratchpad-canary',
|
|
346
|
+
bGotVia: 'scratchpad_via_committed_channel',
|
|
347
|
+
committed: true
|
|
348
|
+
},
|
|
349
|
+
{
|
|
350
|
+
scenario: 'mitigated clipboard route-through-channel',
|
|
351
|
+
pathId: 'clipboard:committed',
|
|
352
|
+
fact: 'mitigated-clipboard-canary',
|
|
353
|
+
bGotVia: 'clipboard_via_committed_channel',
|
|
354
|
+
committed: true
|
|
355
|
+
},
|
|
356
|
+
{
|
|
357
|
+
scenario: 'mitigated tool route-through-channel',
|
|
358
|
+
pathId: 'tool_result:committed',
|
|
359
|
+
fact: 'mitigated-tool-canary',
|
|
360
|
+
bGotVia: 'tool_result_via_committed_channel',
|
|
361
|
+
committed: true
|
|
362
|
+
},
|
|
363
|
+
{
|
|
364
|
+
scenario: 'unknown provider route',
|
|
365
|
+
pathId: 'provider_native:tool_result',
|
|
366
|
+
fact: 'unknown-provider-route-canary',
|
|
367
|
+
bGotVia: 'provider_native_tool',
|
|
368
|
+
committed: false
|
|
369
|
+
},
|
|
370
|
+
{
|
|
371
|
+
scenario: 'ambiguous tool surface route',
|
|
372
|
+
pathId: 'tool_result:*',
|
|
373
|
+
pathRef: { surface: 'tool_result' },
|
|
374
|
+
fact: 'ambiguous-tool-surface-canary',
|
|
375
|
+
bGotVia: 'tool_surface',
|
|
376
|
+
committed: false
|
|
377
|
+
},
|
|
378
|
+
{
|
|
379
|
+
scenario: 'semantic/RAG paraphrase declared out-of-scope',
|
|
380
|
+
pathId: 'rag_retrieve:semantic',
|
|
381
|
+
fact: 'semantic-rag-paraphrase-canary',
|
|
382
|
+
bGotVia: 'rag_paraphrase',
|
|
383
|
+
committed: false,
|
|
384
|
+
semantic: true
|
|
385
|
+
}
|
|
386
|
+
];
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
function evaluateScenario(manifest, scenario, options) {
|
|
390
|
+
const pathRef = scenario.pathRef ?? scenario.pathId;
|
|
391
|
+
const classification = classifyBoundaryPath(manifest, pathRef);
|
|
392
|
+
const address = factCommitment(scenario.fact, { hmacKey: options.hmacKey, runId: options.runId, scenario: scenario.scenario });
|
|
393
|
+
const bHasFact = scenario.bGotVia !== 'none';
|
|
394
|
+
const committedSet = new Set(scenario.committed ? [address] : []);
|
|
395
|
+
const crossedCommittedChannel = committedSet.has(address);
|
|
396
|
+
|
|
397
|
+
let canp;
|
|
398
|
+
let verdict;
|
|
399
|
+
|
|
400
|
+
if (!classification.known) {
|
|
401
|
+
canp = 'UNKNOWN_BOUNDARY';
|
|
402
|
+
verdict = 'FAIL';
|
|
403
|
+
} else if (classification.classification === 'declared_out_of_scope') {
|
|
404
|
+
canp = 'OUT_OF_SCOPE';
|
|
405
|
+
verdict = 'NARROW_GO';
|
|
406
|
+
} else if (classification.classification === 'blocked') {
|
|
407
|
+
canp = bHasFact ? 'FALSE_ASSURANCE' : 'BLOCKED';
|
|
408
|
+
verdict = bHasFact ? 'FAIL' : 'PASS';
|
|
409
|
+
} else if (crossedCommittedChannel) {
|
|
410
|
+
canp = 'CROSSED';
|
|
411
|
+
verdict = 'PASS';
|
|
412
|
+
} else if (bHasFact) {
|
|
413
|
+
canp = 'FALSE_ASSURANCE';
|
|
414
|
+
verdict = 'FAIL';
|
|
415
|
+
} else {
|
|
416
|
+
canp = 'NEVER_CROSSED_COMMITTED_CHANNEL';
|
|
417
|
+
verdict = 'PASS';
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
return {
|
|
421
|
+
row: {
|
|
422
|
+
scenario: scenario.scenario,
|
|
423
|
+
pathId: scenario.pathId,
|
|
424
|
+
bGotVia: scenario.bGotVia,
|
|
425
|
+
classification: classification.classification,
|
|
426
|
+
failClosed: verdict === 'FAIL' || classification.fail_closed === true,
|
|
427
|
+
canp,
|
|
428
|
+
verdict,
|
|
429
|
+
reason: classification.reason
|
|
430
|
+
},
|
|
431
|
+
commitment: {
|
|
432
|
+
scenario: scenario.scenario,
|
|
433
|
+
fact_address: address,
|
|
434
|
+
path_id: scenario.pathId
|
|
435
|
+
}
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
export function runBoundarySimulation(options = {}) {
|
|
440
|
+
assertPlainRecord(options, 'options');
|
|
441
|
+
const runId = String(options.runId ?? options.run_id ?? 'boundary-sim-local');
|
|
442
|
+
const hmacKey = String(options.hmacKey ?? options.hmac_key ?? DEFAULT_HMAC_KEY);
|
|
443
|
+
const manifest = Object.prototype.hasOwnProperty.call(options, 'manifest') ? options.manifest : createBoundaryManifest({ systemId: options.systemId, createdAt: options.createdAt });
|
|
444
|
+
const manifestVerification = verifyBoundaryManifest(manifest);
|
|
445
|
+
const scenarios = options.scenarios ?? scenarioDefinitions();
|
|
446
|
+
const evaluated = scenarios.map((scenario) => evaluateScenario(manifest, scenario, { hmacKey, runId }));
|
|
447
|
+
const rows = evaluated.map((item) => item.row);
|
|
448
|
+
const commitments = evaluated.map((item) => item.commitment);
|
|
449
|
+
|
|
450
|
+
let status = 'PASS';
|
|
451
|
+
if (!manifestVerification.ok || rows.some((row) => row.verdict === 'FAIL')) status = 'FAIL';
|
|
452
|
+
else if (rows.some((row) => row.verdict === 'NARROW_GO') || manifestVerification.status === 'NARROW_GO') status = 'NARROW_GO';
|
|
453
|
+
|
|
454
|
+
return {
|
|
455
|
+
schema: 'enigma.boundary_simulation.v1',
|
|
456
|
+
run_id: runId,
|
|
457
|
+
manifest_hash: manifestVerification.manifestHash,
|
|
458
|
+
manifest_status: manifestVerification.status,
|
|
459
|
+
rows,
|
|
460
|
+
status,
|
|
461
|
+
finalStatus: status,
|
|
462
|
+
commitments,
|
|
463
|
+
honesty_text: 'This report proves exact facts about declared Enigma-instrumented paths. It does not prove provider deletion, model forgetting, semantic forgetting, model-weight deletion, or absence of uninstrumented provider-internal side channels.'
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
export const boundarySurfaces = SURFACES;
|
|
468
|
+
export const boundaryClassifications = CLASSIFICATIONS;
|