enigma-memory 0.1.11 → 0.1.12
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 +257 -3
- 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/demo-proof-network.md +275 -0
- package/docs/developer-ecosystem.md +44 -1
- 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/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 +130 -10
- package/docs/solana-devnet-acceptance.md +226 -0
- package/docs/solana-proof-rail.md +453 -0
- 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 +40 -4
- 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/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/scripts/install-enigma-local.mjs +0 -270
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
|
@@ -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';
|
|
@@ -1723,7 +1736,7 @@ export async function testDriveCommand(flags, io) {
|
|
|
1723
1736
|
out_dir: outDirInput,
|
|
1724
1737
|
bundle: bundleInput,
|
|
1725
1738
|
install_command: `npm install -g ${packageJson.name ?? 'enigma-memory'}`,
|
|
1726
|
-
release_target: '0.1.
|
|
1739
|
+
release_target: '0.1.12',
|
|
1727
1740
|
artifacts_written: !dryRun,
|
|
1728
1741
|
client_configs_written: false,
|
|
1729
1742
|
client_config_write_required: false,
|
|
@@ -2088,6 +2101,229 @@ function integerFlag(flags, names, label = names[0], fallback = undefined) {
|
|
|
2088
2101
|
return number;
|
|
2089
2102
|
}
|
|
2090
2103
|
|
|
2104
|
+
function flagValues(flags, names) {
|
|
2105
|
+
const values = [];
|
|
2106
|
+
for (const name of names) {
|
|
2107
|
+
const value = getFlag(flags, [name]);
|
|
2108
|
+
const entries = Array.isArray(value) ? value : [value];
|
|
2109
|
+
for (const entry of entries) {
|
|
2110
|
+
if (entry === undefined || entry === true || entry === '') continue;
|
|
2111
|
+
for (const item of String(entry).split(',')) {
|
|
2112
|
+
const trimmed = item.trim();
|
|
2113
|
+
if (trimmed) values.push(trimmed);
|
|
2114
|
+
}
|
|
2115
|
+
}
|
|
2116
|
+
}
|
|
2117
|
+
return values;
|
|
2118
|
+
}
|
|
2119
|
+
|
|
2120
|
+
function chainWriteOrPrint(flags, io, artifact, summary) {
|
|
2121
|
+
if (flags.has('out')) {
|
|
2122
|
+
const outPath = resolve(String(requireFlag(flags, ['out'])));
|
|
2123
|
+
return writeJson(outPath, artifact).then(() => {
|
|
2124
|
+
print({
|
|
2125
|
+
ok: true,
|
|
2126
|
+
path: publicPathDisplay(String(requireFlag(flags, ['out'])), 'proof-network-artifact'),
|
|
2127
|
+
transaction_submitted: false,
|
|
2128
|
+
raw_memory_on_chain: false,
|
|
2129
|
+
...summary,
|
|
2130
|
+
}, io);
|
|
2131
|
+
return 0;
|
|
2132
|
+
});
|
|
2133
|
+
}
|
|
2134
|
+
print(artifact, io);
|
|
2135
|
+
return 0;
|
|
2136
|
+
}
|
|
2137
|
+
|
|
2138
|
+
async function sha256PublicFile(path) {
|
|
2139
|
+
const bytes = await readFile(path);
|
|
2140
|
+
try {
|
|
2141
|
+
assertNoPrivateProofPayload(JSON.parse(bytes.toString('utf8')));
|
|
2142
|
+
} catch (error) {
|
|
2143
|
+
if (error instanceof SyntaxError) return `sha256:${createHash('sha256').update(bytes).digest('hex')}`;
|
|
2144
|
+
throw new Error('Report file contains private proof payload markers.');
|
|
2145
|
+
}
|
|
2146
|
+
return `sha256:${createHash('sha256').update(bytes).digest('hex')}`;
|
|
2147
|
+
}
|
|
2148
|
+
|
|
2149
|
+
function scoreFlags(flags) {
|
|
2150
|
+
const scores = {};
|
|
2151
|
+
for (const value of flagValues(flags, ['score', 'scores', 'metric', 'metrics'])) {
|
|
2152
|
+
const eq = value.indexOf('=');
|
|
2153
|
+
if (eq <= 0) throw new Error('--score values must use name=value.');
|
|
2154
|
+
const key = value.slice(0, eq).trim();
|
|
2155
|
+
const raw = value.slice(eq + 1).trim();
|
|
2156
|
+
if (!key || !raw) throw new Error('--score values must use name=value.');
|
|
2157
|
+
const numeric = Number(raw);
|
|
2158
|
+
scores[key] = Number.isFinite(numeric) && raw !== '' ? numeric : raw;
|
|
2159
|
+
}
|
|
2160
|
+
return scores;
|
|
2161
|
+
}
|
|
2162
|
+
|
|
2163
|
+
|
|
2164
|
+
function assertChainArtifact(validate, artifact) {
|
|
2165
|
+
const result = chainValidationResult(validate, artifact);
|
|
2166
|
+
if (!result.ok) throw new Error(result.errors?.join('; ') || 'Invalid proof-network artifact.');
|
|
2167
|
+
return artifact;
|
|
2168
|
+
}
|
|
2169
|
+
function chainValidationResult(validate, artifact) {
|
|
2170
|
+
assertNoPrivateProofPayload(artifact);
|
|
2171
|
+
const result = validate(artifact);
|
|
2172
|
+
if (result === false) return { ok: false };
|
|
2173
|
+
if (result && typeof result === 'object') return { ok: result.ok !== false, ...result };
|
|
2174
|
+
return { ok: true };
|
|
2175
|
+
}
|
|
2176
|
+
|
|
2177
|
+
function chainArtifactValidator(artifact) {
|
|
2178
|
+
const schema = String(artifact?.schema ?? artifact?.type ?? artifact?.artifact_type ?? '');
|
|
2179
|
+
if (schema === 'enigma.proof_network.anchor_batch.v1') return [schema, validateProofNetworkAnchorBatch];
|
|
2180
|
+
if (schema === 'enigma.proof_network.capability_grant.v1') return [schema, validateCapabilityGrant];
|
|
2181
|
+
if (schema === 'enigma.proof_network.capability_revocation.v1') return [schema, validateCapabilityRevocation];
|
|
2182
|
+
if (schema === 'enigma.proof_network.benchmark_attestation.v1') return [schema, validateBenchmarkAttestation];
|
|
2183
|
+
if (schema === 'enigma.proof_network.packet.v1') return [schema, validateProofNetworkPacket];
|
|
2184
|
+
throw new Error(`Unsupported proof-network artifact schema: ${schema || 'missing'}.`);
|
|
2185
|
+
}
|
|
2186
|
+
|
|
2187
|
+
export async function chainAnchorCommand(flags, io) {
|
|
2188
|
+
const roots = flagValues(flags, ['root', 'roots', 'memory-root', 'memoryRoot', 'receipt-root', 'receiptRoot', 'context-root', 'contextRoot', 'memory-commitment-root', 'memoryCommitmentRoot']);
|
|
2189
|
+
if (roots.length === 0) throw new Error('Missing required --root.');
|
|
2190
|
+
const refs = flagValues(flags, ['ref', 'refs', 'public-ref', 'publicRef']);
|
|
2191
|
+
const publicChainRef = getFlag(flags, ['public-chain-ref', 'publicChainRef', 'chain-ref', 'chainRef'], 'solana:local-plan');
|
|
2192
|
+
const batch = createProofNetworkAnchorBatch({
|
|
2193
|
+
roots,
|
|
2194
|
+
root_count: roots.length,
|
|
2195
|
+
commitment_count: roots.length,
|
|
2196
|
+
refs,
|
|
2197
|
+
public_chain_ref: publicChainRef,
|
|
2198
|
+
authority_ref: getFlag(flags, ['authority', 'authority-ref', 'authorityRef']),
|
|
2199
|
+
batch_ref: getFlag(flags, ['batch-ref', 'batchRef']),
|
|
2200
|
+
created_at: getFlag(flags, ['created-at', 'createdAt']),
|
|
2201
|
+
transaction_submitted: false,
|
|
2202
|
+
raw_memory_on_chain: false,
|
|
2203
|
+
});
|
|
2204
|
+
assertChainArtifact(validateProofNetworkAnchorBatch, batch);
|
|
2205
|
+
return chainWriteOrPrint(flags, io, batch, {
|
|
2206
|
+
artifact_type: batch.schema,
|
|
2207
|
+
anchor_batch_id: batch.anchor_batch_id,
|
|
2208
|
+
anchor_batch_hash: batch.anchor_batch_hash ?? proofNetworkSha256Json(batch),
|
|
2209
|
+
});
|
|
2210
|
+
}
|
|
2211
|
+
|
|
2212
|
+
export async function chainGrantCommand(flags, io) {
|
|
2213
|
+
const resourceRefs = flagValues(flags, ['resource-root', 'resource-roots', 'resourceRoot', 'resourceRoots', 'resource-ref', 'resource-refs', 'resourceRef', 'resourceRefs', 'ref', 'refs']);
|
|
2214
|
+
const capability = requireFlag(flags, ['capability', 'capability-id', 'capabilityId'], 'capability');
|
|
2215
|
+
const scope = requireFlag(flags, ['scope', 'scope-ref', 'scopeRef', 'capability-scope', 'capabilityScope'], 'scope');
|
|
2216
|
+
const policyHash = getFlag(flags, ['policy-hash', 'policyHash'], proofNetworkSha256Json({ capability, scope, resource_refs: resourceRefs }));
|
|
2217
|
+
const grant = createCapabilityGrant({
|
|
2218
|
+
issuer_ref: getFlag(flags, ['issuer', 'issuer-ref', 'issuerRef'], 'issuer:local-cli'),
|
|
2219
|
+
subject_ref: requireFlag(flags, ['subject', 'subject-ref', 'subjectRef'], 'subject'),
|
|
2220
|
+
capability,
|
|
2221
|
+
scope,
|
|
2222
|
+
scopes: scope,
|
|
2223
|
+
capability_scope: scope,
|
|
2224
|
+
resource_roots: resourceRefs.length ? resourceRefs : [policyHash],
|
|
2225
|
+
policy_hash: policyHash,
|
|
2226
|
+
expires_at: requireFlag(flags, ['expires-at', 'expiresAt'], 'expires-at'),
|
|
2227
|
+
grant_ref: getFlag(flags, ['grant-ref', 'grantRef']),
|
|
2228
|
+
issued_at: getFlag(flags, ['issued-at', 'issuedAt', 'created-at', 'createdAt']),
|
|
2229
|
+
transaction_submitted: false,
|
|
2230
|
+
raw_memory_on_chain: false,
|
|
2231
|
+
});
|
|
2232
|
+
assertChainArtifact(validateCapabilityGrant, grant);
|
|
2233
|
+
return chainWriteOrPrint(flags, io, grant, {
|
|
2234
|
+
artifact_type: grant.schema,
|
|
2235
|
+
capability_grant_id: grant.capability_grant_id,
|
|
2236
|
+
capability_grant_hash: grant.capability_grant_hash ?? proofNetworkSha256Json(grant),
|
|
2237
|
+
});
|
|
2238
|
+
}
|
|
2239
|
+
|
|
2240
|
+
export async function chainRevokeCommand(flags, io) {
|
|
2241
|
+
const grantValue = getFlag(flags, ['grant']);
|
|
2242
|
+
let grantHash = getFlag(flags, ['grant-hash', 'grantHash']);
|
|
2243
|
+
let grantId = getFlag(flags, ['grant-id', 'grantId']);
|
|
2244
|
+
if (grantValue !== undefined && grantValue !== true && grantValue !== '') {
|
|
2245
|
+
const grantString = String(grantValue);
|
|
2246
|
+
if (grantString.startsWith('sha256:')) {
|
|
2247
|
+
grantHash = grantHash ?? grantString;
|
|
2248
|
+
} else {
|
|
2249
|
+
const grantArtifact = await readJson(resolve(grantString));
|
|
2250
|
+
const grantValidation = validateCapabilityGrant(grantArtifact);
|
|
2251
|
+
if (!grantValidation.ok) throw new Error(`Grant artifact is invalid: ${grantValidation.errors.join('; ')}`);
|
|
2252
|
+
grantHash = grantHash ?? grantArtifact.capability_grant_hash;
|
|
2253
|
+
grantId = grantId ?? grantArtifact.capability_grant_id;
|
|
2254
|
+
}
|
|
2255
|
+
}
|
|
2256
|
+
const nullifierValue = getFlag(flags, ['nullifier-root', 'nullifierRoot', 'nullifier-ref', 'nullifierRef', 'nullifier']);
|
|
2257
|
+
const revocation = createCapabilityRevocation({
|
|
2258
|
+
grant_id: grantId,
|
|
2259
|
+
grant_hash: grantHash ?? requireFlag(flags, ['grant-hash', 'grantHash'], 'grant-hash'),
|
|
2260
|
+
reason_ref: requireFlag(flags, ['reason', 'revocation-reason', 'revocationReason'], 'reason'),
|
|
2261
|
+
revocation_reason: getFlag(flags, ['reason', 'revocation-reason', 'revocationReason']),
|
|
2262
|
+
revocation_ref: getFlag(flags, ['revocation-ref', 'revocationRef']),
|
|
2263
|
+
nullifier_root: nullifierValue && String(nullifierValue).startsWith('sha256:') ? nullifierValue : undefined,
|
|
2264
|
+
nullifier_ref: nullifierValue && !String(nullifierValue).startsWith('sha256:') ? nullifierValue : undefined,
|
|
2265
|
+
revoked_at: getFlag(flags, ['revoked-at', 'revokedAt']),
|
|
2266
|
+
transaction_submitted: false,
|
|
2267
|
+
raw_memory_on_chain: false,
|
|
2268
|
+
});
|
|
2269
|
+
assertChainArtifact(validateCapabilityRevocation, revocation);
|
|
2270
|
+
return chainWriteOrPrint(flags, io, revocation, {
|
|
2271
|
+
artifact_type: revocation.schema,
|
|
2272
|
+
capability_revocation_id: revocation.capability_revocation_id,
|
|
2273
|
+
capability_revocation_hash: revocation.capability_revocation_hash ?? proofNetworkSha256Json(revocation),
|
|
2274
|
+
});
|
|
2275
|
+
}
|
|
2276
|
+
|
|
2277
|
+
export async function chainAttestCommand(flags, io) {
|
|
2278
|
+
const reportHash = getFlag(flags, ['report-hash', 'reportHash']);
|
|
2279
|
+
const reportFile = getFlag(flags, ['report-file', 'reportFile']);
|
|
2280
|
+
const resolvedReportHash = reportHash || (reportFile ? await sha256PublicFile(resolve(String(reportFile))) : undefined);
|
|
2281
|
+
if (!resolvedReportHash) throw new Error('Missing required --report-hash or --report-file.');
|
|
2282
|
+
const scores = scoreFlags(flags);
|
|
2283
|
+
const metricsHash = getFlag(flags, ['metrics-hash', 'metricsHash'], proofNetworkSha256Json({ scores }));
|
|
2284
|
+
const attestation = createBenchmarkAttestation({
|
|
2285
|
+
report_hash: resolvedReportHash,
|
|
2286
|
+
report_file_hash: resolvedReportHash,
|
|
2287
|
+
dataset_ref: requireFlag(flags, ['dataset-ref', 'datasetRef', 'dataset-manifest', 'datasetManifest'], 'dataset-ref'),
|
|
2288
|
+
runner_ref: requireFlag(flags, ['runner-ref', 'runnerRef'], 'runner-ref'),
|
|
2289
|
+
package_ref: requireFlag(flags, ['package-ref', 'packageRef'], 'package-ref'),
|
|
2290
|
+
metrics: scores,
|
|
2291
|
+
metrics_hash: metricsHash,
|
|
2292
|
+
attestation_ref: getFlag(flags, ['attestation-ref', 'attestationRef']),
|
|
2293
|
+
created_at: getFlag(flags, ['created-at', 'createdAt']),
|
|
2294
|
+
transaction_submitted: false,
|
|
2295
|
+
raw_memory_on_chain: false,
|
|
2296
|
+
});
|
|
2297
|
+
assertChainArtifact(validateBenchmarkAttestation, attestation);
|
|
2298
|
+
return chainWriteOrPrint(flags, io, attestation, {
|
|
2299
|
+
artifact_type: attestation.schema,
|
|
2300
|
+
benchmark_attestation_id: attestation.benchmark_attestation_id,
|
|
2301
|
+
benchmark_attestation_hash: attestation.benchmark_attestation_hash ?? proofNetworkSha256Json(attestation),
|
|
2302
|
+
});
|
|
2303
|
+
}
|
|
2304
|
+
|
|
2305
|
+
export async function chainVerifyCommand(flags, io, positionalFile = undefined) {
|
|
2306
|
+
const inPath = resolve(String(requireFileArg(flags, ['file', 'in'], positionalFile, 'file')));
|
|
2307
|
+
const artifact = await readJson(inPath);
|
|
2308
|
+
const [schema, validate] = chainArtifactValidator(artifact);
|
|
2309
|
+
let result;
|
|
2310
|
+
try {
|
|
2311
|
+
result = chainValidationResult(validate, artifact);
|
|
2312
|
+
} catch (error) {
|
|
2313
|
+
result = { ok: false, error: { code: 'PROOF_NETWORK_INVALID', message: error.message } };
|
|
2314
|
+
}
|
|
2315
|
+
print({
|
|
2316
|
+
ok: result.ok === true,
|
|
2317
|
+
artifact_type: schema,
|
|
2318
|
+
artifact_hash: proofNetworkSha256Json(artifact),
|
|
2319
|
+
transaction_submitted: false,
|
|
2320
|
+
raw_memory_on_chain: false,
|
|
2321
|
+
validation: result,
|
|
2322
|
+
}, io);
|
|
2323
|
+
return result.ok === true ? 0 : 1;
|
|
2324
|
+
}
|
|
2325
|
+
|
|
2326
|
+
|
|
2091
2327
|
export async function meterEventCommand(flags, io) {
|
|
2092
2328
|
const event = createUsageEvent({
|
|
2093
2329
|
tenant_id: requireFlag(flags, ['tenant', 'tenant-id', 'tenantId'], 'tenant'),
|
|
@@ -2306,6 +2542,11 @@ function usage() {
|
|
|
2306
2542
|
'settlement receipt',
|
|
2307
2543
|
'settlement verify',
|
|
2308
2544
|
'settlement batch',
|
|
2545
|
+
'chain anchor',
|
|
2546
|
+
'chain grant',
|
|
2547
|
+
'chain revoke',
|
|
2548
|
+
'chain attest',
|
|
2549
|
+
'chain verify',
|
|
2309
2550
|
],
|
|
2310
2551
|
connector_options: {
|
|
2311
2552
|
'--bundle <path>': 'Absolute local Enigma vault bundle path rendered as ENIGMA_BUNDLE.',
|
|
@@ -2401,6 +2642,14 @@ function usage() {
|
|
|
2401
2642
|
batch: 'enigma settlement batch --receipts <receipts.json> --batch-ref <ref> [--asset <asset>] [--out <file>]',
|
|
2402
2643
|
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
2644
|
},
|
|
2645
|
+
chain: {
|
|
2646
|
+
anchor: 'enigma chain anchor --root <sha256:...> [--root <sha256:...>] [--ref <public-ref>] [--authority <public-authority-ref>] [--batch-ref <ref>] [--out <file>]',
|
|
2647
|
+
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>]',
|
|
2648
|
+
revoke: 'enigma chain revoke --grant-hash <sha256:...> --reason <public-reason-code> [--revocation-ref <public-ref>] [--out <file>]',
|
|
2649
|
+
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>]',
|
|
2650
|
+
verify: 'enigma chain verify --file <proof-artifact.json>',
|
|
2651
|
+
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.',
|
|
2652
|
+
},
|
|
2404
2653
|
relay_gateway_options: {
|
|
2405
2654
|
'--host <host>': 'Bind host. Defaults to 127.0.0.1.',
|
|
2406
2655
|
'--port <port>': `Bind port. Defaults to ${DEFAULT_RELAY_PORT} for relay and ${DEFAULT_GATEWAY_PORT} for gateway.`,
|
|
@@ -2427,10 +2676,10 @@ export async function main(argv = process.argv.slice(2), io = { stdout: process.
|
|
|
2427
2676
|
print(usage(), io);
|
|
2428
2677
|
return 0;
|
|
2429
2678
|
}
|
|
2430
|
-
const twoPartCommands = ['boundary', 'mcp', 'mesh', 'enterprise', 'capsule', 'relay', 'gateway', 'connect', 'disconnect', 'import', 'native-host', 'meter', 'settlement', 'demo', 'passport'];
|
|
2679
|
+
const twoPartCommands = ['boundary', 'mcp', 'mesh', 'enterprise', 'capsule', 'relay', 'gateway', 'connect', 'disconnect', 'import', 'native-host', 'meter', 'settlement', 'chain', 'demo', 'passport'];
|
|
2431
2680
|
const flags = parseArgs(twoPartCommands.includes(command) ? argv.slice(2) : argv.slice(1));
|
|
2432
2681
|
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'))) {
|
|
2682
|
+
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
2683
|
print(usage(), io);
|
|
2435
2684
|
return 0;
|
|
2436
2685
|
}
|
|
@@ -2472,6 +2721,11 @@ export async function main(argv = process.argv.slice(2), io = { stdout: process.
|
|
|
2472
2721
|
if (command === 'settlement' && subcommand === 'receipt') return await settlementReceiptCommand(flags, io);
|
|
2473
2722
|
if (command === 'settlement' && subcommand === 'verify') return await settlementVerifyCommand(flags, io);
|
|
2474
2723
|
if (command === 'settlement' && subcommand === 'batch') return await settlementBatchCommand(flags, io, positionalFile);
|
|
2724
|
+
if (command === 'chain' && subcommand === 'anchor') return await chainAnchorCommand(flags, io);
|
|
2725
|
+
if (command === 'chain' && subcommand === 'grant') return await chainGrantCommand(flags, io);
|
|
2726
|
+
if (command === 'chain' && subcommand === 'revoke') return await chainRevokeCommand(flags, io);
|
|
2727
|
+
if (command === 'chain' && subcommand === 'attest') return await chainAttestCommand(flags, io);
|
|
2728
|
+
if (command === 'chain' && subcommand === 'verify') return await chainVerifyCommand(flags, io, positionalFile);
|
|
2475
2729
|
if (command === 'native-host' && subcommand === 'install-plan') return await nativeHostInstallPlanCommand(flags, io);
|
|
2476
2730
|
if (command === 'mesh' && subcommand === 'demo') return await meshDemoCommand(flags, io);
|
|
2477
2731
|
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.
|