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,213 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tests for _QueryCache and fast-path SELECT shortcuts in AIQLExecutor.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
os.environ["CONTEXTSYNAPSE_GRAPH_BACKEND"] = "csr" # tests need isolated in-memory graphs
|
|
7
|
+
os.environ["AICONTEXTDB_GRAPH_BACKEND"] = "csr" # backward compat
|
|
8
|
+
|
|
9
|
+
import time
|
|
10
|
+
import tempfile
|
|
11
|
+
import shutil
|
|
12
|
+
import pytest
|
|
13
|
+
|
|
14
|
+
from contextsynapse.aiql.engine.executor import _QueryCache, _query_cache, AIQLExecutor
|
|
15
|
+
from contextsynapse.core.registry import GraphRegistry
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# ────────────────────────────────────────────────────────────────────
|
|
19
|
+
# Fixtures
|
|
20
|
+
# ────────────────────────────────────────────────────────────────────
|
|
21
|
+
|
|
22
|
+
@pytest.fixture()
|
|
23
|
+
def cache():
|
|
24
|
+
"""Fresh _QueryCache with small defaults for testing."""
|
|
25
|
+
return _QueryCache(max_size=4, ttl_seconds=1.0)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@pytest.fixture()
|
|
29
|
+
def tmp_storage(tmp_path):
|
|
30
|
+
"""Temporary directory for GraphRegistry storage."""
|
|
31
|
+
return str(tmp_path / "graphs")
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@pytest.fixture()
|
|
35
|
+
def executor(tmp_storage):
|
|
36
|
+
"""AIQLExecutor wired to a temporary GraphRegistry with a test graph."""
|
|
37
|
+
registry = GraphRegistry(storage_dir=tmp_storage)
|
|
38
|
+
registry.create_graph("test")
|
|
39
|
+
ex = AIQLExecutor(graph_registry=registry)
|
|
40
|
+
ex.active_namespace = "test"
|
|
41
|
+
|
|
42
|
+
# Clear the module-level cache so tests start clean
|
|
43
|
+
_query_cache.clear()
|
|
44
|
+
|
|
45
|
+
# Seed a few nodes
|
|
46
|
+
ex.execute('CREATE NODE Person {name: "Alice", age: "30"}')
|
|
47
|
+
ex.execute('CREATE NODE Person {name: "Bob", age: "25"}')
|
|
48
|
+
ex.execute('CREATE NODE Task {name: "Deploy", status: "done"}')
|
|
49
|
+
|
|
50
|
+
# Clear again after writes so cached CREATE results don't interfere
|
|
51
|
+
_query_cache.clear()
|
|
52
|
+
return ex
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
# ====================================================================
|
|
56
|
+
# 1. _QueryCache unit tests
|
|
57
|
+
# ====================================================================
|
|
58
|
+
|
|
59
|
+
class TestQueryCache:
|
|
60
|
+
"""Direct unit tests for the _QueryCache class."""
|
|
61
|
+
|
|
62
|
+
def test_put_and_get(self, cache):
|
|
63
|
+
cache.put("ns1", "SELECT * FROM Foo", {"rows": [1, 2, 3]})
|
|
64
|
+
result = cache.get("ns1", "SELECT * FROM Foo")
|
|
65
|
+
assert result == {"rows": [1, 2, 3]}
|
|
66
|
+
|
|
67
|
+
def test_get_miss_returns_none(self, cache):
|
|
68
|
+
assert cache.get("ns1", "SELECT 1") is None
|
|
69
|
+
|
|
70
|
+
def test_ttl_expiration(self, cache):
|
|
71
|
+
cache.put("ns1", "SELECT 1", "ok")
|
|
72
|
+
# Should be retrievable immediately
|
|
73
|
+
assert cache.get("ns1", "SELECT 1") == "ok"
|
|
74
|
+
# Wait for TTL (1 second) to expire
|
|
75
|
+
time.sleep(1.1)
|
|
76
|
+
assert cache.get("ns1", "SELECT 1") is None
|
|
77
|
+
|
|
78
|
+
def test_lru_eviction(self, cache):
|
|
79
|
+
"""Oldest entries are evicted when max_size is exceeded."""
|
|
80
|
+
cache.put("ns", "q1", "r1")
|
|
81
|
+
cache.put("ns", "q2", "r2")
|
|
82
|
+
cache.put("ns", "q3", "r3")
|
|
83
|
+
cache.put("ns", "q4", "r4")
|
|
84
|
+
assert cache.size == 4
|
|
85
|
+
|
|
86
|
+
# Adding a 5th entry should evict the oldest (q1)
|
|
87
|
+
cache.put("ns", "q5", "r5")
|
|
88
|
+
assert cache.size == 4
|
|
89
|
+
assert cache.get("ns", "q1") is None
|
|
90
|
+
assert cache.get("ns", "q5") == "r5"
|
|
91
|
+
|
|
92
|
+
def test_lru_access_refreshes_order(self, cache):
|
|
93
|
+
"""Accessing an entry moves it to the end, protecting it from eviction."""
|
|
94
|
+
cache.put("ns", "q1", "r1")
|
|
95
|
+
cache.put("ns", "q2", "r2")
|
|
96
|
+
cache.put("ns", "q3", "r3")
|
|
97
|
+
cache.put("ns", "q4", "r4")
|
|
98
|
+
|
|
99
|
+
# Access q1 so it becomes most-recently used
|
|
100
|
+
cache.get("ns", "q1")
|
|
101
|
+
|
|
102
|
+
# Insert two more; q2 and q3 should be evicted (oldest untouched)
|
|
103
|
+
cache.put("ns", "q5", "r5")
|
|
104
|
+
cache.put("ns", "q6", "r6")
|
|
105
|
+
|
|
106
|
+
assert cache.get("ns", "q1") == "r1" # survived because it was accessed
|
|
107
|
+
assert cache.get("ns", "q2") is None # evicted
|
|
108
|
+
assert cache.get("ns", "q3") is None # evicted
|
|
109
|
+
|
|
110
|
+
def test_invalidate_namespace(self, cache):
|
|
111
|
+
cache.put("ns1", "q1", "r1")
|
|
112
|
+
cache.put("ns1", "q2", "r2")
|
|
113
|
+
cache.put("ns2", "q1", "r3")
|
|
114
|
+
assert cache.size == 3
|
|
115
|
+
|
|
116
|
+
cache.invalidate("ns1")
|
|
117
|
+
|
|
118
|
+
assert cache.get("ns1", "q1") is None
|
|
119
|
+
assert cache.get("ns1", "q2") is None
|
|
120
|
+
assert cache.get("ns2", "q1") == "r3"
|
|
121
|
+
assert cache.size == 1
|
|
122
|
+
|
|
123
|
+
def test_clear(self, cache):
|
|
124
|
+
cache.put("ns1", "q1", "r1")
|
|
125
|
+
cache.put("ns2", "q2", "r2")
|
|
126
|
+
assert cache.size == 2
|
|
127
|
+
|
|
128
|
+
cache.clear()
|
|
129
|
+
assert cache.size == 0
|
|
130
|
+
assert cache.get("ns1", "q1") is None
|
|
131
|
+
|
|
132
|
+
def test_namespaces_isolated(self, cache):
|
|
133
|
+
"""Same query string in different namespaces returns different results."""
|
|
134
|
+
cache.put("alpha", "SELECT *", {"from": "alpha"})
|
|
135
|
+
cache.put("beta", "SELECT *", {"from": "beta"})
|
|
136
|
+
|
|
137
|
+
assert cache.get("alpha", "SELECT *") == {"from": "alpha"}
|
|
138
|
+
assert cache.get("beta", "SELECT *") == {"from": "beta"}
|
|
139
|
+
|
|
140
|
+
def test_invalidate_one_namespace_keeps_other(self, cache):
|
|
141
|
+
cache.put("alpha", "SELECT *", "a")
|
|
142
|
+
cache.put("beta", "SELECT *", "b")
|
|
143
|
+
|
|
144
|
+
cache.invalidate("alpha")
|
|
145
|
+
|
|
146
|
+
assert cache.get("alpha", "SELECT *") is None
|
|
147
|
+
assert cache.get("beta", "SELECT *") == "b"
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
# ====================================================================
|
|
151
|
+
# 2. Fast-path SELECT shortcut tests (via AIQLExecutor)
|
|
152
|
+
# ====================================================================
|
|
153
|
+
|
|
154
|
+
class TestFastPathSelects:
|
|
155
|
+
"""Integration tests for fast-path SELECT shortcuts and SHOW GRAPHS."""
|
|
156
|
+
|
|
157
|
+
def test_select_star_returns_all_nodes(self, executor):
|
|
158
|
+
result = executor.execute("SELECT *")
|
|
159
|
+
assert result["nodes"] is not None
|
|
160
|
+
assert len(result["nodes"]) == 3 # Alice, Bob, Deploy
|
|
161
|
+
|
|
162
|
+
def test_select_star_from_label(self, executor):
|
|
163
|
+
result = executor.execute("SELECT * FROM Person")
|
|
164
|
+
assert len(result["nodes"]) == 2
|
|
165
|
+
names = {n["properties"]["name"] for n in result["nodes"]}
|
|
166
|
+
assert names == {"Alice", "Bob"}
|
|
167
|
+
|
|
168
|
+
def test_select_star_from_label_case_insensitive(self, executor):
|
|
169
|
+
result = executor.execute("SELECT * FROM person")
|
|
170
|
+
assert len(result["nodes"]) == 2
|
|
171
|
+
|
|
172
|
+
def test_select_star_where_property(self, executor):
|
|
173
|
+
result = executor.execute('SELECT * WHERE name = "Alice"')
|
|
174
|
+
assert len(result["nodes"]) == 1
|
|
175
|
+
assert result["nodes"][0]["properties"]["name"] == "Alice"
|
|
176
|
+
|
|
177
|
+
def test_select_star_where_no_match(self, executor):
|
|
178
|
+
result = executor.execute('SELECT * WHERE name = "Nobody"')
|
|
179
|
+
assert len(result["nodes"]) == 0
|
|
180
|
+
|
|
181
|
+
def test_show_graphs(self, executor):
|
|
182
|
+
result = executor.execute("SHOW GRAPHS")
|
|
183
|
+
graphs = result["data"]["graphs"]
|
|
184
|
+
names = [g["name"] for g in graphs]
|
|
185
|
+
assert "test" in names
|
|
186
|
+
|
|
187
|
+
def test_cache_hit_on_second_call(self, executor):
|
|
188
|
+
"""Second identical read should come from cache."""
|
|
189
|
+
_query_cache.clear()
|
|
190
|
+
|
|
191
|
+
r1 = executor.execute("SELECT *")
|
|
192
|
+
assert _query_cache.size >= 1 # stored after first call
|
|
193
|
+
|
|
194
|
+
r2 = executor.execute("SELECT *")
|
|
195
|
+
# Results should be identical (same object from cache)
|
|
196
|
+
assert r1 is r2
|
|
197
|
+
|
|
198
|
+
def test_write_invalidates_cache(self, executor):
|
|
199
|
+
"""A write query should invalidate cached reads for the namespace."""
|
|
200
|
+
_query_cache.clear()
|
|
201
|
+
|
|
202
|
+
executor.execute("SELECT *")
|
|
203
|
+
assert _query_cache.size >= 1
|
|
204
|
+
|
|
205
|
+
# Write invalidates the namespace cache
|
|
206
|
+
executor.execute('CREATE NODE Person {name: "Charlie", age: "40"}')
|
|
207
|
+
# Cache for "test" namespace should have been cleared
|
|
208
|
+
cached = _query_cache.get("test", "SELECT *")
|
|
209
|
+
assert cached is None
|
|
210
|
+
|
|
211
|
+
# Fresh read should now include 4 nodes
|
|
212
|
+
result = executor.execute("SELECT *")
|
|
213
|
+
assert len(result["nodes"]) == 4
|
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
"""Tests for source policy domain matching and auth error message safety."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import inspect
|
|
6
|
+
import re
|
|
7
|
+
|
|
8
|
+
import pytest
|
|
9
|
+
|
|
10
|
+
from contextsynapse.context.source_policy import (
|
|
11
|
+
ALWAYS_BLOCKED_DOMAINS,
|
|
12
|
+
ALWAYS_BLOCKED_IP_PREFIXES,
|
|
13
|
+
check_source_allowed,
|
|
14
|
+
)
|
|
15
|
+
from contextsynapse.api import auth as auth_module
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# ---------------------------------------------------------------------------
|
|
19
|
+
# Helpers
|
|
20
|
+
# ---------------------------------------------------------------------------
|
|
21
|
+
|
|
22
|
+
class FakeContext:
|
|
23
|
+
"""Minimal context object with a config dict and optional attributes."""
|
|
24
|
+
|
|
25
|
+
def __init__(self, config=None, source=None, context_type=None):
|
|
26
|
+
self.config = config or {}
|
|
27
|
+
self.source = source
|
|
28
|
+
self.context_type = context_type
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _policy(**overrides):
|
|
32
|
+
"""Build a config dict wrapping a source_policy."""
|
|
33
|
+
return {"source_policy": overrides}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# ===========================================================================
|
|
37
|
+
# Source Policy — Domain Matching
|
|
38
|
+
# ===========================================================================
|
|
39
|
+
|
|
40
|
+
class TestExactDomainMatch:
|
|
41
|
+
def test_exact_domain_allowed(self):
|
|
42
|
+
ctx = FakeContext(config=_policy(allowed_domains=["example.com"]))
|
|
43
|
+
allowed, reason = check_source_allowed(ctx, source_url="https://example.com/page")
|
|
44
|
+
assert allowed is True
|
|
45
|
+
|
|
46
|
+
def test_exact_domain_rejected(self):
|
|
47
|
+
ctx = FakeContext(config=_policy(allowed_domains=["example.com"]))
|
|
48
|
+
allowed, reason = check_source_allowed(ctx, source_url="https://other.com/page")
|
|
49
|
+
assert allowed is False
|
|
50
|
+
assert "not in allowed" in reason
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class TestWwwPrefixStripping:
|
|
54
|
+
def test_www_prefix_stripped_and_matched(self):
|
|
55
|
+
ctx = FakeContext(config=_policy(allowed_domains=["example.com"]))
|
|
56
|
+
allowed, _ = check_source_allowed(ctx, source_url="https://www.example.com/page")
|
|
57
|
+
assert allowed is True
|
|
58
|
+
|
|
59
|
+
def test_allowed_has_www_source_does_not(self):
|
|
60
|
+
ctx = FakeContext(config=_policy(allowed_domains=["www.example.com"]))
|
|
61
|
+
allowed, _ = check_source_allowed(ctx, source_url="https://example.com/page")
|
|
62
|
+
assert allowed is True
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class TestSubdomainMatching:
|
|
66
|
+
def test_subdomain_of_allowed_domain(self):
|
|
67
|
+
ctx = FakeContext(config=_policy(allowed_domains=["example.com"]))
|
|
68
|
+
allowed, _ = check_source_allowed(ctx, source_url="https://docs.example.com/api")
|
|
69
|
+
assert allowed is True
|
|
70
|
+
|
|
71
|
+
def test_deep_subdomain_of_allowed_domain(self):
|
|
72
|
+
ctx = FakeContext(config=_policy(allowed_domains=["example.com"]))
|
|
73
|
+
allowed, _ = check_source_allowed(ctx, source_url="https://a.b.c.example.com/x")
|
|
74
|
+
assert allowed is True
|
|
75
|
+
|
|
76
|
+
def test_unrelated_domain_with_same_suffix_rejected(self):
|
|
77
|
+
ctx = FakeContext(config=_policy(allowed_domains=["example.com"]))
|
|
78
|
+
allowed, _ = check_source_allowed(ctx, source_url="https://notexample.com/page")
|
|
79
|
+
assert allowed is False
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class TestRelatedDomainMatch:
|
|
83
|
+
def test_related_domain_name_in_subdomain(self):
|
|
84
|
+
"""timesofindia.com should match timesofindia.indiatimes.com."""
|
|
85
|
+
ctx = FakeContext(config=_policy(allowed_domains=["timesofindia.com"]))
|
|
86
|
+
allowed, _ = check_source_allowed(
|
|
87
|
+
ctx, source_url="https://timesofindia.indiatimes.com/article"
|
|
88
|
+
)
|
|
89
|
+
assert allowed is True
|
|
90
|
+
|
|
91
|
+
def test_related_domain_different_tld(self):
|
|
92
|
+
ctx = FakeContext(config=_policy(allowed_domains=["mycompany.com"]))
|
|
93
|
+
allowed, _ = check_source_allowed(
|
|
94
|
+
ctx, source_url="https://mycompany.co.uk/page"
|
|
95
|
+
)
|
|
96
|
+
assert allowed is True
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
class TestShortDomainNoLooseMatch:
|
|
100
|
+
def test_short_name_three_chars_no_loose_match(self):
|
|
101
|
+
"""Domain names <= 3 chars should NOT get the loose related-domain matching."""
|
|
102
|
+
ctx = FakeContext(config=_policy(allowed_domains=["abc.com"]))
|
|
103
|
+
# "abc.otherdomain.com" should NOT match because "abc" is only 3 chars
|
|
104
|
+
allowed, _ = check_source_allowed(
|
|
105
|
+
ctx, source_url="https://abc.otherdomain.com/page"
|
|
106
|
+
)
|
|
107
|
+
assert allowed is False
|
|
108
|
+
|
|
109
|
+
def test_four_char_name_does_match(self):
|
|
110
|
+
ctx = FakeContext(config=_policy(allowed_domains=["abcd.com"]))
|
|
111
|
+
allowed, _ = check_source_allowed(
|
|
112
|
+
ctx, source_url="https://abcd.otherdomain.com/page"
|
|
113
|
+
)
|
|
114
|
+
assert allowed is True
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class TestBlockedDomains:
|
|
118
|
+
def test_blocked_domain_rejected(self):
|
|
119
|
+
ctx = FakeContext(config=_policy(
|
|
120
|
+
allowed_domains=["example.com"],
|
|
121
|
+
blocked_domains=["evil.com"],
|
|
122
|
+
))
|
|
123
|
+
allowed, reason = check_source_allowed(ctx, source_url="https://evil.com/x")
|
|
124
|
+
assert allowed is False
|
|
125
|
+
assert "blocked" in reason.lower()
|
|
126
|
+
|
|
127
|
+
def test_blocked_subdomain_rejected(self):
|
|
128
|
+
ctx = FakeContext(config=_policy(blocked_domains=["evil.com"]))
|
|
129
|
+
allowed, _ = check_source_allowed(ctx, source_url="https://sub.evil.com/x")
|
|
130
|
+
assert allowed is False
|
|
131
|
+
|
|
132
|
+
def test_blocked_takes_priority_over_allowed(self):
|
|
133
|
+
ctx = FakeContext(config=_policy(
|
|
134
|
+
allowed_domains=["evil.com"],
|
|
135
|
+
blocked_domains=["evil.com"],
|
|
136
|
+
))
|
|
137
|
+
allowed, _ = check_source_allowed(ctx, source_url="https://evil.com/x")
|
|
138
|
+
assert allowed is False
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
class TestPathPrefixMatching:
|
|
142
|
+
def test_path_prefix_allowed(self):
|
|
143
|
+
ctx = FakeContext(config=_policy(allowed_domains=["github.com/myorg"]))
|
|
144
|
+
allowed, _ = check_source_allowed(
|
|
145
|
+
ctx, source_url="https://github.com/myorg/repo"
|
|
146
|
+
)
|
|
147
|
+
assert allowed is True
|
|
148
|
+
|
|
149
|
+
def test_path_prefix_different_org_rejected(self):
|
|
150
|
+
ctx = FakeContext(config=_policy(allowed_domains=["github.com/myorg"]))
|
|
151
|
+
allowed, _ = check_source_allowed(
|
|
152
|
+
ctx, source_url="https://github.com/otherorg/repo"
|
|
153
|
+
)
|
|
154
|
+
assert allowed is False
|
|
155
|
+
|
|
156
|
+
def test_path_prefix_exact_path(self):
|
|
157
|
+
ctx = FakeContext(config=_policy(allowed_domains=["github.com/myorg"]))
|
|
158
|
+
allowed, _ = check_source_allowed(
|
|
159
|
+
ctx, source_url="https://github.com/myorg"
|
|
160
|
+
)
|
|
161
|
+
assert allowed is True
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
class TestSecurityBlocklist:
|
|
165
|
+
def test_localhost_always_blocked(self):
|
|
166
|
+
ctx = FakeContext() # No policy at all
|
|
167
|
+
allowed, reason = check_source_allowed(ctx, source_url="http://localhost/admin")
|
|
168
|
+
assert allowed is False
|
|
169
|
+
assert "restricted" in reason.lower() or "blocked" in reason.lower()
|
|
170
|
+
|
|
171
|
+
def test_aws_metadata_blocked(self):
|
|
172
|
+
ctx = FakeContext()
|
|
173
|
+
allowed, _ = check_source_allowed(
|
|
174
|
+
ctx, source_url="http://169.254.169.254/latest/meta-data/"
|
|
175
|
+
)
|
|
176
|
+
assert allowed is False
|
|
177
|
+
|
|
178
|
+
def test_gcp_metadata_blocked(self):
|
|
179
|
+
ctx = FakeContext()
|
|
180
|
+
allowed, _ = check_source_allowed(
|
|
181
|
+
ctx, source_url="http://metadata.google.internal/computeMetadata/v1/"
|
|
182
|
+
)
|
|
183
|
+
assert allowed is False
|
|
184
|
+
|
|
185
|
+
def test_private_ip_10_blocked(self):
|
|
186
|
+
ctx = FakeContext()
|
|
187
|
+
allowed, _ = check_source_allowed(ctx, source_url="http://10.0.0.1/secret")
|
|
188
|
+
assert allowed is False
|
|
189
|
+
|
|
190
|
+
def test_private_ip_192_168_blocked(self):
|
|
191
|
+
ctx = FakeContext()
|
|
192
|
+
allowed, _ = check_source_allowed(
|
|
193
|
+
ctx, source_url="http://192.168.1.1/admin"
|
|
194
|
+
)
|
|
195
|
+
assert allowed is False
|
|
196
|
+
|
|
197
|
+
def test_private_ip_172_16_blocked(self):
|
|
198
|
+
ctx = FakeContext()
|
|
199
|
+
allowed, _ = check_source_allowed(ctx, source_url="http://172.16.0.1/x")
|
|
200
|
+
assert allowed is False
|
|
201
|
+
|
|
202
|
+
def test_loopback_127_blocked(self):
|
|
203
|
+
ctx = FakeContext()
|
|
204
|
+
allowed, _ = check_source_allowed(ctx, source_url="http://127.0.0.1/x")
|
|
205
|
+
assert allowed is False
|
|
206
|
+
|
|
207
|
+
def test_security_blocklist_overrides_allowed_domains(self):
|
|
208
|
+
"""Even if policy allows localhost, security blocklist wins."""
|
|
209
|
+
ctx = FakeContext(config=_policy(allowed_domains=["localhost"]))
|
|
210
|
+
allowed, _ = check_source_allowed(ctx, source_url="http://localhost/x")
|
|
211
|
+
assert allowed is False
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
class TestNoPolicyOpenByDefault:
|
|
215
|
+
def test_no_policy_allows_external_url(self):
|
|
216
|
+
ctx = FakeContext()
|
|
217
|
+
allowed, reason = check_source_allowed(
|
|
218
|
+
ctx, source_url="https://anything.example.com/data"
|
|
219
|
+
)
|
|
220
|
+
assert allowed is True
|
|
221
|
+
assert "no source policy" in reason.lower()
|
|
222
|
+
|
|
223
|
+
def test_no_policy_allows_files(self):
|
|
224
|
+
ctx = FakeContext()
|
|
225
|
+
allowed, _ = check_source_allowed(ctx, filename="report.pdf")
|
|
226
|
+
assert allowed is True
|
|
227
|
+
|
|
228
|
+
def test_no_policy_still_blocks_security_threats(self):
|
|
229
|
+
ctx = FakeContext()
|
|
230
|
+
allowed, _ = check_source_allowed(ctx, source_url="http://0.0.0.0/x")
|
|
231
|
+
assert allowed is False
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
class TestFileExtensionFiltering:
|
|
235
|
+
def test_allowed_extension_passes(self):
|
|
236
|
+
ctx = FakeContext(config=_policy(allowed_file_extensions=[".pdf", ".md"]))
|
|
237
|
+
allowed, _ = check_source_allowed(ctx, filename="report.pdf")
|
|
238
|
+
assert allowed is True
|
|
239
|
+
|
|
240
|
+
def test_disallowed_extension_rejected(self):
|
|
241
|
+
ctx = FakeContext(config=_policy(allowed_file_extensions=[".pdf", ".md"]))
|
|
242
|
+
allowed, reason = check_source_allowed(ctx, filename="malware.exe")
|
|
243
|
+
assert allowed is False
|
|
244
|
+
assert ".exe" in reason
|
|
245
|
+
|
|
246
|
+
def test_case_insensitive_extension(self):
|
|
247
|
+
ctx = FakeContext(config=_policy(allowed_file_extensions=[".pdf"]))
|
|
248
|
+
allowed, _ = check_source_allowed(ctx, filename="report.PDF")
|
|
249
|
+
assert allowed is True
|
|
250
|
+
|
|
251
|
+
def test_no_extension_filter_allows_all(self):
|
|
252
|
+
ctx = FakeContext(config=_policy(allowed_domains=["example.com"]))
|
|
253
|
+
allowed, _ = check_source_allowed(ctx, filename="anything.xyz")
|
|
254
|
+
assert allowed is True
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
class TestFileSizeFiltering:
|
|
258
|
+
def test_within_limit_allowed(self):
|
|
259
|
+
ctx = FakeContext(config=_policy(max_file_size_mb=50))
|
|
260
|
+
allowed, _ = check_source_allowed(ctx, file_size_mb=25.0)
|
|
261
|
+
assert allowed is True
|
|
262
|
+
|
|
263
|
+
def test_exceeds_limit_rejected(self):
|
|
264
|
+
ctx = FakeContext(config=_policy(max_file_size_mb=50))
|
|
265
|
+
allowed, reason = check_source_allowed(ctx, file_size_mb=75.0)
|
|
266
|
+
assert allowed is False
|
|
267
|
+
assert "exceeds" in reason.lower()
|
|
268
|
+
|
|
269
|
+
def test_exact_limit_allowed(self):
|
|
270
|
+
ctx = FakeContext(config=_policy(max_file_size_mb=50))
|
|
271
|
+
allowed, _ = check_source_allowed(ctx, file_size_mb=50.0)
|
|
272
|
+
assert allowed is True
|
|
273
|
+
|
|
274
|
+
def test_no_size_limit_allows_large_files(self):
|
|
275
|
+
ctx = FakeContext(config=_policy(allowed_domains=["example.com"]))
|
|
276
|
+
allowed, _ = check_source_allowed(ctx, file_size_mb=9999.0)
|
|
277
|
+
assert allowed is True
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
# ===========================================================================
|
|
281
|
+
# Auth Error Messages — No Implementation Details Leaked
|
|
282
|
+
# ===========================================================================
|
|
283
|
+
|
|
284
|
+
def _collect_auth_error_messages() -> list[str]:
|
|
285
|
+
"""Extract all HTTPException detail strings from the auth module source."""
|
|
286
|
+
source = inspect.getsource(auth_module)
|
|
287
|
+
# Match detail="..." and detail='...'
|
|
288
|
+
messages = re.findall(r'detail\s*=\s*["\']([^"\']+)["\']', source)
|
|
289
|
+
return messages
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
class TestAuthErrorMessagesNoLeaks:
|
|
293
|
+
"""Verify that error messages in auth.py do not leak implementation details."""
|
|
294
|
+
|
|
295
|
+
@pytest.fixture(autouse=True)
|
|
296
|
+
def _load_messages(self):
|
|
297
|
+
self.messages = _collect_auth_error_messages()
|
|
298
|
+
# Sanity: we should have found at least a few messages
|
|
299
|
+
assert len(self.messages) >= 3, (
|
|
300
|
+
f"Expected at least 3 error messages, found {len(self.messages)}"
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
def test_no_bearer_usage_instructions(self):
|
|
304
|
+
"""Error messages must not tell attackers the exact auth header format."""
|
|
305
|
+
for msg in self.messages:
|
|
306
|
+
assert "Use: Authorization: Bearer" not in msg, (
|
|
307
|
+
f"Error message leaks auth format: {msg!r}"
|
|
308
|
+
)
|
|
309
|
+
assert "Authorization: Bearer" not in msg, (
|
|
310
|
+
f"Error message leaks auth header name: {msg!r}"
|
|
311
|
+
)
|
|
312
|
+
|
|
313
|
+
def test_no_env_var_names_leaked(self):
|
|
314
|
+
"""Error messages must not reveal internal env var names."""
|
|
315
|
+
env_vars = [
|
|
316
|
+
"CONTEXTSYNAPSE_ADMIN_KEY",
|
|
317
|
+
"AICONTEXTDB_ADMIN_KEY",
|
|
318
|
+
"CONTEXTSYNAPSE_JWT_SECRET",
|
|
319
|
+
"AICONTEXTDB_JWT_SECRET",
|
|
320
|
+
"CONTEXTSYNAPSE_CORS_ORIGINS",
|
|
321
|
+
"AICONTEXTDB_CORS_ORIGINS",
|
|
322
|
+
]
|
|
323
|
+
for msg in self.messages:
|
|
324
|
+
for var in env_vars:
|
|
325
|
+
assert var not in msg, (
|
|
326
|
+
f"Error message leaks env var '{var}': {msg!r}"
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
def test_no_stack_trace_hints(self):
|
|
330
|
+
"""Error messages should not contain stacktrace-like content."""
|
|
331
|
+
bad_patterns = ["traceback", "File \"", "line ", "raise ", "Exception("]
|
|
332
|
+
for msg in self.messages:
|
|
333
|
+
for pat in bad_patterns:
|
|
334
|
+
assert pat not in msg, (
|
|
335
|
+
f"Error message contains implementation hint '{pat}': {msg!r}"
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
def test_messages_are_user_friendly(self):
|
|
339
|
+
"""All error messages should be human-readable sentences (not code)."""
|
|
340
|
+
for msg in self.messages:
|
|
341
|
+
# Should end with a period (proper sentence)
|
|
342
|
+
assert msg.rstrip().endswith("."), (
|
|
343
|
+
f"Error message is not a proper sentence (no period): {msg!r}"
|
|
344
|
+
)
|
|
345
|
+
# Should not contain Python code artifacts
|
|
346
|
+
assert "==" not in msg
|
|
347
|
+
assert "!=" not in msg
|
|
348
|
+
assert "None" not in msg
|