contextsynapse 1.0.0__py3-none-any.whl
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.
- contextsynapse/__init__.py +107 -0
- contextsynapse/__main__.py +9 -0
- contextsynapse/a2a/__init__.py +28 -0
- contextsynapse/a2a/client.py +120 -0
- contextsynapse/a2a/discovery.py +128 -0
- contextsynapse/a2a/handlers.py +164 -0
- contextsynapse/a2a/models.py +246 -0
- contextsynapse/a2a/streaming.py +92 -0
- contextsynapse/a2a/task_manager.py +275 -0
- contextsynapse/adapters/__init__.py +98 -0
- contextsynapse/adapters/_base.py +298 -0
- contextsynapse/adapters/autogen/__init__.py +4 -0
- contextsynapse/adapters/autogen/tools.py +34 -0
- contextsynapse/adapters/crewai/__init__.py +4 -0
- contextsynapse/adapters/crewai/tools.py +63 -0
- contextsynapse/adapters/langchain/__init__.py +19 -0
- contextsynapse/adapters/langchain/message_history.py +17 -0
- contextsynapse/adapters/langchain/retriever.py +158 -0
- contextsynapse/adapters/langchain/tools.py +43 -0
- contextsynapse/adapters/langgraph/__init__.py +21 -0
- contextsynapse/adapters/langgraph/checkpoint.py +223 -0
- contextsynapse/adapters/langgraph/context_tools.py +341 -0
- contextsynapse/adapters/langgraph/message_history.py +138 -0
- contextsynapse/adapters/langgraph/tools.py +43 -0
- contextsynapse/adapters/llamaindex/__init__.py +4 -0
- contextsynapse/adapters/llamaindex/tools.py +64 -0
- contextsynapse/adapters/openai/__init__.py +24 -0
- contextsynapse/adapters/openai/tools.py +206 -0
- contextsynapse/adapters/pydantic_ai/__init__.py +4 -0
- contextsynapse/adapters/pydantic_ai/tools.py +36 -0
- contextsynapse/adapters/swarm/__init__.py +4 -0
- contextsynapse/adapters/swarm/tools.py +44 -0
- contextsynapse/agents/__init__.py +6 -0
- contextsynapse/agents/auto_capture.py +80 -0
- contextsynapse/agents/dispatcher.py +299 -0
- contextsynapse/agents/notifications.py +112 -0
- contextsynapse/aiql/__init__.py +71 -0
- contextsynapse/aiql/cache.py +341 -0
- contextsynapse/aiql/compiler/__init__.py +62 -0
- contextsynapse/aiql/compiler/optimizer.py +126 -0
- contextsynapse/aiql/compiler/planner.py +366 -0
- contextsynapse/aiql/compiler/statistics.py +235 -0
- contextsynapse/aiql/compiler/validator.py +425 -0
- contextsynapse/aiql/engine/__init__.py +11 -0
- contextsynapse/aiql/engine/chunk_storage.py +2584 -0
- contextsynapse/aiql/engine/executor.py +7737 -0
- contextsynapse/aiql/engine/extraction_integration.py +442 -0
- contextsynapse/aiql/engine/graph_builder.py +405 -0
- contextsynapse/aiql/engine/node_creation_from_normalized.py +691 -0
- contextsynapse/aiql/engine/performance_monitor.py +289 -0
- contextsynapse/aiql/engine/postprocessing.py +365 -0
- contextsynapse/aiql/engine/ray_stage_executors.py +918 -0
- contextsynapse/aiql/engine/redis_cache.py +106 -0
- contextsynapse/aiql/engine/streaming_json.py +366 -0
- contextsynapse/aiql/engine/streaming_parquet.py +568 -0
- contextsynapse/aiql/engine/streaming_ray_chunking.py +419 -0
- contextsynapse/aiql/grammar/__init__.py +14 -0
- contextsynapse/aiql/grammar/aiql_grammar.py +1822 -0
- contextsynapse/aiql/grammar/base.py +71 -0
- contextsynapse/aiql/parser/__init__.py +46 -0
- contextsynapse/aiql/parser/aiql_parser.py +11330 -0
- contextsynapse/aiql/parser/base_parser.py +47 -0
- contextsynapse/api/__init__.py +5 -0
- contextsynapse/api/a2a_router.py +233 -0
- contextsynapse/api/admin_router.py +140 -0
- contextsynapse/api/agent_worker_router.py +978 -0
- contextsynapse/api/algorithms_router.py +317 -0
- contextsynapse/api/api.py +4144 -0
- contextsynapse/api/audit.py +204 -0
- contextsynapse/api/auth.py +441 -0
- contextsynapse/api/auth_router.py +537 -0
- contextsynapse/api/billing.py +261 -0
- contextsynapse/api/billing_router.py +275 -0
- contextsynapse/api/boundary_router.py +452 -0
- contextsynapse/api/cognition_router.py +116 -0
- contextsynapse/api/connector_router.py +237 -0
- contextsynapse/api/context_router.py +1619 -0
- contextsynapse/api/dashboard_router.py +11367 -0
- contextsynapse/api/errors.py +183 -0
- contextsynapse/api/events.py +88 -0
- contextsynapse/api/experiment_bootstrap.py +321 -0
- contextsynapse/api/experiment_orchestrator.py +1078 -0
- contextsynapse/api/experiment_router.py +2089 -0
- contextsynapse/api/feature_gate.py +89 -0
- contextsynapse/api/federation_router.py +108 -0
- contextsynapse/api/integrations.py +567 -0
- contextsynapse/api/integrations_router.py +461 -0
- contextsynapse/api/intelligence_router.py +1028 -0
- contextsynapse/api/metering.py +155 -0
- contextsynapse/api/metrics.py +112 -0
- contextsynapse/api/models.py +38 -0
- contextsynapse/api/monitoring_router.py +174 -0
- contextsynapse/api/pipeline_router.py +1437 -0
- contextsynapse/api/playground_conn.py +116 -0
- contextsynapse/api/projects_router.py +131 -0
- contextsynapse/api/queries_router.py +282 -0
- contextsynapse/api/quota.py +95 -0
- contextsynapse/api/rate_limit.py +64 -0
- contextsynapse/api/search_router.py +261 -0
- contextsynapse/api/shield_router.py +447 -0
- contextsynapse/api/tenant_guard.py +103 -0
- contextsynapse/api/tenant_quotas.py +231 -0
- contextsynapse/api/tenants.py +305 -0
- contextsynapse/api/users.py +646 -0
- contextsynapse/api/v1.py +167 -0
- contextsynapse/api/vertical_builder_router.py +387 -0
- contextsynapse/benchmark/__init__.py +15 -0
- contextsynapse/benchmark/__main__.py +64 -0
- contextsynapse/benchmark/agents.py +338 -0
- contextsynapse/benchmark/live_ab.py +338 -0
- contextsynapse/benchmark/reporter.py +149 -0
- contextsynapse/benchmark/runner.py +264 -0
- contextsynapse/benchmark/savings.py +266 -0
- contextsynapse/benchmark/token_counter.py +212 -0
- contextsynapse/benchmark/workloads.py +289 -0
- contextsynapse/buffer/__init__.py +154 -0
- contextsynapse/buffer/base.py +257 -0
- contextsynapse/buffer/duckdb_buffer.py +246 -0
- contextsynapse/buffer/file_buffer.py +229 -0
- contextsynapse/buffer/lmdb_buffer.py +286 -0
- contextsynapse/buffer/local_buffer.py +154 -0
- contextsynapse/buffer/redis_buffer.py +211 -0
- contextsynapse/buffer/sqlite_buffer.py +266 -0
- contextsynapse/cache.py +2 -0
- contextsynapse/cli/__init__.py +40 -0
- contextsynapse/cli/cli.py +475 -0
- contextsynapse/cli/config_cli.py +177 -0
- contextsynapse/cli/scaffold.py +465 -0
- contextsynapse/cognition/__init__.py +31 -0
- contextsynapse/cognition/derivation.py +55 -0
- contextsynapse/cognition/events.py +135 -0
- contextsynapse/cognition/feedback.py +52 -0
- contextsynapse/cognition/hallucination.py +90 -0
- contextsynapse/cognition/invalidation.py +70 -0
- contextsynapse/cognition/read_tracker.py +50 -0
- contextsynapse/collaboration.py +2 -0
- contextsynapse/comparison.py +2 -0
- contextsynapse/config/__init__.py +10 -0
- contextsynapse/config/connectors/amfi_nav.yaml +18 -0
- contextsynapse/config/connectors/auto_sector.yaml +20 -0
- contextsynapse/config/connectors/banking_sector.yaml +20 -0
- contextsynapse/config/connectors/energy_sector.yaml +20 -0
- contextsynapse/config/connectors/fmcg_sector.yaml +20 -0
- contextsynapse/config/connectors/nsdl_fpi.yaml +9 -0
- contextsynapse/config/connectors/nse_price.yaml +61 -0
- contextsynapse/config/connectors/pharma_sector.yaml +20 -0
- contextsynapse/config/connectors/rbi_dbie.yaml +12 -0
- contextsynapse/config/context_presets/ai_research.json +25 -0
- contextsynapse/config/context_presets/chatgpt_conversations.json +19 -0
- contextsynapse/config/context_presets/claude_conversations.json +19 -0
- contextsynapse/config/context_presets/legal_compliance.json +21 -0
- contextsynapse/config/context_presets/meeting_notes.json +21 -0
- contextsynapse/config/context_presets/slack_engineering.json +21 -0
- contextsynapse/config/context_presets/tech_climate.json +24 -0
- contextsynapse/config/context_presets/toi_politics.json +25 -0
- contextsynapse/config/database_config.py +453 -0
- contextsynapse/config/deployment.py +221 -0
- contextsynapse/config/gpt_action_schema.json +164 -0
- contextsynapse/config/indicators/india_macro.yaml +213 -0
- contextsynapse/config/logging_config.py +88 -0
- contextsynapse/config/mode_config.py +223 -0
- contextsynapse/config/schemas/api_spec.yaml +48 -0
- contextsynapse/config/schemas/architecture_doc.yaml +51 -0
- contextsynapse/config/schemas/chat_history.yaml +90 -0
- contextsynapse/config/schemas/chatgpt_conversation.yaml +101 -0
- contextsynapse/config/schemas/claude_conversation.yaml +148 -0
- contextsynapse/config/schemas/contract.yaml +48 -0
- contextsynapse/config/schemas/conversation.yaml +167 -0
- contextsynapse/config/schemas/database.yaml +74 -0
- contextsynapse/config/schemas/decision.yaml +72 -0
- contextsynapse/config/schemas/ecommerce.yaml +56 -0
- contextsynapse/config/schemas/education.yaml +42 -0
- contextsynapse/config/schemas/healthcare.yaml +133 -0
- contextsynapse/config/schemas/hr_document.yaml +48 -0
- contextsynapse/config/schemas/invoice.yaml +40 -0
- contextsynapse/config/schemas/knowledge_base.yaml +75 -0
- contextsynapse/config/schemas/legal.yaml +42 -0
- contextsynapse/config/schemas/marketing_content.yaml +48 -0
- contextsynapse/config/schemas/meeting_notes.yaml +51 -0
- contextsynapse/config/schemas/news_article.yaml +61 -0
- contextsynapse/config/schemas/real_estate.yaml +49 -0
- contextsynapse/config/schemas/requirements_doc.yaml +48 -0
- contextsynapse/config/schemas/research_paper.yaml +56 -0
- contextsynapse/config/schemas/resume.yaml +49 -0
- contextsynapse/config/schemas/retail.yaml +42 -0
- contextsynapse/config/schemas/rule_meta.yaml +173 -0
- contextsynapse/config/schemas/rules.yaml +72 -0
- contextsynapse/config/schemas/screener_meta.yaml +236 -0
- contextsynapse/config/schemas/sdlc.yaml +103 -0
- contextsynapse/config/schemas/session_graph.yaml +172 -0
- contextsynapse/config/schemas/support_ticket.yaml +48 -0
- contextsynapse/config/schemas/web.yaml +64 -0
- contextsynapse/config/sensors/earnings_calendar.yaml +52 -0
- contextsynapse/config/sensors/global_risk.yaml +53 -0
- contextsynapse/config/sensors/government_policy.yaml +54 -0
- contextsynapse/config/sensors/supply_chain.yaml +50 -0
- contextsynapse/config/sensors/templates/behavioral.yaml +56 -0
- contextsynapse/config/sensors/templates/equity_sentiment.yaml +48 -0
- contextsynapse/config/sensors/templates/global_macro.yaml +47 -0
- contextsynapse/config/sensors/templates/market_data.yaml +118 -0
- contextsynapse/config/sensors/templates/sector_technical.yaml +47 -0
- contextsynapse/config/sensors/weather.yaml +52 -0
- contextsynapse/config/storage_strategy.py +202 -0
- contextsynapse/config/templates/competitive_intel.yaml +39 -0
- contextsynapse/config/templates/geopolitical_risk.yaml +46 -0
- contextsynapse/config/templates/market_analysis.yaml +58 -0
- contextsynapse/connectors/__init__.py +15 -0
- contextsynapse/connectors/api_router.py +121 -0
- contextsynapse/connectors/base.py +357 -0
- contextsynapse/connectors/financial/audio.py +170 -0
- contextsynapse/connectors/financial/youtube.py +272 -0
- contextsynapse/connectors/github.py +164 -0
- contextsynapse/connectors/jira.py +120 -0
- contextsynapse/connectors/kafka_connector.py +124 -0
- contextsynapse/connectors/pipeline_connector.py +747 -0
- contextsynapse/connectors/registry.py +116 -0
- contextsynapse/connectors/scheduler.py +87 -0
- contextsynapse/connectors/universal.py +360 -0
- contextsynapse/context/__init__.py +96 -0
- contextsynapse/context/__main__.py +4 -0
- contextsynapse/context/acl.py +125 -0
- contextsynapse/context/agent_card.py +201 -0
- contextsynapse/context/agent_memory.py +814 -0
- contextsynapse/context/agents.py +472 -0
- contextsynapse/context/agents_redis.py +391 -0
- contextsynapse/context/assembled.py +204 -0
- contextsynapse/context/attribution.py +113 -0
- contextsynapse/context/blob.py +184 -0
- contextsynapse/context/boundaries.py +187 -0
- contextsynapse/context/boundary.py +507 -0
- contextsynapse/context/bundle.py +155 -0
- contextsynapse/context/cli.py +519 -0
- contextsynapse/context/collaboration.py +165 -0
- contextsynapse/context/compiler.py +604 -0
- contextsynapse/context/composite.py +536 -0
- contextsynapse/context/compression.py +147 -0
- contextsynapse/context/context_manager.py +888 -0
- contextsynapse/context/context_schema.py +90 -0
- contextsynapse/context/context_schema.yaml +105 -0
- contextsynapse/context/context_units.py +891 -0
- contextsynapse/context/conversation.py +488 -0
- contextsynapse/context/dedup.py +207 -0
- contextsynapse/context/document_processor.py +698 -0
- contextsynapse/context/embedding_hooks.py +338 -0
- contextsynapse/context/execution_schema.py +274 -0
- contextsynapse/context/fan_out.py +138 -0
- contextsynapse/context/frozen.py +80 -0
- contextsynapse/context/gravity.py +227 -0
- contextsynapse/context/hub.py +1401 -0
- contextsynapse/context/ingest.py +391 -0
- contextsynapse/context/injection.py +226 -0
- contextsynapse/context/interaction_graphifier.py +562 -0
- contextsynapse/context/layers.py +574 -0
- contextsynapse/context/projection.py +1195 -0
- contextsynapse/context/promotion.py +634 -0
- contextsynapse/context/proof.py +131 -0
- contextsynapse/context/propagation.py +577 -0
- contextsynapse/context/pubsub.py +135 -0
- contextsynapse/context/quality.py +1054 -0
- contextsynapse/context/quality_tracker.py +270 -0
- contextsynapse/context/scoping.py +370 -0
- contextsynapse/context/seed.py +992 -0
- contextsynapse/context/session.py +1142 -0
- contextsynapse/context/session_graph.py +593 -0
- contextsynapse/context/session_memory.py +309 -0
- contextsynapse/context/session_resolver.py +111 -0
- contextsynapse/context/skill_learning.py +237 -0
- contextsynapse/context/smart_budget.py +129 -0
- contextsynapse/context/source_policy.py +242 -0
- contextsynapse/context/store_factory.py +53 -0
- contextsynapse/context/sync.py +648 -0
- contextsynapse/context/token.py +236 -0
- contextsynapse/context/vector_integration.py +297 -0
- contextsynapse/context/webhooks.py +194 -0
- contextsynapse/context/working_memory.py +224 -0
- contextsynapse/core/__init__.py +18 -0
- contextsynapse/core/archiver.py +237 -0
- contextsynapse/core/change_stream.py +282 -0
- contextsynapse/core/checkpoint.py +310 -0
- contextsynapse/core/cloud_storage.py +387 -0
- contextsynapse/core/context_state.py +651 -0
- contextsynapse/core/cron.py +324 -0
- contextsynapse/core/datasource.py +643 -0
- contextsynapse/core/db.py +289 -0
- contextsynapse/core/federation.py +283 -0
- contextsynapse/core/graph_coordinator.py +201 -0
- contextsynapse/core/graph_intelligence.py +388 -0
- contextsynapse/core/graph_structures.py +106 -0
- contextsynapse/core/graph_sync.py +157 -0
- contextsynapse/core/hybrid_graph_storage.py +2998 -0
- contextsynapse/core/lifecycle.py +691 -0
- contextsynapse/core/multiworker.py +378 -0
- contextsynapse/core/pruning.py +312 -0
- contextsynapse/core/redis_registry.py +524 -0
- contextsynapse/core/registry.py +1043 -0
- contextsynapse/core/registry_factory.py +51 -0
- contextsynapse/core/registry_metadata.py +294 -0
- contextsynapse/core/replay.py +354 -0
- contextsynapse/core/replication.py +339 -0
- contextsynapse/core/time_travel.py +260 -0
- contextsynapse/core/write_behind.py +152 -0
- contextsynapse/core/write_context.py +39 -0
- contextsynapse/db/__init__.py +1 -0
- contextsynapse/db/postgres.py +267 -0
- contextsynapse/db/profile.py +236 -0
- contextsynapse/db/rules.py +328 -0
- contextsynapse/demo/__init__.py +0 -0
- contextsynapse/demo/report.py +147 -0
- contextsynapse/demo/runner.py +520 -0
- contextsynapse/demo/scenario.py +165 -0
- contextsynapse/demo/session_demo.py +280 -0
- contextsynapse/demo/session_report.py +143 -0
- contextsynapse/demo/universal_runner.py +257 -0
- contextsynapse/engine/__init__.py +15 -0
- contextsynapse/engine/core.py +555 -0
- contextsynapse/extraction/__init__.py +69 -0
- contextsynapse/extraction/cli.py +274 -0
- contextsynapse/extraction/config.py +107 -0
- contextsynapse/extraction/examples/example_usage.py +118 -0
- contextsynapse/extraction/examples/sample_manifest.json +53 -0
- contextsynapse/extraction/examples/sample_normalized.json +185 -0
- contextsynapse/extraction/extract_engine.py +440 -0
- contextsynapse/extraction/extractors/__init__.py +37 -0
- contextsynapse/extraction/extractors/chat_export_extractor.py +189 -0
- contextsynapse/extraction/extractors/csv_extractor.py +83 -0
- contextsynapse/extraction/extractors/docx_extractor.py +129 -0
- contextsynapse/extraction/extractors/excel_extractor.py +152 -0
- contextsynapse/extraction/extractors/html_extractor.py +146 -0
- contextsynapse/extraction/extractors/pdf_extractor.py +635 -0
- contextsynapse/extraction/extractors/pdf_extractor_layoutparser.py +408 -0
- contextsynapse/extraction/extractors/register_extractors.py +63 -0
- contextsynapse/extraction/extractors/text_extractor.py +65 -0
- contextsynapse/extraction/extractors/txt_extractor.py +120 -0
- contextsynapse/extraction/extractors/website_extractor.py +246 -0
- contextsynapse/extraction/fact_extractor.py +236 -0
- contextsynapse/extraction/file_manager.py +353 -0
- contextsynapse/extraction/hierarchy.py +239 -0
- contextsynapse/extraction/id_generator.py +450 -0
- contextsynapse/extraction/layout_detector.py +409 -0
- contextsynapse/extraction/llm_entity_extractor.py +301 -0
- contextsynapse/extraction/normalized_store.py +480 -0
- contextsynapse/extraction/normalizer.py +594 -0
- contextsynapse/extraction/parquet_writer.py +598 -0
- contextsynapse/extraction/post_processors/__init__.py +40 -0
- contextsynapse/extraction/post_processors/column_reorganizer.py +507 -0
- contextsynapse/extraction/ray_normalization.py +233 -0
- contextsynapse/extraction/ray_runner.py +207 -0
- contextsynapse/extraction/redis_schema_registry.py +222 -0
- contextsynapse/extraction/registry.py +204 -0
- contextsynapse/extraction/schema_loader.py +663 -0
- contextsynapse/extraction/schema_registry.py +230 -0
- contextsynapse/extraction/semantic_normalizer.py +245 -0
- contextsynapse/extraction/version_manager.py +314 -0
- contextsynapse/gateway/__init__.py +24 -0
- contextsynapse/gateway/action_emitter.py +212 -0
- contextsynapse/gateway/cost_tracker.py +508 -0
- contextsynapse/gateway/gateway.py +377 -0
- contextsynapse/gateway/policy.py +303 -0
- contextsynapse/governance/__init__.py +13 -0
- contextsynapse/governance/layer.py +513 -0
- contextsynapse/ingestion/__init__.py +15 -0
- contextsynapse/ingestion/amplifier.py +288 -0
- contextsynapse/ingestion/async_ingest.py +463 -0
- contextsynapse/ingestion/chunker.py +303 -0
- contextsynapse/ingestion/chunking.py +58 -0
- contextsynapse/ingestion/cleaner.py +190 -0
- contextsynapse/ingestion/cleanse.py +252 -0
- contextsynapse/ingestion/connectors/__init__.py +38 -0
- contextsynapse/ingestion/connectors/base.py +300 -0
- contextsynapse/ingestion/connectors/chatgpt_memory.py +247 -0
- contextsynapse/ingestion/connectors/claude_memory.py +274 -0
- contextsynapse/ingestion/connectors/sap_ingestor.py +208 -0
- contextsynapse/ingestion/content_detector.py +80 -0
- contextsynapse/ingestion/content_monitor.py +502 -0
- contextsynapse/ingestion/dedup.py +106 -0
- contextsynapse/ingestion/feed.py +640 -0
- contextsynapse/ingestion/filters.py +461 -0
- contextsynapse/ingestion/graph_builder.py +705 -0
- contextsynapse/ingestion/input_classifier.py +307 -0
- contextsynapse/ingestion/job_manager.py +571 -0
- contextsynapse/ingestion/llm_extractor.py +610 -0
- contextsynapse/ingestion/orchestrator.py +116 -0
- contextsynapse/ingestion/parsers/__init__.py +19 -0
- contextsynapse/ingestion/parsers/graph_parser_registry.py +103 -0
- contextsynapse/ingestion/parsers/graphml_parser.py +141 -0
- contextsynapse/ingestion/parsers/jsonld_parser.py +171 -0
- contextsynapse/ingestion/parsers/rdf_parser.py +150 -0
- contextsynapse/ingestion/pipeline_context.py +228 -0
- contextsynapse/ingestion/pipeline_store.py +1195 -0
- contextsynapse/ingestion/queue.py +133 -0
- contextsynapse/ingestion/reprocess.py +179 -0
- contextsynapse/ingestion/scenario_router.py +224 -0
- contextsynapse/ingestion/schema_extractor.py +759 -0
- contextsynapse/ingestion/schema_validator.py +274 -0
- contextsynapse/ingestion/sdlc_ingest.py +87 -0
- contextsynapse/ingestion/smart_ingest.py +2451 -0
- contextsynapse/ingestion/source_connector.py +171 -0
- contextsynapse/ingestion/stage_executor.py +2095 -0
- contextsynapse/ingestion/stages/__init__.py +9 -0
- contextsynapse/ingestion/stages/tabular_to_graph.py +289 -0
- contextsynapse/ingestion/strategies.py +386 -0
- contextsynapse/ingestion/universal/__init__.py +4 -0
- contextsynapse/ingestion/universal/_operator_registry.py +59 -0
- contextsynapse/ingestion/universal/ingest_content.py +32 -0
- contextsynapse/ingestion/universal/operators/__init__.py +1 -0
- contextsynapse/ingestion/universal/operators/base.py +19 -0
- contextsynapse/ingestion/universal/operators/build_edges.py +75 -0
- contextsynapse/ingestion/universal/operators/cluster_topics.py +397 -0
- contextsynapse/ingestion/universal/operators/deduplicate.py +45 -0
- contextsynapse/ingestion/universal/operators/detect_signals.py +90 -0
- contextsynapse/ingestion/universal/operators/embed.py +80 -0
- contextsynapse/ingestion/universal/operators/extract_entities.py +253 -0
- contextsynapse/ingestion/universal/operators/extract_preferences.py +117 -0
- contextsynapse/ingestion/universal/operators/filter_content.py +69 -0
- contextsynapse/ingestion/universal/operators/index_bm25.py +52 -0
- contextsynapse/ingestion/universal/operators/infer_domains.py +69 -0
- contextsynapse/ingestion/universal/operators/link_cross_reference.py +210 -0
- contextsynapse/ingestion/universal/operators/parse_records.py +66 -0
- contextsynapse/ingestion/universal/operators/resolve_entities.py +261 -0
- contextsynapse/ingestion/universal/operators/scanners/__init__.py +16 -0
- contextsynapse/ingestion/universal/operators/scanners/edges.py +173 -0
- contextsynapse/ingestion/universal/operators/scanners/git.py +187 -0
- contextsynapse/ingestion/universal/operators/scanners/github.py +135 -0
- contextsynapse/ingestion/universal/operators/scanners/github_api.py +509 -0
- contextsynapse/ingestion/universal/operators/scanners/helpers.py +67 -0
- contextsynapse/ingestion/universal/operators/scanners/jira.py +65 -0
- contextsynapse/ingestion/universal/operators/scanners/llm_enrichment.py +82 -0
- contextsynapse/ingestion/universal/operators/scanners/repo.py +149 -0
- contextsynapse/ingestion/universal/operators/sdlc_scan.py +213 -0
- contextsynapse/ingestion/universal/operators/spec_scanner.py +149 -0
- contextsynapse/ingestion/universal/operators/store_documents.py +72 -0
- contextsynapse/ingestion/universal/operators/synthesize_cu.py +180 -0
- contextsynapse/ingestion/universal/operators/validate_gate.py +65 -0
- contextsynapse/ingestion/universal/parsers/__init__.py +5 -0
- contextsynapse/ingestion/universal/parsers/record_parser.py +203 -0
- contextsynapse/ingestion/universal/parsers/turn_parser.py +329 -0
- contextsynapse/ingestion/universal/shared_signals.py +161 -0
- contextsynapse/ingestion/universal/stage_executor.py +219 -0
- contextsynapse/ingestion/web_crawler.py +265 -0
- contextsynapse/intelligence/__init__.py +53 -0
- contextsynapse/intelligence/alerts.py +198 -0
- contextsynapse/intelligence/collector.py +655 -0
- contextsynapse/intelligence/comparison.py +198 -0
- contextsynapse/intelligence/config.py +56 -0
- contextsynapse/intelligence/conflict_detector.py +182 -0
- contextsynapse/intelligence/context_gaps.py +192 -0
- contextsynapse/intelligence/context_radar.py +135 -0
- contextsynapse/intelligence/correlation_engine.py +416 -0
- contextsynapse/intelligence/correlation_template.py +120 -0
- contextsynapse/intelligence/dedup.py +296 -0
- contextsynapse/intelligence/event_bus.py +91 -0
- contextsynapse/intelligence/feedback_loop.py +101 -0
- contextsynapse/intelligence/freshness.py +307 -0
- contextsynapse/intelligence/fundamental_feed.py +551 -0
- contextsynapse/intelligence/geo_data.py +170 -0
- contextsynapse/intelligence/geo_reference.py +112 -0
- contextsynapse/intelligence/graph_fusion.py +465 -0
- contextsynapse/intelligence/heuristics.py +176 -0
- contextsynapse/intelligence/impact_tracker.py +336 -0
- contextsynapse/intelligence/macro_indicators.py +319 -0
- contextsynapse/intelligence/ocr.py +104 -0
- contextsynapse/intelligence/persistence.py +267 -0
- contextsynapse/intelligence/pipeline_health.py +130 -0
- contextsynapse/intelligence/price_feed.py +221 -0
- contextsynapse/intelligence/rate_limiter.py +130 -0
- contextsynapse/intelligence/reactive.py +411 -0
- contextsynapse/intelligence/runtime_context.py +390 -0
- contextsynapse/intelligence/sentiment_decay.py +426 -0
- contextsynapse/intelligence/session.py +277 -0
- contextsynapse/intelligence/signal_hierarchy.py +438 -0
- contextsynapse/intelligence/signals.py +185 -0
- contextsynapse/intelligence/source_watcher.py +132 -0
- contextsynapse/intelligence/table_enricher.py +256 -0
- contextsynapse/intelligence/tagger.py +319 -0
- contextsynapse/intelligence/timeseries.py +209 -0
- contextsynapse/intelligence/tracker.py +318 -0
- contextsynapse/intelligence/watchdog.py +392 -0
- contextsynapse/intelligence/watchdog_manager.py +263 -0
- contextsynapse/intelligence/webhook_receiver.py +165 -0
- contextsynapse/intelligence/weight_learner.py +234 -0
- contextsynapse/llm/__init__.py +8 -0
- contextsynapse/llm/client.py +348 -0
- contextsynapse/llm/rate_limiter.py +166 -0
- contextsynapse/logging_config.py +2 -0
- contextsynapse/marketplace/__init__.py +7 -0
- contextsynapse/marketplace/registry.py +173 -0
- contextsynapse/mcp/__init__.py +11 -0
- contextsynapse/mcp/__main__.py +4 -0
- contextsynapse/mcp/auth_middleware.py +212 -0
- contextsynapse/mcp/connection_pool.py +128 -0
- contextsynapse/mcp/server.py +986 -0
- contextsynapse/mcp/session_context.py +67 -0
- contextsynapse/memory/__init__.py +34 -0
- contextsynapse/memory/engine.py +475 -0
- contextsynapse/memory/temporal.py +327 -0
- contextsynapse/metadata/__init__.py +12 -0
- contextsynapse/metadata/metadata_db.py +272 -0
- contextsynapse/metadata/metadata_query_tool.py +300 -0
- contextsynapse/metadata/metadata_tracker.py +425 -0
- contextsynapse/models/__init__.py +27 -0
- contextsynapse/models/embedding_service.py +360 -0
- contextsynapse/models/model_registry.py +228 -0
- contextsynapse/multiworker.py +2 -0
- contextsynapse/pipelines/__init__.py +1 -0
- contextsynapse/pipelines/executor.py +851 -0
- contextsynapse/pipelines/filters.py +189 -0
- contextsynapse/pipelines/models.py +176 -0
- contextsynapse/pipelines/scheduler.py +268 -0
- contextsynapse/playground/__init__.py +1 -0
- contextsynapse/playground/templates.py +85 -0
- contextsynapse/plugins/__init__.py +43 -0
- contextsynapse/plugins/api.py +66 -0
- contextsynapse/plugins/base.py +350 -0
- contextsynapse/plugins/domain_interface.py +508 -0
- contextsynapse/plugins/domain_loader.py +241 -0
- contextsynapse/plugins/loader.py +148 -0
- contextsynapse/plugins/registry.py +265 -0
- contextsynapse/project/__init__.py +11 -0
- contextsynapse/project/code_context.py +807 -0
- contextsynapse/project/connectors/__init__.py +4 -0
- contextsynapse/project/connectors/github_connector.py +113 -0
- contextsynapse/project/connectors/jira_connector.py +160 -0
- contextsynapse/project/graph.py +1023 -0
- contextsynapse/project/project_context.py +545 -0
- contextsynapse/project/scanner_registry.py +61 -0
- contextsynapse/project/schema_manager.py +322 -0
- contextsynapse/project/schemas/knowledge.yaml +59 -0
- contextsynapse/project/schemas/sdlc.yaml +369 -0
- contextsynapse/project/sdlc_schema.py +172 -0
- contextsynapse/project/spec_parser.py +85 -0
- contextsynapse/project/task_lock.py +181 -0
- contextsynapse/project/task_stream.py +203 -0
- contextsynapse/project/team_tools.py +537 -0
- contextsynapse/py.typed +0 -0
- contextsynapse/realtime/__init__.py +6 -0
- contextsynapse/realtime/collaboration.py +147 -0
- contextsynapse/rules/__init__.py +10 -0
- contextsynapse/rules/engine.py +116 -0
- contextsynapse/rules/evaluators/__init__.py +6 -0
- contextsynapse/rules/evaluators/aggregate.py +205 -0
- contextsynapse/rules/evaluators/custom.py +170 -0
- contextsynapse/rules/evaluators/pre_action.py +125 -0
- contextsynapse/rules/evaluators/temporal.py +129 -0
- contextsynapse/rules/loader.py +52 -0
- contextsynapse/rules/models.py +124 -0
- contextsynapse/rules/universal.py +393 -0
- contextsynapse/scheduler.py +229 -0
- contextsynapse/schema/__init__.py +42 -0
- contextsynapse/schema/compiler.py +252 -0
- contextsynapse/schema/composer.py +158 -0
- contextsynapse/schema/dedup.py +73 -0
- contextsynapse/schema/derivation.py +172 -0
- contextsynapse/schema/sdl.py +326 -0
- contextsynapse/schema/validation_gate.py +124 -0
- contextsynapse/sdk/__init__.py +63 -0
- contextsynapse/sdk/agent.py +214 -0
- contextsynapse/sdk/client.py +269 -0
- contextsynapse/sdk/exceptions.py +23 -0
- contextsynapse/sdk/models.py +78 -0
- contextsynapse/sdk/session.py +408 -0
- contextsynapse/sdk/tracked.py +218 -0
- contextsynapse/sdk/worker.py +266 -0
- contextsynapse/sdk/workspace_client.py +98 -0
- contextsynapse/sdk/ws.py +41 -0
- contextsynapse/search/__init__.py +20 -0
- contextsynapse/search/embedding_cache.py +140 -0
- contextsynapse/search/enhanced_search.py +152 -0
- contextsynapse/search/fulltext.py +130 -0
- contextsynapse/search/graph_search.py +634 -0
- contextsynapse/search/lmdb_index.py +1218 -0
- contextsynapse/search/nl_to_aiql.py +199 -0
- contextsynapse/search/rag.py +1346 -0
- contextsynapse/search/rag_cache.py +167 -0
- contextsynapse/search/reasoning_chain.py +231 -0
- contextsynapse/search/redis_search.py +207 -0
- contextsynapse/search/retrieval_quality.py +314 -0
- contextsynapse/search/semantic_query.py +455 -0
- contextsynapse/search/text_resolver.py +159 -0
- contextsynapse/search/whoosh_search.py +373 -0
- contextsynapse/security/__init__.py +17 -0
- contextsynapse/security/audit.py +297 -0
- contextsynapse/security/audit_logger.py +97 -0
- contextsynapse/security/audit_trail.py +270 -0
- contextsynapse/security/auth_unified.py +284 -0
- contextsynapse/security/auto_tagger.py +230 -0
- contextsynapse/security/data_security.py +218 -0
- contextsynapse/security/encryption.py +207 -0
- contextsynapse/security/identity.py +447 -0
- contextsynapse/security/jwt_identity.py +59 -0
- contextsynapse/security/middleware.py +336 -0
- contextsynapse/security/pii.py +233 -0
- contextsynapse/security/rbac.py +96 -0
- contextsynapse/security/rls.py +205 -0
- contextsynapse/security/sanitize.py +233 -0
- contextsynapse/security/scoped_encryption.py +131 -0
- contextsynapse/security/tenant.py +401 -0
- contextsynapse/shield/__init__.py +21 -0
- contextsynapse/shield/anomaly.py +56 -0
- contextsynapse/shield/permissions.py +99 -0
- contextsynapse/shield/profile.py +103 -0
- contextsynapse/shield/shield.py +108 -0
- contextsynapse/shield/trust_engine.py +69 -0
- contextsynapse/skills/__init__.py +14 -0
- contextsynapse/skills/engine.py +233 -0
- contextsynapse/skills/loader.py +59 -0
- contextsynapse/skills/models.py +139 -0
- contextsynapse/storage/__init__.py +7 -0
- contextsynapse/storage/cache.py +208 -0
- contextsynapse/storage/columnar_store_v2.py +178 -0
- contextsynapse/storage/csr_graph_storage.py +587 -0
- contextsynapse/storage/csr_store.py +388 -0
- contextsynapse/storage/document_store.py +491 -0
- contextsynapse/storage/hnsw_index.py +294 -0
- contextsynapse/storage/hybrid_store_v2.py +278 -0
- contextsynapse/storage/lmdb_graph_storage.py +366 -0
- contextsynapse/storage/migration.py +279 -0
- contextsynapse/storage/namespace_store.py +346 -0
- contextsynapse/storage/pure_graph_storage.py +185 -0
- contextsynapse/storage/redis_graph_adapter.py +186 -0
- contextsynapse/storage/redis_graph_storage.py +375 -0
- contextsynapse/storage/router/__init__.py +29 -0
- contextsynapse/storage/router/duckdb_store.py +398 -0
- contextsynapse/storage/router/factory.py +83 -0
- contextsynapse/storage/router/interface.py +125 -0
- contextsynapse/storage/router/postgres_store.py +339 -0
- contextsynapse/storage/router/resolver.py +192 -0
- contextsynapse/storage/router/router.py +300 -0
- contextsynapse/storage/single_file_storage.py +391 -0
- contextsynapse/storage/storage_manager.py +214 -0
- contextsynapse/storage/storage_query_optimizer.py +314 -0
- contextsynapse/storage/wal.py +359 -0
- contextsynapse/temporal/__init__.py +0 -0
- contextsynapse/temporal/storage.py +106 -0
- contextsynapse/tests/__init__.py +11 -0
- contextsynapse/tests/regression/__init__.py +1 -0
- contextsynapse/tests/regression/add_metadata.py +395 -0
- contextsynapse/tests/regression/add_skip_flags.py +85 -0
- contextsynapse/tests/regression/cases/test_basic_create_node.yaml +20 -0
- contextsynapse/tests/regression/cases/test_basic_select.yaml +21 -0
- contextsynapse/tests/regression/cases/test_blockchain_audit_trail.yaml +37 -0
- contextsynapse/tests/regression/cases/test_blockchain_audit_trail_filtered.yaml +39 -0
- contextsynapse/tests/regression/cases/test_blockchain_blocks_range.yaml +39 -0
- contextsynapse/tests/regression/cases/test_blockchain_get_block.yaml +35 -0
- contextsynapse/tests/regression/cases/test_blockchain_latest_block.yaml +35 -0
- contextsynapse/tests/regression/cases/test_blockchain_length.yaml +37 -0
- contextsynapse/tests/regression/cases/test_blockchain_merkle_root.yaml +37 -0
- contextsynapse/tests/regression/cases/test_blockchain_verify.yaml +35 -0
- contextsynapse/tests/regression/cases/test_blockchain_verify_block.yaml +35 -0
- contextsynapse/tests/regression/cases/test_create_edge.yaml +28 -0
- contextsynapse/tests/regression/cases/test_delete_edge_basic.yaml +29 -0
- contextsynapse/tests/regression/cases/test_delete_node_basic.yaml +29 -0
- contextsynapse/tests/regression/cases/test_evaluation_mrr.yaml +40 -0
- contextsynapse/tests/regression/cases/test_evaluation_ndcg.yaml +40 -0
- contextsynapse/tests/regression/cases/test_evaluation_precision.yaml +40 -0
- contextsynapse/tests/regression/cases/test_evaluation_recall.yaml +40 -0
- contextsynapse/tests/regression/cases/test_group_by_basic.yaml +56 -0
- contextsynapse/tests/regression/cases/test_match_node_basic.yaml +29 -0
- contextsynapse/tests/regression/cases/test_match_node_with_order_limit.yaml +31 -0
- contextsynapse/tests/regression/cases/test_namespace_switch.yaml +18 -0
- contextsynapse/tests/regression/cases/test_pipeline_cascaded.yaml +61 -0
- contextsynapse/tests/regression/cases/test_pipeline_fixed_size_chunking.yaml +48 -0
- contextsynapse/tests/regression/cases/test_pipeline_gpt4_chunking.yaml +54 -0
- contextsynapse/tests/regression/cases/test_pipeline_hybrid_indexing.yaml +57 -0
- contextsynapse/tests/regression/cases/test_pipeline_large_embedding.yaml +52 -0
- contextsynapse/tests/regression/cases/test_pipeline_paragraph_chunking.yaml +49 -0
- contextsynapse/tests/regression/cases/test_pipeline_recursive_chunking.yaml +47 -0
- contextsynapse/tests/regression/cases/test_pipeline_run_pipeline.yaml +56 -0
- contextsynapse/tests/regression/cases/test_pipeline_section_based_chunking.yaml +53 -0
- contextsynapse/tests/regression/cases/test_pipeline_semantic_chunking.yaml +51 -0
- contextsynapse/tests/regression/cases/test_pipeline_with_entity_extraction.yaml +57 -0
- contextsynapse/tests/regression/cases/test_pipeline_with_relationships.yaml +62 -0
- contextsynapse/tests/regression/cases/test_rag_evaluation.yaml +38 -0
- contextsynapse/tests/regression/cases/test_rag_graph_bfs_with_eval.yaml +48 -0
- contextsynapse/tests/regression/cases/test_rag_graph_centrality.yaml +40 -0
- contextsynapse/tests/regression/cases/test_rag_graph_centrality_eval.yaml +35 -0
- contextsynapse/tests/regression/cases/test_rag_graph_community.yaml +40 -0
- contextsynapse/tests/regression/cases/test_rag_graph_community_eval.yaml +35 -0
- contextsynapse/tests/regression/cases/test_rag_graph_dfs_with_eval.yaml +35 -0
- contextsynapse/tests/regression/cases/test_rag_graph_multi_hop_eval.yaml +35 -0
- contextsynapse/tests/regression/cases/test_rag_graph_path.yaml +40 -0
- contextsynapse/tests/regression/cases/test_rag_graph_search_basic.yaml +38 -0
- contextsynapse/tests/regression/cases/test_rag_graph_search_bfs.yaml +52 -0
- contextsynapse/tests/regression/cases/test_rag_graph_search_dfs.yaml +41 -0
- contextsynapse/tests/regression/cases/test_rag_graph_search_multi_hop.yaml +43 -0
- contextsynapse/tests/regression/cases/test_rag_graph_search_shortest_path.yaml +41 -0
- contextsynapse/tests/regression/cases/test_rag_graph_search_weighted.yaml +43 -0
- contextsynapse/tests/regression/cases/test_rag_graph_shortest_path_eval.yaml +35 -0
- contextsynapse/tests/regression/cases/test_rag_graph_traversal.yaml +30 -0
- contextsynapse/tests/regression/cases/test_rag_graph_weighted_eval.yaml +35 -0
- contextsynapse/tests/regression/cases/test_rag_hybrid_search.yaml +33 -0
- contextsynapse/tests/regression/cases/test_rag_hybrid_with_prompt_embedding.yaml +44 -0
- contextsynapse/tests/regression/cases/test_rag_keyword_search.yaml +32 -0
- contextsynapse/tests/regression/cases/test_rag_multi_hop_graph.yaml +32 -0
- contextsynapse/tests/regression/cases/test_rag_path_based.yaml +34 -0
- contextsynapse/tests/regression/cases/test_rag_profile_based.yaml +32 -0
- contextsynapse/tests/regression/cases/test_rag_vector_search.yaml +32 -0
- contextsynapse/tests/regression/cases/test_rag_weighted_graph.yaml +34 -0
- contextsynapse/tests/regression/cases/test_rag_weighted_hybrid.yaml +31 -0
- contextsynapse/tests/regression/cases/test_semantic_boundary_chunking.yaml +57 -0
- contextsynapse/tests/regression/cases/test_semantic_boundary_detection.yaml +33 -0
- contextsynapse/tests/regression/cases/test_semantic_hash_function.yaml +30 -0
- contextsynapse/tests/regression/cases/test_semantic_hash_with_model.yaml +31 -0
- contextsynapse/tests/regression/cases/test_tcs_ingestion_fixed_size.yaml +44 -0
- contextsynapse/tests/regression/cases/test_tcs_ingestion_recursive.yaml +46 -0
- contextsynapse/tests/regression/cases/test_tcs_ingestion_section.yaml +46 -0
- contextsynapse/tests/regression/cases/test_tcs_ingestion_semantic.yaml +44 -0
- contextsynapse/tests/regression/cases/test_time_travel_as_of.yaml +35 -0
- contextsynapse/tests/regression/cases/test_time_travel_at_commit.yaml +33 -0
- contextsynapse/tests/regression/cases/test_time_travel_at_timestamp.yaml +33 -0
- contextsynapse/tests/regression/cases/test_time_travel_for_system_time_all.yaml +37 -0
- contextsynapse/tests/regression/cases/test_time_travel_versions_between.yaml +39 -0
- contextsynapse/tests/regression/cases/test_traverse_basic.yaml +31 -0
- contextsynapse/tests/regression/cases/test_traverse_max_depth.yaml +34 -0
- contextsynapse/tests/regression/cases/test_update_edge_basic.yaml +29 -0
- contextsynapse/tests/regression/evaluation_metrics.py +227 -0
- contextsynapse/tests/regression/regression_runner.py +1081 -0
- contextsynapse/tests/regression/setup_regression_data.py +212 -0
- contextsynapse/tests/regression/test_basic_only.py +84 -0
- contextsynapse/tests/regression/test_namespace_creation.py +29 -0
- contextsynapse/tests/regression/test_single_fix.py +61 -0
- contextsynapse/tests/regression/test_single_query.py +20 -0
- contextsynapse/tests/regression/validate_test_syntax.py +179 -0
- contextsynapse/tests/test_advanced_features.py +347 -0
- contextsynapse/tests/test_aiql_summary.py +283 -0
- contextsynapse/tests/test_all_aiql_queries.py +948 -0
- contextsynapse/tests/test_all_create_queries.py +213 -0
- contextsynapse/tests/test_api_vs_native.py +280 -0
- contextsynapse/tests/test_chunking_dedup.py +199 -0
- contextsynapse/tests/test_connectors.py +171 -0
- contextsynapse/tests/test_edges_and_match.py +202 -0
- contextsynapse/tests/test_extraction_pipeline_integration.py +581 -0
- contextsynapse/tests/test_name_property.py +224 -0
- contextsynapse/tests/test_node_edge_metadata.py +250 -0
- contextsynapse/tests/test_playground_conn.py +114 -0
- contextsynapse/tests/test_query_cache.py +213 -0
- contextsynapse/tests/test_source_policy_auth.py +348 -0
- contextsynapse/tests/test_temporal_and_domain.py +224 -0
- contextsynapse/tests/test_time_travel_e2e.py +571 -0
- contextsynapse/tests/test_traversal_and_aggregation.py +275 -0
- contextsynapse/tools/__init__.py +36 -0
- contextsynapse/tools/a2a_tools.py +106 -0
- contextsynapse/tools/cognition_tools.py +118 -0
- contextsynapse/tools/context.py +905 -0
- contextsynapse/tools/formatting.py +92 -0
- contextsynapse/tools/gateway_tools.py +186 -0
- contextsynapse/tools/graph.py +1700 -0
- contextsynapse/tools/intelligence.py +235 -0
- contextsynapse/tools/memory.py +118 -0
- contextsynapse/tools/registry.py +373 -0
- contextsynapse/tools/shield_tools.py +159 -0
- contextsynapse/tools/tasks.py +341 -0
- contextsynapse/tools/workspace_tools.py +124 -0
- contextsynapse/utils/__init__.py +15 -0
- contextsynapse/utils/config_loader.py +198 -0
- contextsynapse/utils/env_loader.py +156 -0
- contextsynapse/utils/file_utils.py +288 -0
- contextsynapse/utils/logging_optimizer.py +119 -0
- contextsynapse/vector/__init__.py +30 -0
- contextsynapse/vector/chroma_vector_store.py +152 -0
- contextsynapse/vector/custom_vector_store.py +537 -0
- contextsynapse/vector/faiss_vector_store.py +296 -0
- contextsynapse/vector/qdrant_vector_store.py +163 -0
- contextsynapse/vector/vector_db.py +953 -0
- contextsynapse/vector/vector_db_manager.py +197 -0
- contextsynapse/workspace/__init__.py +27 -0
- contextsynapse/workspace/base.py +94 -0
- contextsynapse/workspace/git.py +228 -0
- contextsynapse/workspace/github.py +78 -0
- contextsynapse/workspace/local.py +73 -0
- contextsynapse/workspace/tools.py +222 -0
- contextsynapse-1.0.0.dist-info/METADATA +847 -0
- contextsynapse-1.0.0.dist-info/RECORD +776 -0
- contextsynapse-1.0.0.dist-info/WHEEL +5 -0
- contextsynapse-1.0.0.dist-info/entry_points.txt +4 -0
- contextsynapse-1.0.0.dist-info/licenses/LICENSE +200 -0
- contextsynapse-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Auto-Tagging & Classification
|
|
3
|
+
===============================
|
|
4
|
+
Automatically classify graph nodes, contexts, and graphs with sensitivity levels
|
|
5
|
+
based on content analysis (PII detection, keyword matching, pattern recognition).
|
|
6
|
+
|
|
7
|
+
Tags: public | internal | confidential | restricted
|
|
8
|
+
|
|
9
|
+
Usage::
|
|
10
|
+
|
|
11
|
+
tagger = AutoTagger()
|
|
12
|
+
tags = tagger.classify_node(node_properties)
|
|
13
|
+
# {"sensitivity": "confidential", "tags": ["pii:email", "personal_data"], "pii_detected": True}
|
|
14
|
+
|
|
15
|
+
tagger.tag_context(context_id, graph_registry, context_manager)
|
|
16
|
+
# Scans all nodes, sets context-level sensitivity to highest found
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
import logging
|
|
22
|
+
import re
|
|
23
|
+
from dataclasses import dataclass, field
|
|
24
|
+
from typing import Any, Dict, List, Optional, Set
|
|
25
|
+
|
|
26
|
+
logger = logging.getLogger(__name__)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass
|
|
30
|
+
class ClassificationResult:
|
|
31
|
+
"""Result of classifying a piece of content."""
|
|
32
|
+
sensitivity: str = "public" # public | internal | confidential | restricted
|
|
33
|
+
tags: List[str] = field(default_factory=list)
|
|
34
|
+
pii_detected: bool = False
|
|
35
|
+
confidence: float = 1.0
|
|
36
|
+
reason: str = ""
|
|
37
|
+
|
|
38
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
39
|
+
return {
|
|
40
|
+
"sensitivity": self.sensitivity,
|
|
41
|
+
"tags": self.tags,
|
|
42
|
+
"pii_detected": self.pii_detected,
|
|
43
|
+
"confidence": self.confidence,
|
|
44
|
+
"reason": self.reason,
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
# Keyword patterns that indicate sensitivity levels
|
|
49
|
+
_CONFIDENTIAL_KEYWORDS = {
|
|
50
|
+
"salary", "compensation", "ssn", "social security", "bank account",
|
|
51
|
+
"credit card", "password", "secret key", "private key", "api key",
|
|
52
|
+
"medical", "diagnosis", "patient", "health record", "prescription",
|
|
53
|
+
"passport number", "aadhaar", "pan card",
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
_RESTRICTED_KEYWORDS = {
|
|
57
|
+
"classified", "top secret", "board meeting", "acquisition target",
|
|
58
|
+
"insider", "material nonpublic", "merger", "confidential strategy",
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
_INTERNAL_KEYWORDS = {
|
|
62
|
+
"internal only", "do not share", "draft", "work in progress",
|
|
63
|
+
"internal memo", "staff only", "employee",
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class AutoTagger:
|
|
68
|
+
"""Auto-classify content and tag with sensitivity levels."""
|
|
69
|
+
|
|
70
|
+
def __init__(self):
|
|
71
|
+
from .pii import get_pii_detector
|
|
72
|
+
self._pii = get_pii_detector()
|
|
73
|
+
|
|
74
|
+
def classify_text(self, text: str) -> ClassificationResult:
|
|
75
|
+
"""Classify a text string by sensitivity level."""
|
|
76
|
+
if not text:
|
|
77
|
+
return ClassificationResult(sensitivity="public")
|
|
78
|
+
|
|
79
|
+
tags = []
|
|
80
|
+
reasons = []
|
|
81
|
+
text_lower = text.lower()
|
|
82
|
+
|
|
83
|
+
# 1. PII detection (highest priority)
|
|
84
|
+
pii_result = self._pii.scan(text)
|
|
85
|
+
pii_detected = pii_result.pii_found
|
|
86
|
+
|
|
87
|
+
if pii_detected:
|
|
88
|
+
for _, pii_type in pii_result.entities:
|
|
89
|
+
tags.append(f"pii:{pii_type}")
|
|
90
|
+
reasons.append(f"PII detected: {', '.join(set(t for _,t in pii_result.entities))}")
|
|
91
|
+
|
|
92
|
+
# 2. Keyword-based classification
|
|
93
|
+
sensitivity = pii_result.sensitivity if pii_detected else "public"
|
|
94
|
+
|
|
95
|
+
for kw in _RESTRICTED_KEYWORDS:
|
|
96
|
+
if kw in text_lower:
|
|
97
|
+
sensitivity = "restricted"
|
|
98
|
+
tags.append("classified")
|
|
99
|
+
reasons.append(f"Restricted keyword: {kw}")
|
|
100
|
+
break
|
|
101
|
+
|
|
102
|
+
if sensitivity not in ("restricted",):
|
|
103
|
+
for kw in _CONFIDENTIAL_KEYWORDS:
|
|
104
|
+
if kw in text_lower:
|
|
105
|
+
if sensitivity not in ("restricted",):
|
|
106
|
+
sensitivity = "confidential"
|
|
107
|
+
tags.append("sensitive_data")
|
|
108
|
+
reasons.append(f"Confidential keyword: {kw}")
|
|
109
|
+
break
|
|
110
|
+
|
|
111
|
+
if sensitivity == "public":
|
|
112
|
+
for kw in _INTERNAL_KEYWORDS:
|
|
113
|
+
if kw in text_lower:
|
|
114
|
+
sensitivity = "internal"
|
|
115
|
+
tags.append("internal")
|
|
116
|
+
reasons.append(f"Internal keyword: {kw}")
|
|
117
|
+
break
|
|
118
|
+
|
|
119
|
+
return ClassificationResult(
|
|
120
|
+
sensitivity=sensitivity,
|
|
121
|
+
tags=tags,
|
|
122
|
+
pii_detected=pii_detected,
|
|
123
|
+
confidence=0.9 if pii_detected else 0.7,
|
|
124
|
+
reason="; ".join(reasons) if reasons else "No sensitive content detected",
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
def classify_node(self, properties: Dict[str, Any]) -> ClassificationResult:
|
|
128
|
+
"""Classify a graph node's properties."""
|
|
129
|
+
# Combine all text fields for analysis
|
|
130
|
+
text_fields = ["content", "description", "name", "title", "statement",
|
|
131
|
+
"body", "text", "summary", "rationale"]
|
|
132
|
+
combined = " ".join(
|
|
133
|
+
str(properties.get(f, "")) for f in text_fields if properties.get(f)
|
|
134
|
+
)
|
|
135
|
+
return self.classify_text(combined)
|
|
136
|
+
|
|
137
|
+
def tag_node(self, properties: Dict[str, Any]) -> Dict[str, Any]:
|
|
138
|
+
"""Classify and add tags directly to node properties.
|
|
139
|
+
|
|
140
|
+
Returns updated properties dict with sensitivity, tags, pii_detected.
|
|
141
|
+
"""
|
|
142
|
+
result = self.classify_node(properties)
|
|
143
|
+
tagged = dict(properties)
|
|
144
|
+
tagged["sensitivity"] = result.sensitivity
|
|
145
|
+
tagged["pii_detected"] = result.pii_detected
|
|
146
|
+
|
|
147
|
+
existing_tags = tagged.get("tags", [])
|
|
148
|
+
if isinstance(existing_tags, str):
|
|
149
|
+
existing_tags = [t.strip() for t in existing_tags.split(",") if t.strip()]
|
|
150
|
+
tagged["tags"] = list(set(existing_tags + result.tags))
|
|
151
|
+
tagged["_auto_classified"] = True
|
|
152
|
+
|
|
153
|
+
return tagged
|
|
154
|
+
|
|
155
|
+
def tag_context(self, context_id: str, graph_registry=None,
|
|
156
|
+
context_manager=None) -> Dict[str, Any]:
|
|
157
|
+
"""Scan all nodes in a context and set context-level sensitivity.
|
|
158
|
+
|
|
159
|
+
The context gets the HIGHEST sensitivity found in any node.
|
|
160
|
+
"""
|
|
161
|
+
if not context_manager or not graph_registry:
|
|
162
|
+
return {"error": "Missing context_manager or graph_registry"}
|
|
163
|
+
|
|
164
|
+
ctx = context_manager.get_context(context_id)
|
|
165
|
+
if not ctx:
|
|
166
|
+
return {"error": f"Context {context_id} not found"}
|
|
167
|
+
|
|
168
|
+
db = graph_registry.get_graph(ctx.graph_namespace, load_if_missing=True)
|
|
169
|
+
if not db:
|
|
170
|
+
return {"error": "Graph not available"}
|
|
171
|
+
|
|
172
|
+
# Scan all nodes
|
|
173
|
+
sensitivity_levels = {"public": 0, "internal": 1, "confidential": 2, "restricted": 3}
|
|
174
|
+
max_sensitivity = "public"
|
|
175
|
+
total_nodes = 0
|
|
176
|
+
pii_count = 0
|
|
177
|
+
tagged_count = 0
|
|
178
|
+
|
|
179
|
+
for node in db.get_all_nodes():
|
|
180
|
+
props = getattr(node, "properties", {}) or {}
|
|
181
|
+
total_nodes += 1
|
|
182
|
+
|
|
183
|
+
result = self.classify_node(props)
|
|
184
|
+
|
|
185
|
+
if result.pii_detected:
|
|
186
|
+
pii_count += 1
|
|
187
|
+
|
|
188
|
+
# Update node with classification
|
|
189
|
+
if not props.get("_auto_classified"):
|
|
190
|
+
tagged_props = self.tag_node(props)
|
|
191
|
+
try:
|
|
192
|
+
from ..core.graph_structures import GraphNode
|
|
193
|
+
db.add_node(GraphNode(
|
|
194
|
+
id=node.id, label=getattr(node, "label", ""),
|
|
195
|
+
properties=tagged_props,
|
|
196
|
+
), write_through=True)
|
|
197
|
+
tagged_count += 1
|
|
198
|
+
except Exception:
|
|
199
|
+
pass
|
|
200
|
+
|
|
201
|
+
# Track highest sensitivity
|
|
202
|
+
if sensitivity_levels.get(result.sensitivity, 0) > sensitivity_levels.get(max_sensitivity, 0):
|
|
203
|
+
max_sensitivity = result.sensitivity
|
|
204
|
+
|
|
205
|
+
# Update context-level sensitivity
|
|
206
|
+
try:
|
|
207
|
+
context_manager.update_context(context_id, {"sensitivity": max_sensitivity})
|
|
208
|
+
except Exception:
|
|
209
|
+
pass
|
|
210
|
+
|
|
211
|
+
result = {
|
|
212
|
+
"context_id": context_id,
|
|
213
|
+
"total_nodes": total_nodes,
|
|
214
|
+
"nodes_tagged": tagged_count,
|
|
215
|
+
"pii_nodes": pii_count,
|
|
216
|
+
"context_sensitivity": max_sensitivity,
|
|
217
|
+
}
|
|
218
|
+
logger.info("[AUTO-TAG] Context %s: %d nodes scanned, %d PII, sensitivity=%s",
|
|
219
|
+
context_id[:12], total_nodes, pii_count, max_sensitivity)
|
|
220
|
+
return result
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
# Global singleton
|
|
224
|
+
_tagger: Optional[AutoTagger] = None
|
|
225
|
+
|
|
226
|
+
def get_auto_tagger() -> AutoTagger:
|
|
227
|
+
global _tagger
|
|
228
|
+
if _tagger is None:
|
|
229
|
+
_tagger = AutoTagger()
|
|
230
|
+
return _tagger
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
"""
|
|
2
|
+
AIContextDB Data Security System
|
|
3
|
+
Comprehensive security including encryption, access control, PII detection, and audit logging.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import hashlib
|
|
7
|
+
import json
|
|
8
|
+
from typing import Dict, List, Any, Optional, Set, Tuple
|
|
9
|
+
from dataclasses import dataclass
|
|
10
|
+
from datetime import datetime
|
|
11
|
+
import logging
|
|
12
|
+
import re
|
|
13
|
+
from enum import Enum
|
|
14
|
+
from collections import defaultdict
|
|
15
|
+
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
class AccessLevel(Enum):
|
|
19
|
+
"""Access levels for RBAC."""
|
|
20
|
+
READ = "read"
|
|
21
|
+
WRITE = "write"
|
|
22
|
+
DELETE = "delete"
|
|
23
|
+
ADMIN = "admin"
|
|
24
|
+
|
|
25
|
+
@dataclass
|
|
26
|
+
class AccessControl:
|
|
27
|
+
"""Access control entry."""
|
|
28
|
+
user_id: str
|
|
29
|
+
resource: str
|
|
30
|
+
access_level: AccessLevel
|
|
31
|
+
granted_at: datetime
|
|
32
|
+
expires_at: Optional[datetime] = None
|
|
33
|
+
|
|
34
|
+
class PIIDetector:
|
|
35
|
+
"""PII (Personally Identifiable Information) detector."""
|
|
36
|
+
|
|
37
|
+
# Patterns for common PII
|
|
38
|
+
EMAIL_PATTERN = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b'
|
|
39
|
+
PHONE_PATTERN = r'\b\d{3}[-.]?\d{3}[-.]?\d{4}\b'
|
|
40
|
+
SSN_PATTERN = r'\b\d{3}-\d{2}-\d{4}\b'
|
|
41
|
+
CREDIT_CARD_PATTERN = r'\b\d{4}[- ]?\d{4}[- ]?\d{4}[- ]?\d{4}\b'
|
|
42
|
+
|
|
43
|
+
@staticmethod
|
|
44
|
+
def detect_pii(text: str) -> Dict[str, List[str]]:
|
|
45
|
+
"""Detect PII in text."""
|
|
46
|
+
pii_found = {
|
|
47
|
+
'emails': re.findall(PIIDetector.EMAIL_PATTERN, text),
|
|
48
|
+
'phones': re.findall(PIIDetector.PHONE_PATTERN, text),
|
|
49
|
+
'ssns': re.findall(PIIDetector.SSN_PATTERN, text),
|
|
50
|
+
'credit_cards': re.findall(PIIDetector.CREDIT_CARD_PATTERN, text)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
# Remove empty lists
|
|
54
|
+
return {k: v for k, v in pii_found.items() if v}
|
|
55
|
+
|
|
56
|
+
@staticmethod
|
|
57
|
+
def mask_pii(text: str, mask_char: str = '*') -> str:
|
|
58
|
+
"""Mask PII in text."""
|
|
59
|
+
masked = text
|
|
60
|
+
|
|
61
|
+
# Mask emails
|
|
62
|
+
masked = re.sub(PIIDetector.EMAIL_PATTERN, lambda m: mask_char * len(m.group()), masked)
|
|
63
|
+
|
|
64
|
+
# Mask phones
|
|
65
|
+
masked = re.sub(PIIDetector.PHONE_PATTERN, lambda m: mask_char * len(m.group()), masked)
|
|
66
|
+
|
|
67
|
+
# Mask SSNs
|
|
68
|
+
masked = re.sub(PIIDetector.SSN_PATTERN, lambda m: mask_char * len(m.group()), masked)
|
|
69
|
+
|
|
70
|
+
# Mask credit cards
|
|
71
|
+
masked = re.sub(PIIDetector.CREDIT_CARD_PATTERN, lambda m: mask_char * len(m.group()), masked)
|
|
72
|
+
|
|
73
|
+
return masked
|
|
74
|
+
|
|
75
|
+
class DataSecurity:
|
|
76
|
+
"""Comprehensive data security system."""
|
|
77
|
+
|
|
78
|
+
def __init__(self, namespace: str):
|
|
79
|
+
self.namespace = namespace
|
|
80
|
+
self.access_controls: Dict[str, List[AccessControl]] = defaultdict(list)
|
|
81
|
+
self.audit_log: List[Dict[str, Any]] = []
|
|
82
|
+
self.pii_detector = PIIDetector()
|
|
83
|
+
self.encryption_enabled = False
|
|
84
|
+
|
|
85
|
+
logger.info(f"[EMOJI] DataSecurity initialized for namespace: {namespace}")
|
|
86
|
+
|
|
87
|
+
def check_access(self, user_id: str, resource: str, required_level: AccessLevel) -> bool:
|
|
88
|
+
"""Check if user has required access."""
|
|
89
|
+
if resource not in self.access_controls:
|
|
90
|
+
return False # No access by default
|
|
91
|
+
|
|
92
|
+
for acl in self.access_controls[resource]:
|
|
93
|
+
if acl.user_id == user_id:
|
|
94
|
+
# Check expiration
|
|
95
|
+
if acl.expires_at and datetime.now() > acl.expires_at:
|
|
96
|
+
continue
|
|
97
|
+
|
|
98
|
+
# Check access level
|
|
99
|
+
if self._has_sufficient_level(acl.access_level, required_level):
|
|
100
|
+
return True
|
|
101
|
+
|
|
102
|
+
return False
|
|
103
|
+
|
|
104
|
+
def _has_sufficient_level(self, granted: AccessLevel, required: AccessLevel) -> bool:
|
|
105
|
+
"""Check if granted level is sufficient."""
|
|
106
|
+
level_hierarchy = {
|
|
107
|
+
AccessLevel.READ: 1,
|
|
108
|
+
AccessLevel.WRITE: 2,
|
|
109
|
+
AccessLevel.DELETE: 3,
|
|
110
|
+
AccessLevel.ADMIN: 4
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return level_hierarchy.get(granted, 0) >= level_hierarchy.get(required, 0)
|
|
114
|
+
|
|
115
|
+
def grant_access(self, user_id: str, resource: str, access_level: AccessLevel,
|
|
116
|
+
expires_at: Optional[datetime] = None):
|
|
117
|
+
"""Grant access to resource."""
|
|
118
|
+
acl = AccessControl(
|
|
119
|
+
user_id=user_id,
|
|
120
|
+
resource=resource,
|
|
121
|
+
access_level=access_level,
|
|
122
|
+
granted_at=datetime.now(),
|
|
123
|
+
expires_at=expires_at
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
self.access_controls[resource].append(acl)
|
|
127
|
+
self._audit_log('GRANT_ACCESS', user_id, resource, {'access_level': access_level.value})
|
|
128
|
+
|
|
129
|
+
def revoke_access(self, user_id: str, resource: str):
|
|
130
|
+
"""Revoke access to resource."""
|
|
131
|
+
if resource in self.access_controls:
|
|
132
|
+
self.access_controls[resource] = [
|
|
133
|
+
acl for acl in self.access_controls[resource] if acl.user_id != user_id
|
|
134
|
+
]
|
|
135
|
+
self._audit_log('REVOKE_ACCESS', user_id, resource)
|
|
136
|
+
|
|
137
|
+
def detect_and_mask_pii(self, data: Dict[str, Any]) -> Dict[str, Any]:
|
|
138
|
+
"""Detect and mask PII in data."""
|
|
139
|
+
masked_data = data.copy()
|
|
140
|
+
pii_detected = {}
|
|
141
|
+
|
|
142
|
+
for key, value in data.items():
|
|
143
|
+
if isinstance(value, str):
|
|
144
|
+
detected = self.pii_detector.detect_pii(value)
|
|
145
|
+
if detected:
|
|
146
|
+
pii_detected[key] = detected
|
|
147
|
+
masked_data[key] = self.pii_detector.mask_pii(value)
|
|
148
|
+
elif isinstance(value, dict):
|
|
149
|
+
masked_data[key], nested_pii = self._detect_and_mask_nested(value)
|
|
150
|
+
if nested_pii:
|
|
151
|
+
pii_detected[key] = nested_pii
|
|
152
|
+
|
|
153
|
+
if pii_detected:
|
|
154
|
+
self._audit_log('PII_DETECTED', None, None, {'pii_types': list(pii_detected.keys())})
|
|
155
|
+
|
|
156
|
+
return masked_data, pii_detected
|
|
157
|
+
|
|
158
|
+
def _detect_and_mask_nested(self, data: Dict[str, Any]) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
|
159
|
+
"""Recursively detect and mask PII in nested structures."""
|
|
160
|
+
masked = {}
|
|
161
|
+
pii_detected = {}
|
|
162
|
+
|
|
163
|
+
for key, value in data.items():
|
|
164
|
+
if isinstance(value, str):
|
|
165
|
+
detected = self.pii_detector.detect_pii(value)
|
|
166
|
+
if detected:
|
|
167
|
+
pii_detected[key] = detected
|
|
168
|
+
masked[key] = self.pii_detector.mask_pii(value)
|
|
169
|
+
else:
|
|
170
|
+
masked[key] = value
|
|
171
|
+
elif isinstance(value, dict):
|
|
172
|
+
nested_masked, nested_pii = self._detect_and_mask_nested(value)
|
|
173
|
+
masked[key] = nested_masked
|
|
174
|
+
if nested_pii:
|
|
175
|
+
pii_detected[key] = nested_pii
|
|
176
|
+
else:
|
|
177
|
+
masked[key] = value
|
|
178
|
+
|
|
179
|
+
return masked, pii_detected
|
|
180
|
+
|
|
181
|
+
def _audit_log(self, action: str, user_id: Optional[str], resource: Optional[str],
|
|
182
|
+
details: Dict[str, Any] = None):
|
|
183
|
+
"""Log security event."""
|
|
184
|
+
log_entry = {
|
|
185
|
+
'timestamp': datetime.now().isoformat(),
|
|
186
|
+
'action': action,
|
|
187
|
+
'user_id': user_id,
|
|
188
|
+
'resource': resource,
|
|
189
|
+
'details': details or {}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
self.audit_log.append(log_entry)
|
|
193
|
+
|
|
194
|
+
# Keep only last 10000 entries
|
|
195
|
+
if len(self.audit_log) > 10000:
|
|
196
|
+
self.audit_log = self.audit_log[-10000:]
|
|
197
|
+
|
|
198
|
+
def get_audit_log(self, user_id: str = None, resource: str = None,
|
|
199
|
+
start_time: datetime = None, end_time: datetime = None) -> List[Dict[str, Any]]:
|
|
200
|
+
"""Get audit log with filters."""
|
|
201
|
+
filtered = self.audit_log
|
|
202
|
+
|
|
203
|
+
if user_id:
|
|
204
|
+
filtered = [entry for entry in filtered if entry.get('user_id') == user_id]
|
|
205
|
+
|
|
206
|
+
if resource:
|
|
207
|
+
filtered = [entry for entry in filtered if entry.get('resource') == resource]
|
|
208
|
+
|
|
209
|
+
if start_time:
|
|
210
|
+
filtered = [entry for entry in filtered
|
|
211
|
+
if datetime.fromisoformat(entry['timestamp']) >= start_time]
|
|
212
|
+
|
|
213
|
+
if end_time:
|
|
214
|
+
filtered = [entry for entry in filtered
|
|
215
|
+
if datetime.fromisoformat(entry['timestamp']) <= end_time]
|
|
216
|
+
|
|
217
|
+
return filtered
|
|
218
|
+
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Data Encryption Layer
|
|
3
|
+
======================
|
|
4
|
+
Field-level encryption for graph node properties at rest.
|
|
5
|
+
|
|
6
|
+
Uses Fernet (AES-128-CBC) for symmetric encryption with key derivation
|
|
7
|
+
from a master secret. Supports searchable encryption via deterministic
|
|
8
|
+
hashing for keyword queries on encrypted fields.
|
|
9
|
+
|
|
10
|
+
For full homomorphic encryption on search, uses HMAC-based searchable
|
|
11
|
+
tokens that allow keyword matching without decrypting the full content.
|
|
12
|
+
|
|
13
|
+
Usage::
|
|
14
|
+
|
|
15
|
+
enc = FieldEncryptor(master_key="your-secret-key")
|
|
16
|
+
|
|
17
|
+
# Encrypt node properties before storage
|
|
18
|
+
encrypted = enc.encrypt_properties({"name": "John", "email": "john@x.com"}, fields=["email"])
|
|
19
|
+
# {"name": "John", "email": "gAAAAB...", "_encrypted_fields": ["email"]}
|
|
20
|
+
|
|
21
|
+
# Decrypt after retrieval
|
|
22
|
+
decrypted = enc.decrypt_properties(encrypted)
|
|
23
|
+
# {"name": "John", "email": "john@x.com"}
|
|
24
|
+
|
|
25
|
+
# Searchable token (allows keyword search on encrypted data)
|
|
26
|
+
token = enc.searchable_token("john@x.com")
|
|
27
|
+
# deterministic hash — same input always produces same token
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
from __future__ import annotations
|
|
31
|
+
|
|
32
|
+
import base64
|
|
33
|
+
import hashlib
|
|
34
|
+
import hmac
|
|
35
|
+
import json
|
|
36
|
+
import logging
|
|
37
|
+
import os
|
|
38
|
+
from typing import Any, Dict, List, Optional
|
|
39
|
+
|
|
40
|
+
logger = logging.getLogger(__name__)
|
|
41
|
+
|
|
42
|
+
# Try Fernet (cryptography package)
|
|
43
|
+
_FERNET_AVAILABLE = False
|
|
44
|
+
try:
|
|
45
|
+
from cryptography.fernet import Fernet
|
|
46
|
+
from cryptography.hazmat.primitives import hashes
|
|
47
|
+
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
|
|
48
|
+
_FERNET_AVAILABLE = True
|
|
49
|
+
except ImportError:
|
|
50
|
+
logger.info("cryptography package not installed — using fallback encryption")
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class FieldEncryptor:
|
|
54
|
+
"""Encrypt/decrypt individual node properties using Fernet (AES-128-CBC).
|
|
55
|
+
|
|
56
|
+
If the `cryptography` package isn't installed, falls back to
|
|
57
|
+
base64 encoding (NOT secure — for development only).
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
ENCRYPTED_PREFIX = "ENC:"
|
|
61
|
+
SEARCH_PREFIX = "STOK:"
|
|
62
|
+
|
|
63
|
+
def __init__(self, master_key: Optional[str] = None):
|
|
64
|
+
self._master_key = master_key or os.environ.get("CONTEXTSYNAPSE_ENCRYPTION_KEY") or os.environ.get("AICONTEXTDB_ENCRYPTION_KEY", "")
|
|
65
|
+
self._fernet = None
|
|
66
|
+
self._hmac_key = b""
|
|
67
|
+
|
|
68
|
+
if self._master_key and _FERNET_AVAILABLE:
|
|
69
|
+
# Derive Fernet key from master key using PBKDF2
|
|
70
|
+
salt = b"contextcore-field-encryption-v1"
|
|
71
|
+
kdf = PBKDF2HMAC(
|
|
72
|
+
algorithm=hashes.SHA256(),
|
|
73
|
+
length=32,
|
|
74
|
+
salt=salt,
|
|
75
|
+
iterations=100_000,
|
|
76
|
+
)
|
|
77
|
+
key = base64.urlsafe_b64encode(kdf.derive(self._master_key.encode()))
|
|
78
|
+
self._fernet = Fernet(key)
|
|
79
|
+
# Derive HMAC key for searchable tokens
|
|
80
|
+
self._hmac_key = hashlib.sha256(
|
|
81
|
+
(self._master_key + ":search-token").encode()
|
|
82
|
+
).digest()
|
|
83
|
+
logger.info("[ENCRYPTION] Fernet encryption initialized")
|
|
84
|
+
elif self._master_key:
|
|
85
|
+
# Fallback HMAC key without Fernet
|
|
86
|
+
self._hmac_key = hashlib.sha256(
|
|
87
|
+
(self._master_key + ":search-token").encode()
|
|
88
|
+
).digest()
|
|
89
|
+
logger.warning("[ENCRYPTION] Using base64 fallback (install cryptography for real encryption)")
|
|
90
|
+
|
|
91
|
+
@property
|
|
92
|
+
def available(self) -> bool:
|
|
93
|
+
return self._fernet is not None
|
|
94
|
+
|
|
95
|
+
def encrypt_value(self, value: str) -> str:
|
|
96
|
+
"""Encrypt a single string value."""
|
|
97
|
+
if not value or not isinstance(value, str):
|
|
98
|
+
return value
|
|
99
|
+
if self._fernet:
|
|
100
|
+
token = self._fernet.encrypt(value.encode())
|
|
101
|
+
return self.ENCRYPTED_PREFIX + token.decode()
|
|
102
|
+
else:
|
|
103
|
+
# Fallback: base64 (NOT secure — development only)
|
|
104
|
+
encoded = base64.b64encode(value.encode()).decode()
|
|
105
|
+
return self.ENCRYPTED_PREFIX + "B64:" + encoded
|
|
106
|
+
|
|
107
|
+
def decrypt_value(self, value: str) -> str:
|
|
108
|
+
"""Decrypt a single string value."""
|
|
109
|
+
if not isinstance(value, str) or not value.startswith(self.ENCRYPTED_PREFIX):
|
|
110
|
+
return value
|
|
111
|
+
|
|
112
|
+
payload = value[len(self.ENCRYPTED_PREFIX):]
|
|
113
|
+
|
|
114
|
+
if payload.startswith("B64:"):
|
|
115
|
+
# Base64 fallback
|
|
116
|
+
return base64.b64decode(payload[4:]).decode()
|
|
117
|
+
|
|
118
|
+
if self._fernet:
|
|
119
|
+
try:
|
|
120
|
+
return self._fernet.decrypt(payload.encode()).decode()
|
|
121
|
+
except Exception as e:
|
|
122
|
+
logger.warning("[ENCRYPTION] Decrypt failed: %s", e)
|
|
123
|
+
return "[DECRYPTION FAILED]"
|
|
124
|
+
|
|
125
|
+
return value
|
|
126
|
+
|
|
127
|
+
def encrypt_properties(self, properties: Dict[str, Any],
|
|
128
|
+
fields: Optional[List[str]] = None) -> Dict[str, Any]:
|
|
129
|
+
"""Encrypt specified fields in a properties dict.
|
|
130
|
+
|
|
131
|
+
Args:
|
|
132
|
+
fields: Which fields to encrypt. Default: content, email, phone, ssn.
|
|
133
|
+
"""
|
|
134
|
+
if not self._master_key:
|
|
135
|
+
return properties
|
|
136
|
+
|
|
137
|
+
target_fields = fields or ["content", "email", "phone", "ssn",
|
|
138
|
+
"credit_card", "aadhaar", "address"]
|
|
139
|
+
encrypted = dict(properties)
|
|
140
|
+
encrypted_fields = []
|
|
141
|
+
|
|
142
|
+
for field_name in target_fields:
|
|
143
|
+
if field_name in encrypted and isinstance(encrypted[field_name], str):
|
|
144
|
+
encrypted[field_name] = self.encrypt_value(encrypted[field_name])
|
|
145
|
+
encrypted_fields.append(field_name)
|
|
146
|
+
|
|
147
|
+
# Generate searchable token for encrypted field
|
|
148
|
+
token = self.searchable_token(str(properties[field_name]))
|
|
149
|
+
encrypted[f"_stok_{field_name}"] = token
|
|
150
|
+
|
|
151
|
+
if encrypted_fields:
|
|
152
|
+
encrypted["_encrypted_fields"] = encrypted_fields
|
|
153
|
+
|
|
154
|
+
return encrypted
|
|
155
|
+
|
|
156
|
+
def decrypt_properties(self, properties: Dict[str, Any]) -> Dict[str, Any]:
|
|
157
|
+
"""Decrypt all encrypted fields in a properties dict."""
|
|
158
|
+
encrypted_fields = properties.get("_encrypted_fields", [])
|
|
159
|
+
if not encrypted_fields:
|
|
160
|
+
return properties
|
|
161
|
+
|
|
162
|
+
decrypted = dict(properties)
|
|
163
|
+
for field_name in encrypted_fields:
|
|
164
|
+
if field_name in decrypted:
|
|
165
|
+
decrypted[field_name] = self.decrypt_value(decrypted[field_name])
|
|
166
|
+
|
|
167
|
+
# Remove encryption metadata from output
|
|
168
|
+
decrypted.pop("_encrypted_fields", None)
|
|
169
|
+
for f in encrypted_fields:
|
|
170
|
+
decrypted.pop(f"_stok_{f}", None)
|
|
171
|
+
|
|
172
|
+
return decrypted
|
|
173
|
+
|
|
174
|
+
def searchable_token(self, value: str) -> str:
|
|
175
|
+
"""Generate a deterministic searchable token for encrypted content.
|
|
176
|
+
|
|
177
|
+
This enables keyword search on encrypted fields without decryption:
|
|
178
|
+
- Same plaintext always produces the same token
|
|
179
|
+
- Token cannot be reversed to get the plaintext
|
|
180
|
+
- Allows exact-match search on encrypted fields
|
|
181
|
+
|
|
182
|
+
For substring search, tokens are generated for each word.
|
|
183
|
+
"""
|
|
184
|
+
if not self._hmac_key:
|
|
185
|
+
return ""
|
|
186
|
+
h = hmac.new(self._hmac_key, value.lower().strip().encode(), hashlib.sha256)
|
|
187
|
+
return self.SEARCH_PREFIX + h.hexdigest()[:16]
|
|
188
|
+
|
|
189
|
+
def searchable_tokens_for_text(self, text: str) -> List[str]:
|
|
190
|
+
"""Generate searchable tokens for each significant word in text.
|
|
191
|
+
|
|
192
|
+
Enables keyword search on encrypted content.
|
|
193
|
+
"""
|
|
194
|
+
if not self._hmac_key:
|
|
195
|
+
return []
|
|
196
|
+
words = set(w.lower() for w in text.split() if len(w) > 3)
|
|
197
|
+
return [self.searchable_token(w) for w in words]
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
# Global singleton
|
|
201
|
+
_encryptor: Optional[FieldEncryptor] = None
|
|
202
|
+
|
|
203
|
+
def get_encryptor() -> FieldEncryptor:
|
|
204
|
+
global _encryptor
|
|
205
|
+
if _encryptor is None:
|
|
206
|
+
_encryptor = FieldEncryptor()
|
|
207
|
+
return _encryptor
|