enigma-memory 0.1.18 → 0.1.22
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 +76 -24
- package/apps/cli/bin/enigma-desktop.mjs +140 -0
- package/apps/cli/bin/enigma-terminal.mjs +78 -0
- package/apps/cli/bin/enigma.mjs +1923 -285
- package/apps/desktop/electron-main.cjs +217 -0
- package/apps/desktop/package.json +12 -0
- package/apps/desktop/src/app.js +264 -7
- package/apps/desktop/src/index.html +3514 -1373
- package/apps/desktop/src/launch-electron.mjs +51 -0
- package/apps/desktop/src/server.mjs +2914 -0
- package/apps/desktop/src/styles.css +2972 -260
- package/apps/desktop/src/zk-browser-prove.mjs +53 -0
- package/apps/desktop/src/zk-state.mjs +1789 -0
- package/apps/gateway/bin/enigma-gateway.mjs +102 -5
- package/apps/gateway/src/server.mjs +271 -8
- package/apps/ios/EnigmaCore/Package.swift +12 -0
- package/apps/ios/EnigmaCore/Sources/EnigmaCore/EnigmaAPIClient.swift +227 -0
- package/apps/ios/EnigmaCore/Sources/EnigmaCore/Models.swift +278 -0
- package/apps/ios/EnigmaCore/Sources/EnigmaCore/PKCE.swift +96 -0
- package/apps/ios/EnigmaCore/Sources/EnigmaCore/PrivacyMinimizer.swift +187 -0
- package/apps/ios/EnigmaCore/Sources/EnigmaCore/ToolModels.swift +129 -0
- package/apps/ios/EnigmaCore/Tests/EnigmaCoreTests/EnigmaCoreTests.swift +42 -0
- package/apps/ios/EnigmaIOS/Enigma/AppModel.swift +346 -0
- package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/AccentColor.colorset/Contents.json +12 -0
- package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/AppIcon.appiconset/Contents.json +11 -0
- package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/AppIcon.appiconset/EnigmaAppIcon.png +0 -0
- package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/Contents.json +3 -0
- package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/LaunchBackground.colorset/Contents.json +12 -0
- package/apps/ios/EnigmaIOS/Enigma/ChatView.swift +181 -0
- package/apps/ios/EnigmaIOS/Enigma/CouncilView.swift +78 -0
- package/apps/ios/EnigmaIOS/Enigma/CreateView.swift +152 -0
- package/apps/ios/EnigmaIOS/Enigma/EnigmaApp.swift +52 -0
- package/apps/ios/EnigmaIOS/Enigma/Info.plist +52 -0
- package/apps/ios/EnigmaIOS/Enigma/NaturalLanguagePrivacyTagger.swift +26 -0
- package/apps/ios/EnigmaIOS/Enigma/OAuthClient.swift +321 -0
- package/apps/ios/EnigmaIOS/Enigma/OnboardingView.swift +105 -0
- package/apps/ios/EnigmaIOS/Enigma/PrivateVaultView.swift +275 -0
- package/apps/ios/EnigmaIOS/Enigma/SecureStore.swift +76 -0
- package/apps/ios/EnigmaIOS/Enigma/SettingsView.swift +60 -0
- package/apps/ios/EnigmaIOS/Enigma/Theme.swift +80 -0
- package/apps/ios/EnigmaIOS/EnigmaIOS.xcodeproj/project.pbxproj +211 -0
- package/apps/ios/EnigmaIOS/EnigmaIOS.xcodeproj/xcshareddata/xcschemes/Enigma.xcscheme +23 -0
- package/apps/native-host/README.md +19 -8
- package/apps/native-host/bin/enigma-native-host.mjs +229 -13
- package/apps/relay/bin/enigma-relay.mjs +103 -5
- package/apps/relay/src/federation-runtime.mjs +618 -0
- package/apps/relay/src/server.mjs +310 -9
- package/apps/verifier/bin/enigma-verify.mjs +327 -11
- package/cortex-v3/circuits/build/intent_vk_bytes.json +35 -0
- package/cortex-v3/circuits/build/sale_vk_bytes.json +35 -0
- package/cortex-v3/circuits/build/vk_bytes.json +32 -0
- package/cortex-v3/proving-assets.json +64 -0
- package/cortex-v3/zk/BUILD-CONTRACT.md +87 -0
- package/cortex-v3/zk/action-transition-vk.json +119 -0
- package/cortex-v3/zk/alias-adversarial.test.mjs +220 -0
- package/cortex-v3/zk/groth16-verify-child.mjs +17 -0
- package/cortex-v3/zk/intent-witness.mjs +365 -0
- package/cortex-v3/zk/intent-witness.test.mjs +485 -0
- package/cortex-v3/zk/proving-assets.mjs +203 -0
- package/cortex-v3/zk/sale-witness.mjs +783 -0
- package/cortex-v3/zk/sale-witness.test.mjs +784 -0
- package/cortex-v3/zk/sealed-sale-release-vk.json +119 -0
- package/cortex-v3/zk/settlement-evidence.mjs +722 -0
- package/cortex-v3/zk/setup-intent.mjs +688 -0
- package/cortex-v3/zk/setup-sale.mjs +666 -0
- package/cortex-v3/zk/setup.mjs +594 -0
- package/cortex-v3/zk/witness.mjs +184 -0
- package/cortex-v3/zk/zk-codec.mjs +232 -0
- package/cortex-v3/zk/zk-codec.test.mjs +293 -0
- package/cortex-v3/zk/zk-settle.mjs +370 -0
- package/cortex-v3/zk/zk-tree.mjs +256 -0
- package/cortex-v3/zk/zk-tree.test.mjs +419 -0
- package/deploy/docker-compose.local-production-simulation.yml +36 -0
- package/docs/browser-extension-install.md +8 -6
- package/docs/client-connectors.md +15 -11
- package/docs/developer-ecosystem.md +15 -13
- package/docs/enigma-memory-ready-conformance.md +11 -9
- package/docs/install-anywhere.md +61 -28
- package/docs/installers-and-desktop.md +8 -7
- package/docs/novelty-invention-candidates.md +161 -161
- package/docs/proof-network-claim-boundaries.md +320 -318
- package/examples/01-quickstart-agent/index.mjs +49 -0
- package/examples/01_agent_memory_quickstart.mjs +57 -0
- package/examples/02-multi-agent-swarm/index.mjs +57 -0
- package/examples/02_cross_model_passport.mjs +64 -0
- package/examples/03-langchain-memory/index.mjs +41 -0
- package/examples/03_poseidon_commitment_verification.mjs +71 -0
- package/examples/04-python-trading-agent/trader.py +49 -0
- package/examples/README.md +27 -0
- package/examples/ci/github-actions.yml +7 -2
- package/package.json +142 -11
- package/packages/adapters/PACKAGE_CONTRACT.md +1 -1
- package/packages/connectors/src/index.js +196 -4
- package/packages/connectors/swarm-router.mjs +168 -0
- package/packages/core/src/index.js +248 -1
- package/packages/core/src/version.mjs +7 -0
- package/packages/dev-tools/package.json +19 -0
- package/packages/dev-tools/src/index.js +4 -0
- package/packages/dev-tools/src/memory-benchmark-suite.js +112 -0
- package/packages/dev-tools/src/swarm-simulator.js +101 -0
- package/packages/dev-tools/src/vault-inspector.js +114 -0
- package/packages/dev-tools/src/vector-benchmark.js +100 -0
- package/packages/developer-platform/src/access-credentials.js +341 -0
- package/packages/developer-platform/src/http.js +132 -0
- package/packages/developer-platform/src/index.js +4 -0
- package/packages/developer-platform/src/usage-http.js +60 -0
- package/packages/developer-platform/src/usage.js +295 -0
- package/packages/enclave-runtime/attestation.mjs +159 -0
- package/packages/enclave-runtime/index.mjs +47 -0
- package/packages/enclave-runtime/session-manager.mjs +253 -0
- package/packages/enclave-runtime/zeroization-proof.mjs +227 -0
- package/packages/enigma-reflex/package.json +14 -0
- package/packages/enigma-reflex/src/index.js +204 -0
- package/packages/enigma-reflex/training/generate-dataset.mjs +40 -0
- package/packages/enigma-reflex/training/requirements.txt +8 -0
- package/packages/enigma-reflex/training/train.py +314 -0
- package/packages/enigma-weave/LICENSE +22 -0
- package/packages/enigma-weave/UPSTREAM.json +21 -0
- package/packages/enigma-weave/package.json +14 -0
- package/packages/enigma-weave/src/index.js +286 -0
- package/packages/hosted-cloud/src/index.js +80 -5
- package/packages/importers/src/index.js +432 -0
- package/packages/inference-runtime/src/browser.js +401 -0
- package/packages/inference-runtime/src/chat.js +265 -0
- package/packages/inference-runtime/src/code.js +407 -0
- package/packages/inference-runtime/src/contracts.js +162 -0
- package/packages/inference-runtime/src/http.js +232 -0
- package/packages/inference-runtime/src/image.js +186 -0
- package/packages/inference-runtime/src/index.js +10 -0
- package/packages/inference-runtime/src/model-router.js +320 -0
- package/packages/inference-runtime/src/platform.js +125 -0
- package/packages/inference-runtime/src/privacy.js +400 -0
- package/packages/inference-runtime/src/video.js +253 -0
- package/packages/mcp-server/README.md +22 -6
- package/packages/mcp-server/bin/enigma-mcp.mjs +2 -1
- package/packages/mcp-server/src/index.js +1418 -105
- package/packages/mcp-server/src/oauth.js +561 -0
- package/packages/mcp-server/src/private-handoff.js +84 -0
- package/packages/mcp-server/src/remote-http.js +273 -0
- package/packages/mcp-server/src/remote-policy.js +72 -0
- package/packages/mcp-server/swarm-bridge.mjs +361 -0
- package/packages/mesh/index.d.ts +283 -0
- package/packages/mesh/package.json +23 -0
- package/packages/mesh/src/crypto.js +189 -0
- package/packages/mesh/src/federation-packets.js +353 -0
- package/packages/mesh/src/gossip.js +311 -0
- package/packages/mesh/src/index.js +6 -0
- package/packages/mesh/src/protocol.js +255 -0
- package/packages/mesh/src/router.js +279 -0
- package/packages/mesh/src/transport.js +306 -0
- package/packages/passport/src/index.js +426 -1
- package/packages/private-economy/src/credits-http.js +100 -0
- package/packages/private-economy/src/credits.js +447 -0
- package/packages/private-economy/src/index.js +5 -0
- package/packages/private-economy/src/payments-http.js +120 -0
- package/packages/private-economy/src/payments.js +509 -0
- package/packages/private-economy/src/x402.js +346 -0
- package/packages/proof-network/PACKAGE_CONTRACT.md +21 -0
- package/packages/rag/index.d.ts +182 -0
- package/packages/rag/models/Xenova/all-MiniLM-L6-v2/THIRD_PARTY_LICENSES.txt +207 -0
- package/packages/rag/models/Xenova/all-MiniLM-L6-v2/config.json +25 -0
- package/packages/rag/models/Xenova/all-MiniLM-L6-v2/onnx/model_quantized.onnx +0 -0
- package/packages/rag/models/Xenova/all-MiniLM-L6-v2/sha256-manifest.json +28 -0
- package/packages/rag/models/Xenova/all-MiniLM-L6-v2/tokenizer.json +30686 -0
- package/packages/rag/models/Xenova/all-MiniLM-L6-v2/tokenizer_config.json +15 -0
- package/packages/rag/package.json +27 -0
- package/packages/rag/src/blinded-search.js +109 -0
- package/packages/rag/src/bm25.js +169 -0
- package/packages/rag/src/embeddings.js +459 -0
- package/packages/rag/src/hybrid.js +76 -0
- package/packages/rag/src/index.js +38 -0
- package/packages/rag/src/reranker.js +61 -0
- package/packages/rag/src/research.js +107 -0
- package/packages/rag/src/vector-store.js +430 -0
- package/packages/rag/src/verify-model-artifacts.mjs +4 -0
- package/packages/sdk/index.d.ts +760 -0
- package/packages/sdk/package.json +33 -0
- package/packages/sdk/python/README.md +24 -0
- package/packages/sdk/python/enigma_sdk.py +250 -0
- package/packages/sdk/python/pyproject.toml +34 -0
- package/packages/sdk/python/requirements.txt +1 -0
- package/packages/sdk/python/setup.py +20 -0
- package/packages/sdk/src/federation/capability-grant.js +389 -0
- package/packages/sdk/src/federation/federation-router.js +360 -0
- package/packages/sdk/src/federation/ghostmesh-bridge.js +497 -0
- package/packages/sdk/src/federation/index.js +3 -0
- package/packages/sdk/src/index.js +1796 -0
- package/packages/sdk/src/intelligence/contradiction.js +337 -0
- package/packages/sdk/src/intelligence/decision-engine.js +155 -0
- package/packages/sdk/src/intelligence/index.js +4 -0
- package/packages/sdk/src/intelligence/ontology.js +122 -0
- package/packages/sdk/src/intelligence/temporal.js +123 -0
- package/packages/sdk/src/market-client.js +142 -0
- package/packages/sdk/src/mesh-client.js +110 -0
- package/packages/sdk/src/middleware/index.js +3 -0
- package/packages/sdk/src/middleware/langchain.js +159 -0
- package/packages/sdk/src/middleware/llamaindex.js +101 -0
- package/packages/sdk/src/middleware/vercel-ai.js +112 -0
- package/packages/sdk/src/rag-client.js +85 -0
- package/packages/sdk/src/swarm-orchestrator.js +260 -0
- package/packages/settlement/PACKAGE_CONTRACT.md +1 -1
- package/packages/snapcompact/THIRD_PARTY_LICENSES.txt +40 -0
- package/packages/snapcompact/assets/8x13-latin1.bdf +3837 -0
- package/packages/snapcompact/index.d.ts +284 -0
- package/packages/snapcompact/package.json +25 -0
- package/packages/snapcompact/src/index.js +716 -0
- package/packages/storage/PACKAGE_CONTRACT.md +1 -1
- package/packages/terminal-console/animations.mjs +240 -0
- package/packages/terminal-console/auto-anchor.mjs +220 -0
- package/packages/terminal-console/banner.mjs +91 -0
- package/packages/terminal-console/commands.mjs +459 -0
- package/packages/terminal-console/delegation.mjs +152 -0
- package/packages/terminal-console/index.mjs +5 -0
- package/packages/terminal-console/outbox.mjs +143 -0
- package/packages/terminal-console/phantom-bridge.mjs +637 -0
- package/packages/terminal-console/repl.mjs +136 -0
- package/packages/terminal-console/signer-store.mjs +130 -0
- package/packages/terminal-console/solana-rpc.mjs +214 -0
- package/packages/terminal-console/solana-transport.mjs +189 -0
- package/packages/terminal-tui/dashboard.mjs +214 -0
- package/packages/terminal-tui/index.mjs +28 -0
- package/packages/terminal-tui/merkle-tree-renderer.mjs +268 -0
- package/packages/terminal-tui/telemetry-hud.mjs +137 -0
- package/packages/vault/index.d.ts +449 -0
- package/packages/vault/package.json +27 -0
- package/packages/vault/src/e2ee.mjs +393 -0
- package/packages/vault/src/enclave.js +481 -0
- package/packages/vault/src/erasure.js +207 -0
- package/packages/vault/src/index.js +1018 -155
- package/packages/vault/src/persistence.js +307 -0
- package/packages/vault/src/poseidon.js +354 -0
- package/packages/vault/src/receipt.js +459 -0
- package/scripts/benchmark-optical-context.mjs +166 -0
- package/scripts/bootstrap-enigma.mjs +502 -0
- package/scripts/build-edge-backend-workers.mjs +20 -5
- package/scripts/build-goal-completion-audit.mjs +72 -25
- package/scripts/build-hosted-api-key-lifecycle.mjs +26 -8
- package/scripts/build-hosted-customer-lifecycle.mjs +20 -3
- package/scripts/build-hosted-probe-worker.mjs +19 -4
- package/scripts/build-installer-assets.mjs +41 -21
- package/scripts/build-operator-evidence-starter.mjs +59 -1
- package/scripts/build-production-backend-env-kit.mjs +2 -0
- package/scripts/build-production-unblocker.mjs +3 -0
- package/scripts/check.mjs +17 -3
- package/scripts/collect-hosted-backend-live-evidence.mjs +49 -12
- package/scripts/install-enigma-local.mjs +18 -5
- package/scripts/release-audit.mjs +65 -109
- package/scripts/release-provenance.mjs +6 -0
- package/scripts/run-backend-readiness-smoke.mjs +112 -10
- package/scripts/scan-secrets.mjs +1 -0
- package/scripts/simulate-production-env.mjs +7 -2
- package/scripts/validate-hosted-backend-live.mjs +112 -1
- package/specs/antibody-pack-v1.schema.json +95 -0
- package/specs/antigen-envelope-v1.schema.json +81 -0
- package/specs/boundary-manifest-v1.schema.json +35 -35
- package/specs/capsule-v1.schema.json +55 -55
- package/specs/claim-boundary-manifest-v1.schema.json +22 -22
- package/specs/claim-ledger-v1.schema.json +291 -0
- package/specs/context-passport-v1.schema.json +59 -0
- package/specs/deletion-tombstone-v1.schema.json +26 -26
- package/specs/evidence-packet-v1.schema.json +177 -0
- package/specs/hosted-backend-live-evidence-v1.schema.json +72 -3
- package/specs/immune-scan-report-v1.schema.json +112 -0
- package/specs/lifecycle-receipt-log-v1.schema.json +67 -0
- package/specs/memory-atom-v1.schema.json +59 -0
- package/specs/memory-event-v1.schema.json +42 -42
- package/specs/passport-v1.schema.json +50 -50
- package/specs/proof-of-non-use-v1.schema.json +65 -0
- package/specs/quarantine-record-v1.schema.json +126 -0
- package/specs/receipt-v1.schema.json +61 -61
- package/specs/state-checkpoint-v1.schema.json +37 -37
- package/specs/trust-bundle-v1.schema.json +56 -56
- package/specs/trust-card-v1.schema.json +119 -0
- package/docs/proof-network-launch-plan.md +0 -421
- package/packages/metering/PACKAGE_CONTRACT.md +0 -20
- package/scripts/build-ai-orchestration-plan.mjs +0 -248
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { createCipheriv, createDecipheriv, randomBytes, scryptSync } from 'node:crypto';
|
|
2
|
+
import { readFile, rename, rm, writeFile } from 'node:fs/promises';
|
|
1
3
|
import { canonicalize, sha256Hex, MerkleSet, verifyReceipt } from '../../core/src/index.js';
|
|
2
4
|
import { remember } from '../../vault/src/index.js';
|
|
3
5
|
import { createCapsuleManifest, createMeshNode, verifyCapsuleManifest } from '../../mesh/src/index.js';
|
|
@@ -6,6 +8,10 @@ const REPORT_SCHEMA = 'enigma.import_report.v1';
|
|
|
6
8
|
const CAPSULE_SCHEMA = 'enigma.import_capsule.v1';
|
|
7
9
|
const CAPSULE_PAYLOAD_SCHEMA = 'enigma.import_capsule_payload.v1';
|
|
8
10
|
const VERIFIER_METADATA_SCHEMA = 'enigma.import_capsule_verifier_metadata.v1';
|
|
11
|
+
const IMMUNE_INGRESS_SCHEMA = 'enigma.immune_scan_report.v1';
|
|
12
|
+
const IMMUNE_INGRESS_DEFAULT_SOURCE = 'importer_candidate_ingress';
|
|
13
|
+
const ENCRYPTED_ARTIFACT_SCHEMA = 'enigma.importer_encrypted_artifact.v1';
|
|
14
|
+
const IMPORTER_KDF = Object.freeze({ algorithm: 'scrypt', N: 16384, r: 8, p: 1, key_length: 32 });
|
|
9
15
|
const DEFAULT_NOW = '1970-01-01T00:00:00.000Z';
|
|
10
16
|
const DEFAULT_EXPIRY = '2100-01-01T00:00:00.000Z';
|
|
11
17
|
const CONFIDENCE_ORDER = new Map([
|
|
@@ -284,6 +290,277 @@ function normalizeMetadata(value, extra = {}) {
|
|
|
284
290
|
return metadata;
|
|
285
291
|
}
|
|
286
292
|
|
|
293
|
+
const IMMUNE_DETECTOR_IDS = Object.freeze({
|
|
294
|
+
rawPublicField: 'enigma.detector.forbidden_field.raw_public_payload.v1',
|
|
295
|
+
secretField: 'enigma.detector.forbidden_field.secret_or_credential.v1',
|
|
296
|
+
providerResponseField: 'enigma.detector.forbidden_field.provider_response.v1',
|
|
297
|
+
embeddingField: 'enigma.detector.forbidden_field.embedding.v1',
|
|
298
|
+
secretValue: 'enigma.detector.secret_value.v1',
|
|
299
|
+
localPathValue: 'enigma.detector.local_path_value.v1',
|
|
300
|
+
forbiddenClaimValue: 'enigma.detector.forbidden_claim_value.v1',
|
|
301
|
+
rawStringCandidate: 'enigma.detector.raw_string_candidate.v1',
|
|
302
|
+
cyclicCandidate: 'enigma.detector.cyclic_candidate.v1'
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
const RAW_PUBLIC_FIELD_KEYS = new Set([
|
|
306
|
+
'body',
|
|
307
|
+
'completion',
|
|
308
|
+
'completions',
|
|
309
|
+
'content',
|
|
310
|
+
'conversation',
|
|
311
|
+
'conversations',
|
|
312
|
+
'memory',
|
|
313
|
+
'memories',
|
|
314
|
+
'message',
|
|
315
|
+
'messages',
|
|
316
|
+
'plaintext',
|
|
317
|
+
'plainmemory',
|
|
318
|
+
'prompt',
|
|
319
|
+
'prompts',
|
|
320
|
+
'rawmemory',
|
|
321
|
+
'response',
|
|
322
|
+
'responses',
|
|
323
|
+
'summary',
|
|
324
|
+
'text',
|
|
325
|
+
'transcript',
|
|
326
|
+
'transcripts',
|
|
327
|
+
'value'
|
|
328
|
+
]);
|
|
329
|
+
|
|
330
|
+
const SECRET_FIELD_KEYS = new Set([
|
|
331
|
+
'accesstoken',
|
|
332
|
+
'apikey',
|
|
333
|
+
'apisecret',
|
|
334
|
+
'bearer',
|
|
335
|
+
'clientsecret',
|
|
336
|
+
'credential',
|
|
337
|
+
'credentials',
|
|
338
|
+
'password',
|
|
339
|
+
'privatekey',
|
|
340
|
+
'refreshtoken',
|
|
341
|
+
'secret',
|
|
342
|
+
'seedphrase',
|
|
343
|
+
'token'
|
|
344
|
+
]);
|
|
345
|
+
|
|
346
|
+
const PROVIDER_RESPONSE_FIELD_KEYS = new Set([
|
|
347
|
+
'providerresponse',
|
|
348
|
+
'providerresponses',
|
|
349
|
+
'providerresponsebody',
|
|
350
|
+
'responsebody'
|
|
351
|
+
]);
|
|
352
|
+
|
|
353
|
+
const EMBEDDING_FIELD_KEYS = new Set([
|
|
354
|
+
'embedding',
|
|
355
|
+
'embeddings',
|
|
356
|
+
'embeddingvector',
|
|
357
|
+
'embeddingvectors',
|
|
358
|
+
'vector',
|
|
359
|
+
'vectors'
|
|
360
|
+
]);
|
|
361
|
+
|
|
362
|
+
const PUBLIC_COMMITMENT_FIELD_RE = /(?:hash|root|ref|refs|id|ids|count|counts|schema|status|decision|policy|capability|signature|signer|nullifier|timestamp|generatedat|issuedat|expiresat)$/u;
|
|
363
|
+
const SECRET_VALUE_RE = /(?:Bearer\s+[A-Za-z0-9._~+/=-]{12,}|Basic\s+[A-Za-z0-9+/=-]{12,}|-----BEGIN [A-Z ]*PRIVATE KEY-----|https?:\/\/[^\s/@]+:[^\s/@]+@|sk-[A-Za-z0-9_-]{16,}|AKIA[0-9A-Z]{16}|xox[baprs]-[A-Za-z0-9-]{16,}|eyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}|(?:seed phrase|mnemonic phrase|api key secret|access token|refresh token|private key))/iu;
|
|
364
|
+
const RAW_PUBLIC_VALUE_RE = /(?:raw memory|private prompt|plaintext prompt|plain text prompt|full transcript|decrypted memory|decrypted capsule|provider response|embedding vector|launch-code phrase)/iu;
|
|
365
|
+
const LOCAL_PATH_VALUE_RE = /(?:^|[\s"'`(])(?:[A-Za-z]:[\\/][^\s"'`<>]+|\\\\[^\\/]+[\\/][^\s"'`<>]+|\/(?:Users|home)\/[^\s"'`<>]+)/u;
|
|
366
|
+
const FORBIDDEN_CLAIM_VALUE_RE = /(?:provider(?:-native|-side|\s+native|\s+side)?\s+(?:deletion|erasure|memory control|forgetting)|model\s+(?:forgetting|forgot|erasure)|makes?\s+models?\s+forget|deleted\s+from\s+every\s+provider|compliance\s+certification|certified\s+compliant|hosted\s+saas\s+ready|byoc\s+ready|benchmark\s+(?:superiority|leader)|raw\s+embeddings?\s+(?:safe|public)|hardware\s+tamper[-\s]?proof|patent(?:able|ability)|legal\s+conclusion)/iu;
|
|
367
|
+
const RAW_PUBLIC_FIELD_RE = /(?:(?:raw|plain|plaintext|cleartext|decrypted).*(?:memory|prompt|text|content|message|transcript|conversation|response|body)|(?:memory|prompt|text|content|message|transcript|conversation|response|body).*(?:raw|plain|plaintext|cleartext|decrypted)|(?:prompt|message|transcript|conversation|memory|content|text)(?:body|value))$/u;
|
|
368
|
+
const SECRET_FIELD_RE = /(?:apikey|apisecret|accesstoken|refreshtoken|tokenvalue|credential|password|privatekey|clientsecret|secretkey|seedphrase|mnemonic|bearertoken)/u;
|
|
369
|
+
const PROVIDER_RESPONSE_FIELD_RE = /(?:provider.*responses?|responses?.*body)$/u;
|
|
370
|
+
const EMBEDDING_FIELD_RE = /(?:embedding|embeddings|embeddingvector|embeddingvectors|vector|vectors)$/u;
|
|
371
|
+
|
|
372
|
+
function normalizePublicToken(value, fallback) {
|
|
373
|
+
const token = String(value ?? '').toLowerCase().replace(/[^a-z0-9_.:-]+/gu, '_').replace(/^_+|_+$/gu, '');
|
|
374
|
+
return token.length > 0 && token.length <= 96 ? token : fallback;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
function hasMeaningfulForbiddenValue(value) {
|
|
378
|
+
if (value === undefined || value === null || value === false) return false;
|
|
379
|
+
if (typeof value === 'string') return value.length > 0;
|
|
380
|
+
if (Array.isArray(value)) return value.length > 0;
|
|
381
|
+
if (isRecord(value)) return Object.keys(value).length > 0;
|
|
382
|
+
return true;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
function detectorIdsForField(key, value, options = {}) {
|
|
386
|
+
if (!hasMeaningfulForbiddenValue(value)) return [];
|
|
387
|
+
const normalized = normalizedMetadataKey(key);
|
|
388
|
+
if (PUBLIC_COMMITMENT_FIELD_RE.test(normalized)) return [];
|
|
389
|
+
const detectors = [];
|
|
390
|
+
if (!options.private_boundary && (PROVIDER_RESPONSE_FIELD_KEYS.has(normalized) || PROVIDER_RESPONSE_FIELD_RE.test(normalized))) detectors.push(IMMUNE_DETECTOR_IDS.providerResponseField);
|
|
391
|
+
if (!options.private_boundary && (EMBEDDING_FIELD_KEYS.has(normalized) || EMBEDDING_FIELD_RE.test(normalized))) detectors.push(IMMUNE_DETECTOR_IDS.embeddingField);
|
|
392
|
+
if (SECRET_FIELD_KEYS.has(normalized) || SECRET_FIELD_RE.test(normalized)) detectors.push(IMMUNE_DETECTOR_IDS.secretField);
|
|
393
|
+
if (!options.private_boundary && (RAW_PUBLIC_FIELD_KEYS.has(normalized) || RAW_PUBLIC_FIELD_RE.test(normalized))) detectors.push(IMMUNE_DETECTOR_IDS.rawPublicField);
|
|
394
|
+
return detectors;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
function detectorIdsForString(value, options = {}) {
|
|
398
|
+
const detectors = [];
|
|
399
|
+
if (SECRET_VALUE_RE.test(value)) detectors.push(IMMUNE_DETECTOR_IDS.secretValue);
|
|
400
|
+
if (!options.private_boundary && RAW_PUBLIC_VALUE_RE.test(value)) detectors.push(IMMUNE_DETECTOR_IDS.rawPublicField);
|
|
401
|
+
if (!options.private_boundary && LOCAL_PATH_VALUE_RE.test(value)) detectors.push(IMMUNE_DETECTOR_IDS.localPathValue);
|
|
402
|
+
if (FORBIDDEN_CLAIM_VALUE_RE.test(value)) detectors.push(IMMUNE_DETECTOR_IDS.forbiddenClaimValue);
|
|
403
|
+
return detectors;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
function addAntigen(antigens, detector_id, candidate_ref, path_ref) {
|
|
407
|
+
antigens.push({
|
|
408
|
+
detector_id,
|
|
409
|
+
antigen_ref: `antigen_${shortHash({ detector_id, candidate_ref, path_ref })}`
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
function candidateOpaqueRef(candidate, index) {
|
|
414
|
+
try {
|
|
415
|
+
return `candidate_${shortHash({ index, root: rootOf(candidate) })}`;
|
|
416
|
+
} catch {
|
|
417
|
+
return `candidate_${shortHash({ index, uncanonicalizable: true, type: Object.prototype.toString.call(candidate) })}`;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
function scanImmuneIngressValue(value, candidate_ref, antigens, path_ref, seen, options = {}) {
|
|
422
|
+
if (typeof value === 'string') {
|
|
423
|
+
for (const detector of detectorIdsForString(value, options)) addAntigen(antigens, detector, candidate_ref, path_ref);
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
if (value === null || typeof value !== 'object') return;
|
|
427
|
+
if (seen.has(value)) {
|
|
428
|
+
addAntigen(antigens, IMMUNE_DETECTOR_IDS.cyclicCandidate, candidate_ref, path_ref);
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
seen.add(value);
|
|
432
|
+
if (Array.isArray(value)) {
|
|
433
|
+
value.forEach((item, index) => scanImmuneIngressValue(item, candidate_ref, antigens, `${path_ref}.${index}`, seen, options));
|
|
434
|
+
seen.delete(value);
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
for (const [key, child] of Object.entries(value)) {
|
|
438
|
+
const childPathRef = `${path_ref}.${shortHash(key)}`;
|
|
439
|
+
for (const detector of detectorIdsForField(key, child, options)) addAntigen(antigens, detector, candidate_ref, childPathRef);
|
|
440
|
+
scanImmuneIngressValue(child, candidate_ref, antigens, childPathRef, seen, options);
|
|
441
|
+
}
|
|
442
|
+
seen.delete(value);
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
function immuneIngressCandidates(input, options = {}) {
|
|
446
|
+
const candidatesKey = options.candidates_key ?? options.candidatesKey;
|
|
447
|
+
if (candidatesKey !== undefined && isRecord(input) && Array.isArray(input[candidatesKey])) return input[candidatesKey];
|
|
448
|
+
if (Array.isArray(input)) return input;
|
|
449
|
+
if (!isRecord(input)) return input === undefined || input === null ? [] : [input];
|
|
450
|
+
for (const key of ['memory_candidates', 'memoryCandidates', 'candidates', 'candidate_objects', 'candidateObjects', 'items']) {
|
|
451
|
+
if (Array.isArray(input[key])) return input[key];
|
|
452
|
+
}
|
|
453
|
+
if (Object.prototype.hasOwnProperty.call(input, 'candidate')) return [input.candidate];
|
|
454
|
+
return [input];
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
function immuneIngressReportFromCandidates(candidates, options = {}) {
|
|
458
|
+
const source_type = normalizePublicToken(options.source_type ?? options.sourceType, IMMUNE_INGRESS_DEFAULT_SOURCE);
|
|
459
|
+
const generated_at = nowFrom(options);
|
|
460
|
+
const allAntigenRefs = [];
|
|
461
|
+
const candidateReports = candidates.map((candidate, index) => {
|
|
462
|
+
const candidate_ref = candidateOpaqueRef(candidate, index);
|
|
463
|
+
const antigens = [];
|
|
464
|
+
if (typeof candidate === 'string') addAntigen(antigens, IMMUNE_DETECTOR_IDS.rawStringCandidate, candidate_ref, 'candidate');
|
|
465
|
+
scanImmuneIngressValue(candidate, candidate_ref, antigens, 'candidate', new WeakSet(), options);
|
|
466
|
+
const detector_ids = uniqueStrings(antigens.map((antigen) => antigen.detector_id));
|
|
467
|
+
const antigenRefs = antigens.map((antigen) => antigen.antigen_ref);
|
|
468
|
+
allAntigenRefs.push(...antigenRefs);
|
|
469
|
+
return {
|
|
470
|
+
candidate_ref,
|
|
471
|
+
quarantine_decision: antigens.length > 0 ? 'quarantine' : 'accept',
|
|
472
|
+
antigen_count: antigens.length,
|
|
473
|
+
detector_ids,
|
|
474
|
+
antigen_refs: antigenRefs,
|
|
475
|
+
antigen_root: new MerkleSet(antigenRefs).root()
|
|
476
|
+
};
|
|
477
|
+
});
|
|
478
|
+
const quarantined = candidateReports.filter((candidate) => candidate.quarantine_decision === 'quarantine');
|
|
479
|
+
const accepted = candidateReports.filter((candidate) => candidate.quarantine_decision === 'accept');
|
|
480
|
+
const detector_ids = uniqueStrings(candidateReports.flatMap((candidate) => candidate.detector_ids));
|
|
481
|
+
const antigenRefs = allAntigenRefs;
|
|
482
|
+
const candidateRefs = candidateReports.map((candidate) => candidate.candidate_ref);
|
|
483
|
+
const quarantineRefs = quarantined.map((candidate) => candidate.candidate_ref);
|
|
484
|
+
const roots = {
|
|
485
|
+
candidate_root: new MerkleSet(candidateRefs).root(),
|
|
486
|
+
accepted_root: new MerkleSet(accepted.map((candidate) => candidate.candidate_ref)).root(),
|
|
487
|
+
quarantine_root: new MerkleSet(quarantineRefs).root(),
|
|
488
|
+
antigen_root: new MerkleSet(antigenRefs).root()
|
|
489
|
+
};
|
|
490
|
+
const findings = quarantined.map((candidate) => ({
|
|
491
|
+
finding_ref: `finding_${shortHash({ candidate_ref: candidate.candidate_ref, antigen_root: candidate.antigen_root })}`,
|
|
492
|
+
subject_ref: candidate.candidate_ref,
|
|
493
|
+
detector_ids: candidate.detector_ids,
|
|
494
|
+
antigen_count: candidate.antigen_count,
|
|
495
|
+
status: 'quarantined',
|
|
496
|
+
risk: 'high',
|
|
497
|
+
antigen_refs: candidate.antigen_refs,
|
|
498
|
+
antigen_root: candidate.antigen_root
|
|
499
|
+
}));
|
|
500
|
+
return {
|
|
501
|
+
schema: IMMUNE_INGRESS_SCHEMA,
|
|
502
|
+
report_id: `immune_scan_${shortHash({ source_type, generated_at, findings, roots })}`,
|
|
503
|
+
generated_at,
|
|
504
|
+
scan_root: new MerkleSet([...candidateRefs, ...antigenRefs]).root(),
|
|
505
|
+
antigen_envelope_refs: antigenRefs,
|
|
506
|
+
detector_ids,
|
|
507
|
+
findings,
|
|
508
|
+
counts: {
|
|
509
|
+
candidate_count: candidateReports.length,
|
|
510
|
+
accepted_candidate_count: accepted.length,
|
|
511
|
+
quarantined_candidate_count: quarantined.length,
|
|
512
|
+
antigen_count: candidateReports.reduce((sum, candidate) => sum + candidate.antigen_count, 0)
|
|
513
|
+
},
|
|
514
|
+
status: {
|
|
515
|
+
ok: quarantined.length === 0,
|
|
516
|
+
quarantine_decision: quarantined.length === 0 ? 'accept' : 'quarantine'
|
|
517
|
+
},
|
|
518
|
+
quarantine_refs: quarantineRefs,
|
|
519
|
+
roots,
|
|
520
|
+
public_payload_only: true,
|
|
521
|
+
private_payload_detected: antigenRefs.length > 0
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
export function createImmuneIngressReport(input = [], options = {}) {
|
|
526
|
+
return immuneIngressReportFromCandidates(immuneIngressCandidates(input, options), options);
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
export function quarantineImmuneIngressCandidates(input = [], options = {}) {
|
|
530
|
+
return createImmuneIngressReport(input, options);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
export function assertImmuneIngressPublicSafe(input = [], options = {}) {
|
|
534
|
+
const report = quarantineImmuneIngressCandidates(input, options);
|
|
535
|
+
if (!report.status.ok) {
|
|
536
|
+
const error = new Error(`Immune ingress quarantine required: ${report.counts.antigen_count} antigen(s) detected.`);
|
|
537
|
+
error.name = 'ImmuneIngressQuarantineError';
|
|
538
|
+
error.report = report;
|
|
539
|
+
throw error;
|
|
540
|
+
}
|
|
541
|
+
return report;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
export function createImporterIngressReport(candidates = [], options = {}) {
|
|
545
|
+
const privateCandidates = asArray(candidates).filter(isRecord);
|
|
546
|
+
return createImmuneIngressReport(privateCandidates, {
|
|
547
|
+
...options,
|
|
548
|
+
source_type: options.source_type ?? options.sourceType ?? 'importer_private_candidate_ingress',
|
|
549
|
+
private_boundary: true,
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
export function assertImporterCandidatesSafe(candidates = [], options = {}) {
|
|
554
|
+
const report = createImporterIngressReport(candidates, options);
|
|
555
|
+
if (!report.status.ok) {
|
|
556
|
+
const error = new Error(`Importer ingress quarantined ${report.counts.quarantined_candidate_count} unsafe candidate(s).`);
|
|
557
|
+
error.name = 'ImporterIngressQuarantineError';
|
|
558
|
+
error.report = report;
|
|
559
|
+
throw error;
|
|
560
|
+
}
|
|
561
|
+
return report;
|
|
562
|
+
}
|
|
563
|
+
|
|
287
564
|
function makeCandidate({ importer, sourceType, content, source_refs, limitations, confidence, kind, metadata }) {
|
|
288
565
|
const normalizedContent = stringValue(content);
|
|
289
566
|
if (!normalizedContent) return null;
|
|
@@ -312,6 +589,7 @@ function reportFrom(importer, sourceType, input, candidates, baseLimitations, op
|
|
|
312
589
|
...candidate,
|
|
313
590
|
limitations: uniqueStrings([...candidate.limitations, ...limitations])
|
|
314
591
|
}));
|
|
592
|
+
const immune_ingress = assertImporterCandidatesSafe(memoryCandidates, options);
|
|
315
593
|
const vault_writes = writeCandidatesToVault(memoryCandidates, options);
|
|
316
594
|
return {
|
|
317
595
|
schema: REPORT_SCHEMA,
|
|
@@ -333,6 +611,7 @@ function reportFrom(importer, sourceType, input, candidates, baseLimitations, op
|
|
|
333
611
|
source_refs: uniqueSourceRefs(memoryCandidates.flatMap((candidate) => candidate.source_refs)),
|
|
334
612
|
limitations,
|
|
335
613
|
confidence: aggregateConfidence(memoryCandidates),
|
|
614
|
+
immune_ingress,
|
|
336
615
|
memory_candidates: memoryCandidates,
|
|
337
616
|
vault_writes
|
|
338
617
|
};
|
|
@@ -363,6 +642,7 @@ function publicKeyForVault(vault) {
|
|
|
363
642
|
function writeCandidatesToVault(candidates, options) {
|
|
364
643
|
const vault = options?.vault;
|
|
365
644
|
if (!vault) return [];
|
|
645
|
+
assertImporterCandidatesSafe(candidates, options);
|
|
366
646
|
const writes = [];
|
|
367
647
|
for (const candidate of candidates) {
|
|
368
648
|
const rememberArgs = {
|
|
@@ -962,6 +1242,29 @@ export function importEnigmaCapsule(capsule, options = {}) {
|
|
|
962
1242
|
const payload = capsule.payload;
|
|
963
1243
|
const reports = asArray(payload?.reports).filter(isRecord);
|
|
964
1244
|
const memoryCandidates = collectPayloadCandidates(payload, reports);
|
|
1245
|
+
const immuneIngress = createImporterIngressReport(memoryCandidates, options);
|
|
1246
|
+
if (!immuneIngress.status.ok) {
|
|
1247
|
+
return {
|
|
1248
|
+
schema: 'enigma.import_capsule_result.v1',
|
|
1249
|
+
ok: false,
|
|
1250
|
+
capsule_id: manifest?.capsule_id ?? capsule.capsule_id,
|
|
1251
|
+
manifest_ok: false,
|
|
1252
|
+
payload_hash_ok: false,
|
|
1253
|
+
manifest_payload_hash_ok: false,
|
|
1254
|
+
verifier_metadata_ok: false,
|
|
1255
|
+
verification: {
|
|
1256
|
+
ok: false,
|
|
1257
|
+
errors: ['importer ingress quarantine required'],
|
|
1258
|
+
metadata_errors: ['unsafe capsule payload rejected before vault writes'],
|
|
1259
|
+
},
|
|
1260
|
+
complete: false,
|
|
1261
|
+
completeness: 'quarantined',
|
|
1262
|
+
limitations: ['unsafe capsule payload rejected before vault writes'],
|
|
1263
|
+
quarantine: immuneIngress,
|
|
1264
|
+
memory_candidates: [],
|
|
1265
|
+
vault_writes: [],
|
|
1266
|
+
};
|
|
1267
|
+
}
|
|
965
1268
|
const vaultWritesFromReports = mappedVaultWrites(memoryCandidates, reports);
|
|
966
1269
|
const payload_hash = isRecord(payload) ? rootOf(payload) : undefined;
|
|
967
1270
|
const active_set_root = new MerkleSet(vaultWritesFromReports.map((write) => write.memory_addr)).root();
|
|
@@ -1016,6 +1319,126 @@ export function importEnigmaCapsule(capsule, options = {}) {
|
|
|
1016
1319
|
};
|
|
1017
1320
|
}
|
|
1018
1321
|
|
|
1322
|
+
export async function persistImportReport(report, options = {}) {
|
|
1323
|
+
if (!isRecord(report) || report.schema !== REPORT_SCHEMA) throw new TypeError(`report must use ${REPORT_SCHEMA}`);
|
|
1324
|
+
return persistImporterArtifact(report, options);
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
export async function persistEnigmaCapsule(capsule, options = {}) {
|
|
1328
|
+
if (!isRecord(capsule) || capsule.schema !== CAPSULE_SCHEMA) throw new TypeError(`capsule must use ${CAPSULE_SCHEMA}`);
|
|
1329
|
+
return persistImporterArtifact(capsule, options);
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1332
|
+
export async function persistImporterArtifact(artifact, options = {}) {
|
|
1333
|
+
if (!isRecord(artifact)) throw new TypeError('artifact must be an object');
|
|
1334
|
+
const path = String(options.path ?? options.outputPath ?? '');
|
|
1335
|
+
if (path.length === 0) throw new Error('Encrypted importer persistence requires a path.');
|
|
1336
|
+
const passphrase = importerArtifactPassphrase(options);
|
|
1337
|
+
const candidates = artifactCandidates(artifact);
|
|
1338
|
+
const immuneIngress = assertImporterCandidatesSafe(candidates, options);
|
|
1339
|
+
const plaintext = Buffer.from(canonicalize(artifact), 'utf8');
|
|
1340
|
+
const salt = randomBytes(16);
|
|
1341
|
+
const iv = randomBytes(12);
|
|
1342
|
+
const key = scryptSync(passphrase, salt, IMPORTER_KDF.key_length, {
|
|
1343
|
+
N: IMPORTER_KDF.N,
|
|
1344
|
+
r: IMPORTER_KDF.r,
|
|
1345
|
+
p: IMPORTER_KDF.p,
|
|
1346
|
+
maxmem: 64 * 1024 * 1024,
|
|
1347
|
+
});
|
|
1348
|
+
const header = {
|
|
1349
|
+
schema: ENCRYPTED_ARTIFACT_SCHEMA,
|
|
1350
|
+
artifact_schema: String(artifact.schema ?? 'unknown'),
|
|
1351
|
+
created_at: nowFrom(options),
|
|
1352
|
+
payload_hash: rootOf(artifact),
|
|
1353
|
+
cipher: 'aes-256-gcm',
|
|
1354
|
+
kdf: IMPORTER_KDF,
|
|
1355
|
+
salt: salt.toString('base64'),
|
|
1356
|
+
iv: iv.toString('base64'),
|
|
1357
|
+
};
|
|
1358
|
+
const cipher = createCipheriv('aes-256-gcm', key, iv);
|
|
1359
|
+
cipher.setAAD(Buffer.from(canonicalize(header), 'utf8'));
|
|
1360
|
+
const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
1361
|
+
const envelope = {
|
|
1362
|
+
...header,
|
|
1363
|
+
tag: cipher.getAuthTag().toString('base64'),
|
|
1364
|
+
ciphertext: ciphertext.toString('base64'),
|
|
1365
|
+
};
|
|
1366
|
+
const tempPath = `${path}.tmp-${process.pid}-${Date.now()}`;
|
|
1367
|
+
try {
|
|
1368
|
+
await writeFile(tempPath, `${JSON.stringify(envelope, null, 2)}\n`, { encoding: 'utf8', mode: 0o600 });
|
|
1369
|
+
await rename(tempPath, path);
|
|
1370
|
+
} catch (error) {
|
|
1371
|
+
await rm(tempPath, { force: true }).catch(() => {});
|
|
1372
|
+
throw error;
|
|
1373
|
+
}
|
|
1374
|
+
return {
|
|
1375
|
+
schema: ENCRYPTED_ARTIFACT_SCHEMA,
|
|
1376
|
+
path,
|
|
1377
|
+
artifact_schema: header.artifact_schema,
|
|
1378
|
+
payload_hash: header.payload_hash,
|
|
1379
|
+
immune_ingress_report_id: immuneIngress.report_id,
|
|
1380
|
+
};
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
export async function loadPersistedImporterArtifact(options = {}) {
|
|
1384
|
+
const path = String(options.path ?? options.inputPath ?? '');
|
|
1385
|
+
if (path.length === 0) throw new Error('Encrypted importer persistence requires a path.');
|
|
1386
|
+
const passphrase = importerArtifactPassphrase(options);
|
|
1387
|
+
const envelope = JSON.parse(await readFile(path, 'utf8'));
|
|
1388
|
+
if (!isRecord(envelope)
|
|
1389
|
+
|| envelope.schema !== ENCRYPTED_ARTIFACT_SCHEMA
|
|
1390
|
+
|| envelope.cipher !== 'aes-256-gcm'
|
|
1391
|
+
|| envelope.kdf?.algorithm !== 'scrypt') {
|
|
1392
|
+
throw new Error('Invalid encrypted importer artifact envelope.');
|
|
1393
|
+
}
|
|
1394
|
+
const key = scryptSync(passphrase, Buffer.from(envelope.salt, 'base64'), Number(envelope.kdf.key_length), {
|
|
1395
|
+
N: Number(envelope.kdf.N),
|
|
1396
|
+
r: Number(envelope.kdf.r),
|
|
1397
|
+
p: Number(envelope.kdf.p),
|
|
1398
|
+
maxmem: 64 * 1024 * 1024,
|
|
1399
|
+
});
|
|
1400
|
+
const header = {
|
|
1401
|
+
schema: envelope.schema,
|
|
1402
|
+
artifact_schema: envelope.artifact_schema,
|
|
1403
|
+
created_at: envelope.created_at,
|
|
1404
|
+
payload_hash: envelope.payload_hash,
|
|
1405
|
+
cipher: envelope.cipher,
|
|
1406
|
+
kdf: envelope.kdf,
|
|
1407
|
+
salt: envelope.salt,
|
|
1408
|
+
iv: envelope.iv,
|
|
1409
|
+
};
|
|
1410
|
+
const decipher = createDecipheriv('aes-256-gcm', key, Buffer.from(envelope.iv, 'base64'));
|
|
1411
|
+
decipher.setAAD(Buffer.from(canonicalize(header), 'utf8'));
|
|
1412
|
+
decipher.setAuthTag(Buffer.from(envelope.tag, 'base64'));
|
|
1413
|
+
const plaintext = Buffer.concat([
|
|
1414
|
+
decipher.update(Buffer.from(envelope.ciphertext, 'base64')),
|
|
1415
|
+
decipher.final(),
|
|
1416
|
+
]).toString('utf8');
|
|
1417
|
+
const artifact = JSON.parse(plaintext);
|
|
1418
|
+
if (rootOf(artifact) !== envelope.payload_hash || artifact.schema !== envelope.artifact_schema) {
|
|
1419
|
+
throw new Error('Encrypted importer artifact integrity check failed.');
|
|
1420
|
+
}
|
|
1421
|
+
assertImporterCandidatesSafe(artifactCandidates(artifact), options);
|
|
1422
|
+
return artifact;
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1425
|
+
function importerArtifactPassphrase(options) {
|
|
1426
|
+
const value = options.passphrase ?? options.env?.ENIGMA_PASSPHRASE ?? process.env.ENIGMA_PASSPHRASE;
|
|
1427
|
+
if (typeof value !== 'string' || value.trim().length === 0) {
|
|
1428
|
+
throw new Error('Encrypted importer persistence requires a non-empty passphrase.');
|
|
1429
|
+
}
|
|
1430
|
+
return value;
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1433
|
+
function artifactCandidates(artifact) {
|
|
1434
|
+
if (artifact.schema === REPORT_SCHEMA) return asArray(artifact.memory_candidates).filter(isRecord);
|
|
1435
|
+
if (artifact.schema === CAPSULE_SCHEMA) {
|
|
1436
|
+
const reports = asArray(artifact.payload?.reports).filter(isRecord);
|
|
1437
|
+
return collectPayloadCandidates(artifact.payload, reports);
|
|
1438
|
+
}
|
|
1439
|
+
return asArray(artifact.memory_candidates).filter(isRecord);
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1019
1442
|
export function runImporterDemo(options = {}) {
|
|
1020
1443
|
const shared = { ...options, now: options.now ?? DEFAULT_NOW };
|
|
1021
1444
|
const chatgpt = importChatGptExport({
|
|
@@ -1077,7 +1500,16 @@ export default {
|
|
|
1077
1500
|
importLettaAgentFile,
|
|
1078
1501
|
importLangGraphStore,
|
|
1079
1502
|
importZepGraphitiExport,
|
|
1503
|
+
createImmuneIngressReport,
|
|
1504
|
+
quarantineImmuneIngressCandidates,
|
|
1505
|
+
assertImmuneIngressPublicSafe,
|
|
1506
|
+
createImporterIngressReport,
|
|
1507
|
+
assertImporterCandidatesSafe,
|
|
1080
1508
|
exportEnigmaCapsule,
|
|
1081
1509
|
importEnigmaCapsule,
|
|
1510
|
+
persistImportReport,
|
|
1511
|
+
persistEnigmaCapsule,
|
|
1512
|
+
persistImporterArtifact,
|
|
1513
|
+
loadPersistedImporterArtifact,
|
|
1082
1514
|
runImporterDemo
|
|
1083
1515
|
};
|