enigma-memory 0.1.11 → 0.1.13
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/README.md +8 -0
- package/apps/cli/bin/enigma.mjs +362 -10
- package/deploy/SIMULATION.md +152 -0
- package/deploy/docker-compose.local-production-simulation.yml +237 -0
- package/deploy/docker-compose.production.example.yml +19 -0
- package/deploy/kms-mock.mjs +64 -0
- package/deploy/nginx.local-production-simulation.conf +33 -0
- package/deploy/siem-mock.mjs +50 -0
- package/docs/benchmark-attestation-network.md +488 -0
- package/docs/benchmark-reproducibility.md +19 -2
- package/docs/blockchain-only-mechanisms.md +388 -0
- package/docs/client-connectors.md +512 -0
- package/docs/demo-proof-network.md +275 -0
- package/docs/developer-ecosystem.md +47 -4
- package/docs/developer-proof-quickstart.md +325 -0
- package/docs/enigma-memory-ready-conformance.md +376 -0
- package/docs/enterprise-proof-control-plane.md +365 -0
- package/docs/install-anywhere.md +517 -0
- package/docs/market-category-narrative.md +398 -0
- package/docs/memory-drive-health-model.md +649 -0
- package/docs/memory-drive-strategy.md +458 -0
- package/docs/memory-passport-standard.md +445 -0
- package/docs/novelty-invention-candidates.md +161 -0
- package/docs/privacy-ledger-model.md +229 -0
- package/docs/proof-network-build-notes.md +240 -0
- package/docs/proof-network-claim-boundaries.md +318 -0
- package/docs/proof-network-dashboard-spec.md +773 -0
- package/docs/proof-network-glossary.md +27 -0
- package/docs/proof-network-launch-plan.md +421 -0
- package/docs/proof-network-operator-protocol.md +432 -0
- package/docs/proof-network-roadmap.md +431 -0
- package/docs/proof-network-test-plan.md +216 -0
- package/docs/proof-network-threat-model.md +373 -0
- package/docs/proof-network.md +257 -0
- package/docs/sdk-api.md +132 -10
- package/docs/solana-devnet-acceptance.md +226 -0
- package/docs/solana-proof-rail.md +453 -0
- package/examples/ci/github-actions.yml +6 -3
- package/examples/proof-network-anchor.json +37 -0
- package/examples/proof-network-attestation.json +35 -0
- package/examples/proof-network-grant.json +27 -0
- package/examples/proof-network-packet.json +71 -0
- package/package.json +42 -3
- package/packages/mcp-server/src/index.js +1 -1
- package/packages/proof-network/src/index.js +570 -0
- package/scripts/build-hosted-api-key-lifecycle.mjs +1 -1
- package/scripts/build-hosted-customer-lifecycle.mjs +1 -1
- package/scripts/build-installer-assets.mjs +1 -1
- package/scripts/build-proof-network-packet.mjs +213 -0
- package/scripts/run-standard-memory-benchmarks.mjs +1 -1
- package/scripts/simulate-production-env.mjs +210 -0
- package/scripts/verify-registry-install.mjs +1 -0
- package/scripts/wait-for-backend-ready.mjs +101 -0
- package/specs/goal-completion-audit-v1.schema.json +1 -0
- package/specs/proof-network-anchor-batch-v1.schema.json +125 -0
- package/specs/proof-network-benchmark-attestation-v1.schema.json +103 -0
- package/specs/proof-network-capability-grant-v1.schema.json +132 -0
- package/specs/proof-network-packet-v1.schema.json +171 -0
package/README.md
CHANGED
|
@@ -31,6 +31,14 @@ enigma setup --connect-installed --overwrite
|
|
|
31
31
|
|
|
32
32
|
`--connect-installed` is the explicit client-config write path. It skips missing client configs instead of creating every default client config.
|
|
33
33
|
|
|
34
|
+
## Enigma Proof Network
|
|
35
|
+
|
|
36
|
+
Enigma Proof Network is the public proof layer for AI memory: local tools can package privacy-preserving roots, refs, counts, signatures, scoped capability grants, revocations, and benchmark attestations without exposing raw memory, prompts, transcripts, completions, embeddings, tenant names, private keys, provider responses, or provider credentials.
|
|
37
|
+
|
|
38
|
+
The `enigma chain anchor|grant|revoke|attest|verify` commands are local planning and verification commands. They emit public-safe JSON with `transaction_submitted:false` and `raw_memory_on_chain:false`; they do not submit Solana transactions, deploy hosted SaaS, create accounts, or call external providers.
|
|
39
|
+
|
|
40
|
+
Start with the category narrative in [`docs/market-category-narrative.md`](docs/market-category-narrative.md), then read the technical overview in [`docs/proof-network.md`](docs/proof-network.md), use its [Solana role](docs/proof-network.md#solana-role) section for the Solana-ready anchoring boundary, and read [`docs/proof-network-faq.md`](docs/proof-network-faq.md) for claim boundaries.
|
|
41
|
+
|
|
34
42
|
## Install once, use everywhere
|
|
35
43
|
|
|
36
44
|
Prerequisites:
|
package/apps/cli/bin/enigma.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createHash } from 'node:crypto';
|
|
3
3
|
import { createServer as createHttpServer } from 'node:http';
|
|
4
|
-
import { realpathSync } from 'node:fs';
|
|
5
|
-
import { access, mkdir, readFile, readdir, writeFile } from 'node:fs/promises';
|
|
4
|
+
import { constants as fsConstants, realpathSync } from 'node:fs';
|
|
5
|
+
import { access, mkdir, readFile, readdir, stat, writeFile } from 'node:fs/promises';
|
|
6
6
|
import { dirname, isAbsolute, join, resolve } from 'node:path';
|
|
7
7
|
import { pathToFileURL } from 'node:url';
|
|
8
8
|
import { createVault, remember, recall, updateMemory, deleteMemory, exportBundle } from '../../../packages/vault/src/index.js';
|
|
@@ -30,6 +30,19 @@ import {
|
|
|
30
30
|
createSettlementBatch,
|
|
31
31
|
verifyServiceSettlementReceipt,
|
|
32
32
|
} from '../../../packages/settlement/src/index.js';
|
|
33
|
+
import {
|
|
34
|
+
assertNoPrivateProofPayload,
|
|
35
|
+
createBenchmarkAttestation,
|
|
36
|
+
createCapabilityGrant,
|
|
37
|
+
createCapabilityRevocation,
|
|
38
|
+
createProofNetworkAnchorBatch,
|
|
39
|
+
sha256Json as proofNetworkSha256Json,
|
|
40
|
+
validateBenchmarkAttestation,
|
|
41
|
+
validateCapabilityGrant,
|
|
42
|
+
validateCapabilityRevocation,
|
|
43
|
+
validateProofNetworkAnchorBatch,
|
|
44
|
+
validateProofNetworkPacket,
|
|
45
|
+
} from '../../../packages/proof-network/src/index.js';
|
|
33
46
|
|
|
34
47
|
const DEFAULT_BUNDLE = '.enigma/bundle.json';
|
|
35
48
|
const DEFAULT_TEST_DRIVE_DIR = '.enigma/test-drive';
|
|
@@ -561,6 +574,86 @@ function minimumNodeMajor(range) {
|
|
|
561
574
|
return match ? Number(match[1]) : 0;
|
|
562
575
|
}
|
|
563
576
|
|
|
577
|
+
function npmUserAgentCheck(userAgent = process.env.npm_config_user_agent) {
|
|
578
|
+
const raw = typeof userAgent === 'string' ? userAgent.trim() : '';
|
|
579
|
+
const npmToken = raw.split(/\s+/).find((token) => token.startsWith('npm/'));
|
|
580
|
+
const version = npmToken ? npmToken.slice(4) : null;
|
|
581
|
+
return {
|
|
582
|
+
ok: true,
|
|
583
|
+
detected: version !== null,
|
|
584
|
+
name: version === null ? null : 'npm',
|
|
585
|
+
version,
|
|
586
|
+
source: version === null ? null : 'npm_config_user_agent',
|
|
587
|
+
};
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
async function statIfExists(path) {
|
|
591
|
+
try {
|
|
592
|
+
return await stat(path);
|
|
593
|
+
} catch (error) {
|
|
594
|
+
if (error?.code === 'ENOENT' || error?.code === 'ENOTDIR') return null;
|
|
595
|
+
throw error;
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
async function nearestExistingAncestor(path) {
|
|
600
|
+
let current = resolve(path);
|
|
601
|
+
for (;;) {
|
|
602
|
+
const stats = await statIfExists(current);
|
|
603
|
+
if (stats !== null) return { path: current, stats };
|
|
604
|
+
const parent = dirname(current);
|
|
605
|
+
if (parent === current) return null;
|
|
606
|
+
current = parent;
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
function publicParentDisplay(path, label) {
|
|
611
|
+
const value = String(path);
|
|
612
|
+
if (/^<[^>]+>$/.test(value)) return `<${label}>`;
|
|
613
|
+
const parent = dirname(value);
|
|
614
|
+
return parent === '' ? '.' : publicPathDisplay(parent, label);
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
async function writableVaultPathCheck(bundleInput, displayInput = bundleInput) {
|
|
618
|
+
const bundlePath = resolve(String(bundleInput));
|
|
619
|
+
const parentPath = dirname(bundlePath);
|
|
620
|
+
const targetStats = await statIfExists(bundlePath);
|
|
621
|
+
const nearest = await nearestExistingAncestor(parentPath);
|
|
622
|
+
let ok = false;
|
|
623
|
+
let reason = null;
|
|
624
|
+
let parentExists = false;
|
|
625
|
+
let nearestExistingParent = null;
|
|
626
|
+
if (targetStats?.isDirectory()) {
|
|
627
|
+
reason = 'target_is_directory';
|
|
628
|
+
} else if (nearest === null) {
|
|
629
|
+
reason = 'no_existing_parent';
|
|
630
|
+
} else if (!nearest.stats.isDirectory()) {
|
|
631
|
+
reason = 'nearest_parent_not_directory';
|
|
632
|
+
nearestExistingParent = '<existing-parent-path>';
|
|
633
|
+
} else {
|
|
634
|
+
parentExists = nearest.path === parentPath;
|
|
635
|
+
nearestExistingParent = parentExists ? publicParentDisplay(displayInput, 'bundle-dir') : '<existing-parent-dir>';
|
|
636
|
+
try {
|
|
637
|
+
await access(nearest.path, fsConstants.W_OK);
|
|
638
|
+
ok = true;
|
|
639
|
+
} catch {
|
|
640
|
+
reason = 'parent_not_writable';
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
return {
|
|
644
|
+
ok,
|
|
645
|
+
path: publicPathDisplay(displayInput, 'bundle-path'),
|
|
646
|
+
parent: publicParentDisplay(displayInput, 'bundle-dir'),
|
|
647
|
+
parent_exists: parentExists,
|
|
648
|
+
nearest_existing_parent: nearestExistingParent,
|
|
649
|
+
target_exists: targetStats !== null,
|
|
650
|
+
target_is_directory: targetStats?.isDirectory() === true,
|
|
651
|
+
writable: ok,
|
|
652
|
+
reason,
|
|
653
|
+
hint: ok ? null : 'Choose a writable --bundle path or create a writable parent directory.',
|
|
654
|
+
};
|
|
655
|
+
}
|
|
656
|
+
|
|
564
657
|
async function schemaFiles() {
|
|
565
658
|
return (await readdir(SPECS_URL)).filter((name) => name.endsWith('.schema.json')).sort();
|
|
566
659
|
}
|
|
@@ -895,10 +988,19 @@ function setupNextCommands(bundleInput, exportDisplay, clients, writeConnectors)
|
|
|
895
988
|
`enigma context --bundle ${commandPath(bundleInput)} --query "project context"`,
|
|
896
989
|
`enigma verify --export ${commandPath(exportDisplay)}`,
|
|
897
990
|
];
|
|
898
|
-
if (!writeConnectors) commands.push(`enigma connect ${primaryClient} --bundle ${commandPath(bundleInput)}`);
|
|
991
|
+
if (!writeConnectors) commands.push(`enigma connect ${primaryClient} --bundle ${commandPath(bundleInput)} --dry-run`);
|
|
899
992
|
return commands;
|
|
900
993
|
}
|
|
901
994
|
|
|
995
|
+
function doctorNextCommands(bundleDisplay, client) {
|
|
996
|
+
const clientId = client ?? DEFAULT_SETUP_CLIENTS[0];
|
|
997
|
+
return [
|
|
998
|
+
`enigma setup --bundle ${commandPath(bundleDisplay)}`,
|
|
999
|
+
`enigma doctor --bundle ${commandPath(bundleDisplay)} --client ${clientId}`,
|
|
1000
|
+
`enigma connect ${clientId} --bundle ${commandPath(bundleDisplay)}`,
|
|
1001
|
+
];
|
|
1002
|
+
}
|
|
1003
|
+
|
|
902
1004
|
async function setupDoctorChecks(flags, artifacts, clients, displays) {
|
|
903
1005
|
const packageJson = await readPackageJson();
|
|
904
1006
|
const requiredNodeMajor = minimumNodeMajor(packageJson.engines?.node);
|
|
@@ -925,12 +1027,15 @@ async function setupDoctorChecks(flags, artifacts, clients, displays) {
|
|
|
925
1027
|
const doctor = await doctorConnectors({ ...connectorBaseOptions, clientId: client });
|
|
926
1028
|
connectorClients.push(...doctor.clients);
|
|
927
1029
|
}
|
|
1030
|
+
const vaultPath = await writableVaultPathCheck(artifacts.bundlePath, displays.bundle);
|
|
928
1031
|
const checks = {
|
|
929
1032
|
node: {
|
|
930
1033
|
ok: requiredNodeMajor === 0 || currentNodeMajor >= requiredNodeMajor,
|
|
931
1034
|
current: process.versions.node,
|
|
932
1035
|
required: packageJson.engines?.node ?? null,
|
|
933
1036
|
},
|
|
1037
|
+
npm: npmUserAgentCheck(),
|
|
1038
|
+
vault_path: vaultPath,
|
|
934
1039
|
package_bins: {
|
|
935
1040
|
ok: binEntries.every((entry) => entry.declared && entry.exists),
|
|
936
1041
|
required: REQUIRED_PACKAGE_BINS,
|
|
@@ -1518,7 +1623,7 @@ function testDriveNextCommands(bundleDisplay, crossModelReportDisplay) {
|
|
|
1518
1623
|
`enigma status --bundle ${quotedBundle}`,
|
|
1519
1624
|
`enigma search --bundle ${quotedBundle} --query "local proof bundle"`,
|
|
1520
1625
|
`enigma demo cross-model --bundle ${quotedBundle} --out ${quotedReport}`,
|
|
1521
|
-
'
|
|
1626
|
+
'enigma setup --overwrite',
|
|
1522
1627
|
];
|
|
1523
1628
|
}
|
|
1524
1629
|
|
|
@@ -1723,7 +1828,7 @@ export async function testDriveCommand(flags, io) {
|
|
|
1723
1828
|
out_dir: outDirInput,
|
|
1724
1829
|
bundle: bundleInput,
|
|
1725
1830
|
install_command: `npm install -g ${packageJson.name ?? 'enigma-memory'}`,
|
|
1726
|
-
release_target: '0.1.
|
|
1831
|
+
release_target: '0.1.13',
|
|
1727
1832
|
artifacts_written: !dryRun,
|
|
1728
1833
|
client_configs_written: false,
|
|
1729
1834
|
client_config_write_required: false,
|
|
@@ -1829,10 +1934,11 @@ export async function doctorCommand(flags, io) {
|
|
|
1829
1934
|
};
|
|
1830
1935
|
}));
|
|
1831
1936
|
const schemas = await schemaFiles();
|
|
1937
|
+
const bundleInput = pathFlag(flags, ['bundle', 'file'], DEFAULT_BUNDLE);
|
|
1832
1938
|
const selectedClient = getFlag(flags, ['client']);
|
|
1833
1939
|
const doctorOptions = selectedClient && selectedClient !== true
|
|
1834
|
-
? { ...connectorOptions(flags), clientId: String(selectedClient) }
|
|
1835
|
-
: { ...connectorOptions(flags), clientId: undefined };
|
|
1940
|
+
? { ...connectorOptions(flags), clientId: String(selectedClient), redactPaths: true }
|
|
1941
|
+
: { ...connectorOptions(flags), clientId: undefined, redactPaths: true };
|
|
1836
1942
|
const connectorDoctor = await doctorConnectors(doctorOptions);
|
|
1837
1943
|
const profile = getClientProfile(String(selectedClient && selectedClient !== true ? selectedClient : 'generic-mcp'), connectorOptions(flags));
|
|
1838
1944
|
const checks = {
|
|
@@ -1841,6 +1947,7 @@ export async function doctorCommand(flags, io) {
|
|
|
1841
1947
|
current: process.versions.node,
|
|
1842
1948
|
required: packageJson.engines?.node ?? null,
|
|
1843
1949
|
},
|
|
1950
|
+
npm: npmUserAgentCheck(),
|
|
1844
1951
|
package_bins: {
|
|
1845
1952
|
ok: binEntries.every((entry) => entry.declared && entry.exists),
|
|
1846
1953
|
required: REQUIRED_PACKAGE_BINS,
|
|
@@ -1851,8 +1958,9 @@ export async function doctorCommand(flags, io) {
|
|
|
1851
1958
|
bundle_default_path: {
|
|
1852
1959
|
ok: DEFAULT_BUNDLE === '.enigma/bundle.json',
|
|
1853
1960
|
path: DEFAULT_BUNDLE,
|
|
1854
|
-
resolved: resolve(
|
|
1961
|
+
resolved: publicPathDisplay(resolve(bundleInput), 'bundle-path'),
|
|
1855
1962
|
},
|
|
1963
|
+
vault_path: await writableVaultPathCheck(resolve(bundleInput), publicPathDisplay(bundleInput, 'bundle-path')),
|
|
1856
1964
|
schemas: {
|
|
1857
1965
|
ok: schemas.length > 0,
|
|
1858
1966
|
count: schemas.length,
|
|
@@ -1870,11 +1978,14 @@ export async function doctorCommand(flags, io) {
|
|
|
1870
1978
|
ok,
|
|
1871
1979
|
node: checks.node,
|
|
1872
1980
|
package_bins: checks.package_bins,
|
|
1981
|
+
npm: checks.npm,
|
|
1982
|
+
vault_path: checks.vault_path,
|
|
1873
1983
|
bundle_default_path: checks.bundle_default_path,
|
|
1874
1984
|
schema_count: checks.schemas.count,
|
|
1875
1985
|
schemas: checks.schemas,
|
|
1876
1986
|
mcp_command_name: checks.mcp_command_name.command,
|
|
1877
1987
|
connectors: checks.connectors,
|
|
1988
|
+
next_commands: doctorNextCommands(checks.vault_path.path, String(selectedClient && selectedClient !== true ? selectedClient : 'generic-mcp')),
|
|
1878
1989
|
checks,
|
|
1879
1990
|
}, io);
|
|
1880
1991
|
return ok ? 0 : 1;
|
|
@@ -2088,6 +2199,229 @@ function integerFlag(flags, names, label = names[0], fallback = undefined) {
|
|
|
2088
2199
|
return number;
|
|
2089
2200
|
}
|
|
2090
2201
|
|
|
2202
|
+
function flagValues(flags, names) {
|
|
2203
|
+
const values = [];
|
|
2204
|
+
for (const name of names) {
|
|
2205
|
+
const value = getFlag(flags, [name]);
|
|
2206
|
+
const entries = Array.isArray(value) ? value : [value];
|
|
2207
|
+
for (const entry of entries) {
|
|
2208
|
+
if (entry === undefined || entry === true || entry === '') continue;
|
|
2209
|
+
for (const item of String(entry).split(',')) {
|
|
2210
|
+
const trimmed = item.trim();
|
|
2211
|
+
if (trimmed) values.push(trimmed);
|
|
2212
|
+
}
|
|
2213
|
+
}
|
|
2214
|
+
}
|
|
2215
|
+
return values;
|
|
2216
|
+
}
|
|
2217
|
+
|
|
2218
|
+
function chainWriteOrPrint(flags, io, artifact, summary) {
|
|
2219
|
+
if (flags.has('out')) {
|
|
2220
|
+
const outPath = resolve(String(requireFlag(flags, ['out'])));
|
|
2221
|
+
return writeJson(outPath, artifact).then(() => {
|
|
2222
|
+
print({
|
|
2223
|
+
ok: true,
|
|
2224
|
+
path: publicPathDisplay(String(requireFlag(flags, ['out'])), 'proof-network-artifact'),
|
|
2225
|
+
transaction_submitted: false,
|
|
2226
|
+
raw_memory_on_chain: false,
|
|
2227
|
+
...summary,
|
|
2228
|
+
}, io);
|
|
2229
|
+
return 0;
|
|
2230
|
+
});
|
|
2231
|
+
}
|
|
2232
|
+
print(artifact, io);
|
|
2233
|
+
return 0;
|
|
2234
|
+
}
|
|
2235
|
+
|
|
2236
|
+
async function sha256PublicFile(path) {
|
|
2237
|
+
const bytes = await readFile(path);
|
|
2238
|
+
try {
|
|
2239
|
+
assertNoPrivateProofPayload(JSON.parse(bytes.toString('utf8')));
|
|
2240
|
+
} catch (error) {
|
|
2241
|
+
if (error instanceof SyntaxError) return `sha256:${createHash('sha256').update(bytes).digest('hex')}`;
|
|
2242
|
+
throw new Error('Report file contains private proof payload markers.');
|
|
2243
|
+
}
|
|
2244
|
+
return `sha256:${createHash('sha256').update(bytes).digest('hex')}`;
|
|
2245
|
+
}
|
|
2246
|
+
|
|
2247
|
+
function scoreFlags(flags) {
|
|
2248
|
+
const scores = {};
|
|
2249
|
+
for (const value of flagValues(flags, ['score', 'scores', 'metric', 'metrics'])) {
|
|
2250
|
+
const eq = value.indexOf('=');
|
|
2251
|
+
if (eq <= 0) throw new Error('--score values must use name=value.');
|
|
2252
|
+
const key = value.slice(0, eq).trim();
|
|
2253
|
+
const raw = value.slice(eq + 1).trim();
|
|
2254
|
+
if (!key || !raw) throw new Error('--score values must use name=value.');
|
|
2255
|
+
const numeric = Number(raw);
|
|
2256
|
+
scores[key] = Number.isFinite(numeric) && raw !== '' ? numeric : raw;
|
|
2257
|
+
}
|
|
2258
|
+
return scores;
|
|
2259
|
+
}
|
|
2260
|
+
|
|
2261
|
+
|
|
2262
|
+
function assertChainArtifact(validate, artifact) {
|
|
2263
|
+
const result = chainValidationResult(validate, artifact);
|
|
2264
|
+
if (!result.ok) throw new Error(result.errors?.join('; ') || 'Invalid proof-network artifact.');
|
|
2265
|
+
return artifact;
|
|
2266
|
+
}
|
|
2267
|
+
function chainValidationResult(validate, artifact) {
|
|
2268
|
+
assertNoPrivateProofPayload(artifact);
|
|
2269
|
+
const result = validate(artifact);
|
|
2270
|
+
if (result === false) return { ok: false };
|
|
2271
|
+
if (result && typeof result === 'object') return { ok: result.ok !== false, ...result };
|
|
2272
|
+
return { ok: true };
|
|
2273
|
+
}
|
|
2274
|
+
|
|
2275
|
+
function chainArtifactValidator(artifact) {
|
|
2276
|
+
const schema = String(artifact?.schema ?? artifact?.type ?? artifact?.artifact_type ?? '');
|
|
2277
|
+
if (schema === 'enigma.proof_network.anchor_batch.v1') return [schema, validateProofNetworkAnchorBatch];
|
|
2278
|
+
if (schema === 'enigma.proof_network.capability_grant.v1') return [schema, validateCapabilityGrant];
|
|
2279
|
+
if (schema === 'enigma.proof_network.capability_revocation.v1') return [schema, validateCapabilityRevocation];
|
|
2280
|
+
if (schema === 'enigma.proof_network.benchmark_attestation.v1') return [schema, validateBenchmarkAttestation];
|
|
2281
|
+
if (schema === 'enigma.proof_network.packet.v1') return [schema, validateProofNetworkPacket];
|
|
2282
|
+
throw new Error(`Unsupported proof-network artifact schema: ${schema || 'missing'}.`);
|
|
2283
|
+
}
|
|
2284
|
+
|
|
2285
|
+
export async function chainAnchorCommand(flags, io) {
|
|
2286
|
+
const roots = flagValues(flags, ['root', 'roots', 'memory-root', 'memoryRoot', 'receipt-root', 'receiptRoot', 'context-root', 'contextRoot', 'memory-commitment-root', 'memoryCommitmentRoot']);
|
|
2287
|
+
if (roots.length === 0) throw new Error('Missing required --root.');
|
|
2288
|
+
const refs = flagValues(flags, ['ref', 'refs', 'public-ref', 'publicRef']);
|
|
2289
|
+
const publicChainRef = getFlag(flags, ['public-chain-ref', 'publicChainRef', 'chain-ref', 'chainRef'], 'solana:local-plan');
|
|
2290
|
+
const batch = createProofNetworkAnchorBatch({
|
|
2291
|
+
roots,
|
|
2292
|
+
root_count: roots.length,
|
|
2293
|
+
commitment_count: roots.length,
|
|
2294
|
+
refs,
|
|
2295
|
+
public_chain_ref: publicChainRef,
|
|
2296
|
+
authority_ref: getFlag(flags, ['authority', 'authority-ref', 'authorityRef']),
|
|
2297
|
+
batch_ref: getFlag(flags, ['batch-ref', 'batchRef']),
|
|
2298
|
+
created_at: getFlag(flags, ['created-at', 'createdAt']),
|
|
2299
|
+
transaction_submitted: false,
|
|
2300
|
+
raw_memory_on_chain: false,
|
|
2301
|
+
});
|
|
2302
|
+
assertChainArtifact(validateProofNetworkAnchorBatch, batch);
|
|
2303
|
+
return chainWriteOrPrint(flags, io, batch, {
|
|
2304
|
+
artifact_type: batch.schema,
|
|
2305
|
+
anchor_batch_id: batch.anchor_batch_id,
|
|
2306
|
+
anchor_batch_hash: batch.anchor_batch_hash ?? proofNetworkSha256Json(batch),
|
|
2307
|
+
});
|
|
2308
|
+
}
|
|
2309
|
+
|
|
2310
|
+
export async function chainGrantCommand(flags, io) {
|
|
2311
|
+
const resourceRefs = flagValues(flags, ['resource-root', 'resource-roots', 'resourceRoot', 'resourceRoots', 'resource-ref', 'resource-refs', 'resourceRef', 'resourceRefs', 'ref', 'refs']);
|
|
2312
|
+
const capability = requireFlag(flags, ['capability', 'capability-id', 'capabilityId'], 'capability');
|
|
2313
|
+
const scope = requireFlag(flags, ['scope', 'scope-ref', 'scopeRef', 'capability-scope', 'capabilityScope'], 'scope');
|
|
2314
|
+
const policyHash = getFlag(flags, ['policy-hash', 'policyHash'], proofNetworkSha256Json({ capability, scope, resource_refs: resourceRefs }));
|
|
2315
|
+
const grant = createCapabilityGrant({
|
|
2316
|
+
issuer_ref: getFlag(flags, ['issuer', 'issuer-ref', 'issuerRef'], 'issuer:local-cli'),
|
|
2317
|
+
subject_ref: requireFlag(flags, ['subject', 'subject-ref', 'subjectRef'], 'subject'),
|
|
2318
|
+
capability,
|
|
2319
|
+
scope,
|
|
2320
|
+
scopes: scope,
|
|
2321
|
+
capability_scope: scope,
|
|
2322
|
+
resource_roots: resourceRefs.length ? resourceRefs : [policyHash],
|
|
2323
|
+
policy_hash: policyHash,
|
|
2324
|
+
expires_at: requireFlag(flags, ['expires-at', 'expiresAt'], 'expires-at'),
|
|
2325
|
+
grant_ref: getFlag(flags, ['grant-ref', 'grantRef']),
|
|
2326
|
+
issued_at: getFlag(flags, ['issued-at', 'issuedAt', 'created-at', 'createdAt']),
|
|
2327
|
+
transaction_submitted: false,
|
|
2328
|
+
raw_memory_on_chain: false,
|
|
2329
|
+
});
|
|
2330
|
+
assertChainArtifact(validateCapabilityGrant, grant);
|
|
2331
|
+
return chainWriteOrPrint(flags, io, grant, {
|
|
2332
|
+
artifact_type: grant.schema,
|
|
2333
|
+
capability_grant_id: grant.capability_grant_id,
|
|
2334
|
+
capability_grant_hash: grant.capability_grant_hash ?? proofNetworkSha256Json(grant),
|
|
2335
|
+
});
|
|
2336
|
+
}
|
|
2337
|
+
|
|
2338
|
+
export async function chainRevokeCommand(flags, io) {
|
|
2339
|
+
const grantValue = getFlag(flags, ['grant']);
|
|
2340
|
+
let grantHash = getFlag(flags, ['grant-hash', 'grantHash']);
|
|
2341
|
+
let grantId = getFlag(flags, ['grant-id', 'grantId']);
|
|
2342
|
+
if (grantValue !== undefined && grantValue !== true && grantValue !== '') {
|
|
2343
|
+
const grantString = String(grantValue);
|
|
2344
|
+
if (grantString.startsWith('sha256:')) {
|
|
2345
|
+
grantHash = grantHash ?? grantString;
|
|
2346
|
+
} else {
|
|
2347
|
+
const grantArtifact = await readJson(resolve(grantString));
|
|
2348
|
+
const grantValidation = validateCapabilityGrant(grantArtifact);
|
|
2349
|
+
if (!grantValidation.ok) throw new Error(`Grant artifact is invalid: ${grantValidation.errors.join('; ')}`);
|
|
2350
|
+
grantHash = grantHash ?? grantArtifact.capability_grant_hash;
|
|
2351
|
+
grantId = grantId ?? grantArtifact.capability_grant_id;
|
|
2352
|
+
}
|
|
2353
|
+
}
|
|
2354
|
+
const nullifierValue = getFlag(flags, ['nullifier-root', 'nullifierRoot', 'nullifier-ref', 'nullifierRef', 'nullifier']);
|
|
2355
|
+
const revocation = createCapabilityRevocation({
|
|
2356
|
+
grant_id: grantId,
|
|
2357
|
+
grant_hash: grantHash ?? requireFlag(flags, ['grant-hash', 'grantHash'], 'grant-hash'),
|
|
2358
|
+
reason_ref: requireFlag(flags, ['reason', 'revocation-reason', 'revocationReason'], 'reason'),
|
|
2359
|
+
revocation_reason: getFlag(flags, ['reason', 'revocation-reason', 'revocationReason']),
|
|
2360
|
+
revocation_ref: getFlag(flags, ['revocation-ref', 'revocationRef']),
|
|
2361
|
+
nullifier_root: nullifierValue && String(nullifierValue).startsWith('sha256:') ? nullifierValue : undefined,
|
|
2362
|
+
nullifier_ref: nullifierValue && !String(nullifierValue).startsWith('sha256:') ? nullifierValue : undefined,
|
|
2363
|
+
revoked_at: getFlag(flags, ['revoked-at', 'revokedAt']),
|
|
2364
|
+
transaction_submitted: false,
|
|
2365
|
+
raw_memory_on_chain: false,
|
|
2366
|
+
});
|
|
2367
|
+
assertChainArtifact(validateCapabilityRevocation, revocation);
|
|
2368
|
+
return chainWriteOrPrint(flags, io, revocation, {
|
|
2369
|
+
artifact_type: revocation.schema,
|
|
2370
|
+
capability_revocation_id: revocation.capability_revocation_id,
|
|
2371
|
+
capability_revocation_hash: revocation.capability_revocation_hash ?? proofNetworkSha256Json(revocation),
|
|
2372
|
+
});
|
|
2373
|
+
}
|
|
2374
|
+
|
|
2375
|
+
export async function chainAttestCommand(flags, io) {
|
|
2376
|
+
const reportHash = getFlag(flags, ['report-hash', 'reportHash']);
|
|
2377
|
+
const reportFile = getFlag(flags, ['report-file', 'reportFile']);
|
|
2378
|
+
const resolvedReportHash = reportHash || (reportFile ? await sha256PublicFile(resolve(String(reportFile))) : undefined);
|
|
2379
|
+
if (!resolvedReportHash) throw new Error('Missing required --report-hash or --report-file.');
|
|
2380
|
+
const scores = scoreFlags(flags);
|
|
2381
|
+
const metricsHash = getFlag(flags, ['metrics-hash', 'metricsHash'], proofNetworkSha256Json({ scores }));
|
|
2382
|
+
const attestation = createBenchmarkAttestation({
|
|
2383
|
+
report_hash: resolvedReportHash,
|
|
2384
|
+
report_file_hash: resolvedReportHash,
|
|
2385
|
+
dataset_ref: requireFlag(flags, ['dataset-ref', 'datasetRef', 'dataset-manifest', 'datasetManifest'], 'dataset-ref'),
|
|
2386
|
+
runner_ref: requireFlag(flags, ['runner-ref', 'runnerRef'], 'runner-ref'),
|
|
2387
|
+
package_ref: requireFlag(flags, ['package-ref', 'packageRef'], 'package-ref'),
|
|
2388
|
+
metrics: scores,
|
|
2389
|
+
metrics_hash: metricsHash,
|
|
2390
|
+
attestation_ref: getFlag(flags, ['attestation-ref', 'attestationRef']),
|
|
2391
|
+
created_at: getFlag(flags, ['created-at', 'createdAt']),
|
|
2392
|
+
transaction_submitted: false,
|
|
2393
|
+
raw_memory_on_chain: false,
|
|
2394
|
+
});
|
|
2395
|
+
assertChainArtifact(validateBenchmarkAttestation, attestation);
|
|
2396
|
+
return chainWriteOrPrint(flags, io, attestation, {
|
|
2397
|
+
artifact_type: attestation.schema,
|
|
2398
|
+
benchmark_attestation_id: attestation.benchmark_attestation_id,
|
|
2399
|
+
benchmark_attestation_hash: attestation.benchmark_attestation_hash ?? proofNetworkSha256Json(attestation),
|
|
2400
|
+
});
|
|
2401
|
+
}
|
|
2402
|
+
|
|
2403
|
+
export async function chainVerifyCommand(flags, io, positionalFile = undefined) {
|
|
2404
|
+
const inPath = resolve(String(requireFileArg(flags, ['file', 'in'], positionalFile, 'file')));
|
|
2405
|
+
const artifact = await readJson(inPath);
|
|
2406
|
+
const [schema, validate] = chainArtifactValidator(artifact);
|
|
2407
|
+
let result;
|
|
2408
|
+
try {
|
|
2409
|
+
result = chainValidationResult(validate, artifact);
|
|
2410
|
+
} catch (error) {
|
|
2411
|
+
result = { ok: false, error: { code: 'PROOF_NETWORK_INVALID', message: error.message } };
|
|
2412
|
+
}
|
|
2413
|
+
print({
|
|
2414
|
+
ok: result.ok === true,
|
|
2415
|
+
artifact_type: schema,
|
|
2416
|
+
artifact_hash: proofNetworkSha256Json(artifact),
|
|
2417
|
+
transaction_submitted: false,
|
|
2418
|
+
raw_memory_on_chain: false,
|
|
2419
|
+
validation: result,
|
|
2420
|
+
}, io);
|
|
2421
|
+
return result.ok === true ? 0 : 1;
|
|
2422
|
+
}
|
|
2423
|
+
|
|
2424
|
+
|
|
2091
2425
|
export async function meterEventCommand(flags, io) {
|
|
2092
2426
|
const event = createUsageEvent({
|
|
2093
2427
|
tenant_id: requireFlag(flags, ['tenant', 'tenant-id', 'tenantId'], 'tenant'),
|
|
@@ -2306,6 +2640,11 @@ function usage() {
|
|
|
2306
2640
|
'settlement receipt',
|
|
2307
2641
|
'settlement verify',
|
|
2308
2642
|
'settlement batch',
|
|
2643
|
+
'chain anchor',
|
|
2644
|
+
'chain grant',
|
|
2645
|
+
'chain revoke',
|
|
2646
|
+
'chain attest',
|
|
2647
|
+
'chain verify',
|
|
2309
2648
|
],
|
|
2310
2649
|
connector_options: {
|
|
2311
2650
|
'--bundle <path>': 'Absolute local Enigma vault bundle path rendered as ENIGMA_BUNDLE.',
|
|
@@ -2401,6 +2740,14 @@ function usage() {
|
|
|
2401
2740
|
batch: 'enigma settlement batch --receipts <receipts.json> --batch-ref <ref> [--asset <asset>] [--out <file>]',
|
|
2402
2741
|
boundary: 'Settlement artifacts contain commitment roots, capacity profiles, hashes, refs, prices, and claim boundaries only; no raw memory, prompts, provider responses, credentials, token ROI/profit, decentralization, or provider-invoice savings claim.',
|
|
2403
2742
|
},
|
|
2743
|
+
chain: {
|
|
2744
|
+
anchor: 'enigma chain anchor --root <sha256:...> [--root <sha256:...>] [--ref <public-ref>] [--authority <public-authority-ref>] [--batch-ref <ref>] [--out <file>]',
|
|
2745
|
+
grant: 'enigma chain grant --subject <public-subject-ref> --capability <capability-id> --scope <scope-id> [--resource-ref <sha256:...>] [--policy-hash <sha256:...>] --expires-at <iso> [--grant-ref <public-ref>] [--out <file>]',
|
|
2746
|
+
revoke: 'enigma chain revoke --grant-hash <sha256:...> --reason <public-reason-code> [--revocation-ref <public-ref>] [--out <file>]',
|
|
2747
|
+
attest: 'enigma chain attest (--report-hash <sha256:...> | --report-file <report.json>) --dataset-ref <sha256:...> --runner-ref <public-runner-ref> --package-ref <public-package-ref> [--score name=value] [--out <file>]',
|
|
2748
|
+
verify: 'enigma chain verify --file <proof-artifact.json>',
|
|
2749
|
+
boundary: 'Proof Network chain commands are local planning commands only. They write public-safe hashes, roots, refs, counts, signatures, and booleans; they do not submit Solana transactions or put raw memory on chain.',
|
|
2750
|
+
},
|
|
2404
2751
|
relay_gateway_options: {
|
|
2405
2752
|
'--host <host>': 'Bind host. Defaults to 127.0.0.1.',
|
|
2406
2753
|
'--port <port>': `Bind port. Defaults to ${DEFAULT_RELAY_PORT} for relay and ${DEFAULT_GATEWAY_PORT} for gateway.`,
|
|
@@ -2427,10 +2774,10 @@ export async function main(argv = process.argv.slice(2), io = { stdout: process.
|
|
|
2427
2774
|
print(usage(), io);
|
|
2428
2775
|
return 0;
|
|
2429
2776
|
}
|
|
2430
|
-
const twoPartCommands = ['boundary', 'mcp', 'mesh', 'enterprise', 'capsule', 'relay', 'gateway', 'connect', 'disconnect', 'import', 'native-host', 'meter', 'settlement', 'demo', 'passport'];
|
|
2777
|
+
const twoPartCommands = ['boundary', 'mcp', 'mesh', 'enterprise', 'capsule', 'relay', 'gateway', 'connect', 'disconnect', 'import', 'native-host', 'meter', 'settlement', 'chain', 'demo', 'passport'];
|
|
2431
2778
|
const flags = parseArgs(twoPartCommands.includes(command) ? argv.slice(2) : argv.slice(1));
|
|
2432
2779
|
const positionalFile = optionalPositional(argv[2]);
|
|
2433
|
-
if ((flags.has('help') || argv.includes('-h')) && (command === 'setup' || command === 'test-drive' || command === 'search' || command === 'status' || (command === 'passport' && subcommand === 'status') || ((command === 'relay' || command === 'gateway') && (subcommand === 'serve' || subcommand === 'demo')) || (command === 'native-host' && (subcommand === 'manifest' || subcommand === 'install-plan')) || (command === 'demo' && subcommand === 'cross-model'))) {
|
|
2780
|
+
if ((command === 'chain' && (!subcommand || subcommand === '--help' || subcommand === '-h' || flags.has('help'))) || ((flags.has('help') || argv.includes('-h')) && (command === 'setup' || command === 'test-drive' || command === 'search' || command === 'status' || (command === 'passport' && subcommand === 'status') || ((command === 'relay' || command === 'gateway') && (subcommand === 'serve' || subcommand === 'demo')) || (command === 'native-host' && (subcommand === 'manifest' || subcommand === 'install-plan')) || (command === 'demo' && subcommand === 'cross-model')))) {
|
|
2434
2781
|
print(usage(), io);
|
|
2435
2782
|
return 0;
|
|
2436
2783
|
}
|
|
@@ -2472,6 +2819,11 @@ export async function main(argv = process.argv.slice(2), io = { stdout: process.
|
|
|
2472
2819
|
if (command === 'settlement' && subcommand === 'receipt') return await settlementReceiptCommand(flags, io);
|
|
2473
2820
|
if (command === 'settlement' && subcommand === 'verify') return await settlementVerifyCommand(flags, io);
|
|
2474
2821
|
if (command === 'settlement' && subcommand === 'batch') return await settlementBatchCommand(flags, io, positionalFile);
|
|
2822
|
+
if (command === 'chain' && subcommand === 'anchor') return await chainAnchorCommand(flags, io);
|
|
2823
|
+
if (command === 'chain' && subcommand === 'grant') return await chainGrantCommand(flags, io);
|
|
2824
|
+
if (command === 'chain' && subcommand === 'revoke') return await chainRevokeCommand(flags, io);
|
|
2825
|
+
if (command === 'chain' && subcommand === 'attest') return await chainAttestCommand(flags, io);
|
|
2826
|
+
if (command === 'chain' && subcommand === 'verify') return await chainVerifyCommand(flags, io, positionalFile);
|
|
2475
2827
|
if (command === 'native-host' && subcommand === 'install-plan') return await nativeHostInstallPlanCommand(flags, io);
|
|
2476
2828
|
if (command === 'mesh' && subcommand === 'demo') return await meshDemoCommand(flags, io);
|
|
2477
2829
|
if (command === 'enterprise' && subcommand === 'demo') return await enterpriseDemoCommand(flags, io);
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# Enigma Memory — Local Production Simulation
|
|
2
|
+
|
|
3
|
+
**CLAIM BOUNDARY:** This is a `local-simulation` environment. It uses
|
|
4
|
+
self-signed TLS, bind-mounted file "secrets", a mocked KMS, and a mocked SIEM.
|
|
5
|
+
It is **not** a production deployment and must not be used as go-live evidence.
|
|
6
|
+
|
|
7
|
+
## Public-looking domain (local testing only)
|
|
8
|
+
|
|
9
|
+
The simulation is configured to answer on `sim.enigmamemory.com` so that the
|
|
10
|
+
hosted-backend live validator accepts the non-localhost HTTPS probe URLs. For
|
|
11
|
+
real go-live evidence the operator must point the chosen public domain at the
|
|
12
|
+
deployment's public IP address; the local simulation uses a hosts-file or local
|
|
13
|
+
DNS trick instead.
|
|
14
|
+
|
|
15
|
+
On the host running Docker, map the domain to the loopback interface:
|
|
16
|
+
|
|
17
|
+
```text
|
|
18
|
+
127.0.0.1 sim.enigmamemory.com relay.sim.enigmamemory.com gateway.sim.enigmamemory.com
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
On Linux/macOS add that line to `/etc/hosts`; on Windows add it to
|
|
22
|
+
`C:\Windows\System32\drivers\etc\hosts`. Then the following commands work from
|
|
23
|
+
the host:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
curl -k https://sim.enigmamemory.com:8443/readyz
|
|
27
|
+
curl -k https://sim.enigmamemory.com:9443/readyz
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The tls-proxy service also declares `extra_hosts` entries for the same domain
|
|
31
|
+
names so that containers can resolve them locally when needed.
|
|
32
|
+
|
|
33
|
+
## Quick start
|
|
34
|
+
|
|
35
|
+
1. Generate secrets and a self-signed TLS certificate:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
node scripts/simulate-production-env.mjs
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Files are written to `deploy/secrets-simulation/` (gitignored).
|
|
42
|
+
|
|
43
|
+
2. Start the simulation:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
docker compose -f deploy/docker-compose.local-production-simulation.yml up --build -d
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
3. Wait for the backend to become ready:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
node scripts/wait-for-backend-ready.mjs
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
4. Inspect readiness over HTTPS:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
curl -k https://localhost:8443/readyz
|
|
59
|
+
curl -k https://localhost:9443/readyz
|
|
60
|
+
curl -k https://sim.enigmamemory.com:8443/readyz
|
|
61
|
+
curl -k https://sim.enigmamemory.com:9443/readyz
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Stop
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
docker compose -f deploy/docker-compose.local-production-simulation.yml down
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
To also remove the Postgres volume and mock event data:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
docker compose -f deploy/docker-compose.local-production-simulation.yml down -v
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Ports and routes
|
|
77
|
+
|
|
78
|
+
| Service | Public port | Internal port | Health route | Notes |
|
|
79
|
+
|--------|-------------|---------------|--------------|-------|
|
|
80
|
+
| relay | `8443` (HTTPS, loopback) | `8787` | `/readyz`, `/livez` | TLS terminated by `tls-proxy`; also answers on `sim.enigmamemory.com` and `relay.sim.enigmamemory.com` |
|
|
81
|
+
| gateway | `9443` (HTTPS, loopback) | `8797` | `/readyz`, `/livez` | TLS terminated by `tls-proxy`; also answers on `sim.enigmamemory.com` and `gateway.sim.enigmamemory.com` |
|
|
82
|
+
| postgres | not exposed | `5432` | — | Used as the simulated durable store |
|
|
83
|
+
| kms-mock | not exposed | `3000` | `/healthz` | Serves a generated Ed25519 key ref |
|
|
84
|
+
| siem-mock | not exposed | `3000` | `/healthz` | Accepts `POST /events`, writes minimized metadata to `/data/siem-events.jsonl` |
|
|
85
|
+
|
|
86
|
+
## Verify secret files
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
node scripts/simulate-production-env.mjs --check
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
This reports whether all required files in `deploy/secrets-simulation/` exist
|
|
93
|
+
and are non-empty.
|
|
94
|
+
|
|
95
|
+
## Simulation-only behavior
|
|
96
|
+
|
|
97
|
+
- `ENIGMA_OPERATOR_ACCEPTANCE_DECISION` is set to `go` so the readiness
|
|
98
|
+
endpoints can turn green locally. This is **not** real operator acceptance.
|
|
99
|
+
- `ENIGMA_DISABLE_LOCAL_DEMO_FALLBACK` is `true`, but the "external" storage,
|
|
100
|
+
KMS, and SIEM are local mocks.
|
|
101
|
+
- The TLS certificate is self-signed; curl requires `-k`/`--insecure`.
|
|
102
|
+
- The certificate SAN list includes `localhost`, `127.0.0.1`,
|
|
103
|
+
`sim.enigmamemory.com`, `relay.sim.enigmamemory.com`,
|
|
104
|
+
`gateway.sim.enigmamemory.com`, and `*.sim.enigmamemory.com`.
|
|
105
|
+
|
|
106
|
+
## Collect hosted backend live evidence
|
|
107
|
+
|
|
108
|
+
The simulation can be probed as if it were a public hosted deployment by
|
|
109
|
+
using the public-looking domain `sim.enigmamemory.com`. Because the domain
|
|
110
|
+
has no real DNS record, the collector resolves it to `127.0.0.1` locally and
|
|
111
|
+
accepts the self-signed certificate.
|
|
112
|
+
|
|
113
|
+
1. Build a simulation operator acceptance packet:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
node scripts/build-operator-acceptance-packet.mjs \
|
|
117
|
+
--complete-fixture --decision go --packet-id sim-operator-acceptance \
|
|
118
|
+
--tenant enigma-sim --deployment-mode hosted --environment local-simulation \
|
|
119
|
+
--target-regions local --requested-go-live-date 2026-06-25 \
|
|
120
|
+
--evidence-repository https://github.com/enigma-memory/evidence/sim \
|
|
121
|
+
--packet-owner "Simulation Owner" \
|
|
122
|
+
--last-updated 2026-06-25T00:00:00.000Z \
|
|
123
|
+
--owners-json .enigma/sim-owner-overrides.json \
|
|
124
|
+
--evidence-refs .enigma/sim-evidence-overrides.json \
|
|
125
|
+
--out .enigma/sim-operator-acceptance.json --validate
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
2. Collect and validate live evidence:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
node .enigma/collect-sim-evidence.mjs \
|
|
132
|
+
--relay-url https://sim.enigmamemory.com:8443 \
|
|
133
|
+
--gateway-url https://sim.enigmamemory.com:9443 \
|
|
134
|
+
--refs-json .enigma/sim-hosted-refs.json \
|
|
135
|
+
--domain sim.enigmamemory.com --environment-id local-simulation \
|
|
136
|
+
--cloud-provider local --region local --owner enigma-sim \
|
|
137
|
+
--operator-decision go \
|
|
138
|
+
--operator-packet-ref .enigma/sim-operator-acceptance.json \
|
|
139
|
+
--operator-approved-at <iso8601> --operator-approved-by enigma-sim \
|
|
140
|
+
--out .enigma/hosted-backend-live-collection.json \
|
|
141
|
+
--evidence-out .enigma/hosted-backend-live-simulated.json
|
|
142
|
+
|
|
143
|
+
node scripts/validate-hosted-backend-live.mjs \
|
|
144
|
+
--evidence .enigma/hosted-backend-live-simulated.json
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
The expected result is `status: accepted` with all four probes observed and no
|
|
148
|
+
blockers. The wrapper does not mutate DNS or deploy infrastructure and never
|
|
149
|
+
sends credentials.
|
|
150
|
+
|
|
151
|
+
Never commit `deploy/secrets-simulation/` or `*.pem` files. Both are
|
|
152
|
+
`.gitignore`d.
|