10xgraph-api 0.7.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.
- 10xgraph_api-0.7.0.dist-info/METADATA +618 -0
- 10xgraph_api-0.7.0.dist-info/RECORD +203 -0
- 10xgraph_api-0.7.0.dist-info/WHEEL +5 -0
- 10xgraph_api-0.7.0.dist-info/entry_points.txt +3 -0
- 10xgraph_api-0.7.0.dist-info/licenses/LICENSE +21 -0
- 10xgraph_api-0.7.0.dist-info/top_level.txt +2 -0
- agentflow_cli/__init__.py +69 -0
- tenxgraph_api/__init__.py +23 -0
- tenxgraph_api/cli/__init__.py +6 -0
- tenxgraph_api/cli/capabilities.py +127 -0
- tenxgraph_api/cli/commands/__init__.py +49 -0
- tenxgraph_api/cli/commands/api.py +262 -0
- tenxgraph_api/cli/commands/audit.py +213 -0
- tenxgraph_api/cli/commands/build.py +305 -0
- tenxgraph_api/cli/commands/config.py +71 -0
- tenxgraph_api/cli/commands/demo.py +93 -0
- tenxgraph_api/cli/commands/eval.py +909 -0
- tenxgraph_api/cli/commands/init.py +531 -0
- tenxgraph_api/cli/commands/skills.py +532 -0
- tenxgraph_api/cli/commands/test.py +113 -0
- tenxgraph_api/cli/commands/version.py +47 -0
- tenxgraph_api/cli/config_editor/__init__.py +15 -0
- tenxgraph_api/cli/config_editor/schema.py +566 -0
- tenxgraph_api/cli/config_editor/server.py +240 -0
- tenxgraph_api/cli/config_editor/static/app.css +2 -0
- tenxgraph_api/cli/config_editor/static/app.js +3 -0
- tenxgraph_api/cli/config_editor/static/favicon.svg +11 -0
- tenxgraph_api/cli/config_editor/static/index.html +20 -0
- tenxgraph_api/cli/config_editor/store.py +120 -0
- tenxgraph_api/cli/config_editor/validation.py +377 -0
- tenxgraph_api/cli/constants.py +112 -0
- tenxgraph_api/cli/context.py +46 -0
- tenxgraph_api/cli/core/__init__.py +0 -0
- tenxgraph_api/cli/core/animations.py +550 -0
- tenxgraph_api/cli/core/config.py +279 -0
- tenxgraph_api/cli/core/output.py +625 -0
- tenxgraph_api/cli/core/prompts.py +220 -0
- tenxgraph_api/cli/core/screen.py +287 -0
- tenxgraph_api/cli/core/steps.py +621 -0
- tenxgraph_api/cli/core/theme.py +242 -0
- tenxgraph_api/cli/core/validation.py +251 -0
- tenxgraph_api/cli/exceptions.py +129 -0
- tenxgraph_api/cli/logger.py +84 -0
- tenxgraph_api/cli/main.py +936 -0
- tenxgraph_api/cli/templates/__init__.py +0 -0
- tenxgraph_api/cli/templates/defaults.py +844 -0
- tenxgraph_api/cli/templates/dev/.env.example +1 -0
- tenxgraph_api/cli/templates/dev/10xgraph.json +16 -0
- tenxgraph_api/cli/templates/dev/graph/__init__.py +0 -0
- tenxgraph_api/cli/templates/dev/graph/agent.py +63 -0
- tenxgraph_api/cli/templates/prod/.env.example +75 -0
- tenxgraph_api/cli/templates/prod/.pre-commit-config.yaml +50 -0
- tenxgraph_api/cli/templates/prod/.python-version +1 -0
- tenxgraph_api/cli/templates/prod/10xgraph.json +42 -0
- tenxgraph_api/cli/templates/prod/auth/__init__.py +0 -0
- tenxgraph_api/cli/templates/prod/auth/agent_auth.py +46 -0
- tenxgraph_api/cli/templates/prod/evals/__init__.py +0 -0
- tenxgraph_api/cli/templates/prod/evals/user_simulator_eval.py +76 -0
- tenxgraph_api/cli/templates/prod/evals/weather_agents_eval.py +53 -0
- tenxgraph_api/cli/templates/prod/graph/__init__.py +0 -0
- tenxgraph_api/cli/templates/prod/graph/agent.py +50 -0
- tenxgraph_api/cli/templates/prod/graph/state.py +5 -0
- tenxgraph_api/cli/templates/prod/graph/thread_name_generator.py +7 -0
- tenxgraph_api/cli/templates/prod/graph/tools/__init__.py +0 -0
- tenxgraph_api/cli/templates/prod/graph/tools/weather_tool.py +43 -0
- tenxgraph_api/cli/templates/prod/graph/validators/__init__.py +0 -0
- tenxgraph_api/cli/templates/prod/graph/validators/lifecyle.py +107 -0
- tenxgraph_api/cli/templates/prod/graph/validators/manager.py +9 -0
- tenxgraph_api/cli/templates/prod/graph/validators/validators.py +21 -0
- tenxgraph_api/cli/templates/prod/pyproject.toml +79 -0
- tenxgraph_api/cli/templates/prod/tests/__init__.py +0 -0
- tenxgraph_api/cli/templates/prod/tests/conftest.py +6 -0
- tenxgraph_api/cli/templates/prod/tests/test_agent_eval.py +78 -0
- tenxgraph_api/cli/templates/prod/tests/test_catalog_tools.py +47 -0
- tenxgraph_api/cli/templates/prod/tests/test_graph_nodes.py +57 -0
- tenxgraph_api/cli/templates/skills/10xgraph/SKILL.md +92 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/agents-and-tools.md +389 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/api-client.md +61 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/api-configuration.md +75 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/api-settings-and-middleware.md +89 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/architecture.md +91 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/auth-and-authorization.md +149 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/callbacks-and-command.md +283 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/checkpointing-and-threads.md +63 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/cli-commands.md +73 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/client-auth-and-errors.md +94 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/client-messages-invoke-stream.md +115 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/client-threads-memory-files.md +80 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/context-id-background.md +80 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/dependency-injection.md +58 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/evaluation.md +500 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/id-and-thread-name-generators.md +69 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/media-and-files.md +66 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/memory-and-store.md +70 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/prebuilt-agents-and-tools.md +394 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/production-runtime.md +56 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/providers-and-adapters.md +89 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/publishers-and-runtime-protocols.md +84 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/rate-limiting.md +194 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/realtime.md +172 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/remote-tools.md +55 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/rest-api-and-errors.md +97 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/security-and-validators.md +86 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/state-and-messages.md +68 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/state-graph.md +232 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/stream-emitter.md +144 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/streaming.md +53 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/testing-and-evaluation.md +64 -0
- tenxgraph_api/cli/templates/skills/10xgraph/references/unit-testing.md +202 -0
- tenxgraph_api/cli/templates/skills/copilot/10xgraph.instructions.md +108 -0
- tenxgraph_api/py.typed +0 -0
- tenxgraph_api/src/__init__.py +0 -0
- tenxgraph_api/src/app/__init__.py +13 -0
- tenxgraph_api/src/app/core/__init__.py +15 -0
- tenxgraph_api/src/app/core/auth/__init__.py +0 -0
- tenxgraph_api/src/app/core/auth/auth_backend.py +38 -0
- tenxgraph_api/src/app/core/auth/authorization.py +379 -0
- tenxgraph_api/src/app/core/auth/base_auth.py +27 -0
- tenxgraph_api/src/app/core/auth/jwt_auth.py +122 -0
- tenxgraph_api/src/app/core/auth/ownership_resolver.py +170 -0
- tenxgraph_api/src/app/core/auth/permissions.py +354 -0
- tenxgraph_api/src/app/core/auth/request_config.py +130 -0
- tenxgraph_api/src/app/core/auth/route_guard.py +105 -0
- tenxgraph_api/src/app/core/config/__init__.py +0 -0
- tenxgraph_api/src/app/core/config/graph_config.py +532 -0
- tenxgraph_api/src/app/core/config/media_settings.py +72 -0
- tenxgraph_api/src/app/core/config/sentry_config.py +60 -0
- tenxgraph_api/src/app/core/config/settings.py +202 -0
- tenxgraph_api/src/app/core/config/setup_logs.py +65 -0
- tenxgraph_api/src/app/core/config/setup_middleware.py +483 -0
- tenxgraph_api/src/app/core/config/worker_middleware.py +99 -0
- tenxgraph_api/src/app/core/exceptions/__init__.py +17 -0
- tenxgraph_api/src/app/core/exceptions/general_exception.py +58 -0
- tenxgraph_api/src/app/core/exceptions/handle_errors.py +363 -0
- tenxgraph_api/src/app/core/exceptions/resources_exceptions.py +72 -0
- tenxgraph_api/src/app/core/exceptions/user_exception.py +58 -0
- tenxgraph_api/src/app/core/middleware/__init__.py +25 -0
- tenxgraph_api/src/app/core/middleware/rate_limit/__init__.py +15 -0
- tenxgraph_api/src/app/core/middleware/rate_limit/base.py +27 -0
- tenxgraph_api/src/app/core/middleware/rate_limit/factory.py +98 -0
- tenxgraph_api/src/app/core/middleware/rate_limit/keying.py +133 -0
- tenxgraph_api/src/app/core/middleware/rate_limit/memory.py +98 -0
- tenxgraph_api/src/app/core/middleware/rate_limit/middleware.py +90 -0
- tenxgraph_api/src/app/core/middleware/rate_limit/redis.py +115 -0
- tenxgraph_api/src/app/core/middleware/request_limits.py +154 -0
- tenxgraph_api/src/app/core/middleware/security_headers.py +239 -0
- tenxgraph_api/src/app/core/utils/__init__.py +14 -0
- tenxgraph_api/src/app/core/utils/log_sanitizer.py +216 -0
- tenxgraph_api/src/app/loader.py +516 -0
- tenxgraph_api/src/app/main.py +180 -0
- tenxgraph_api/src/app/routers/__init__.py +4 -0
- tenxgraph_api/src/app/routers/ag_ui/__init__.py +10 -0
- tenxgraph_api/src/app/routers/ag_ui/converter.py +195 -0
- tenxgraph_api/src/app/routers/ag_ui/event_mapper.py +353 -0
- tenxgraph_api/src/app/routers/ag_ui/router.py +90 -0
- tenxgraph_api/src/app/routers/ag_ui/service.py +193 -0
- tenxgraph_api/src/app/routers/checkpointer/__init__.py +1 -0
- tenxgraph_api/src/app/routers/checkpointer/router.py +482 -0
- tenxgraph_api/src/app/routers/checkpointer/schemas/__init__.py +1 -0
- tenxgraph_api/src/app/routers/checkpointer/schemas/checkpointer_schemas.py +121 -0
- tenxgraph_api/src/app/routers/checkpointer/services/__init__.py +1 -0
- tenxgraph_api/src/app/routers/checkpointer/services/checkpointer_service.py +300 -0
- tenxgraph_api/src/app/routers/evals/__init__.py +6 -0
- tenxgraph_api/src/app/routers/evals/router.py +38 -0
- tenxgraph_api/src/app/routers/evals/services/__init__.py +1 -0
- tenxgraph_api/src/app/routers/evals/services/eval_report_service.py +354 -0
- tenxgraph_api/src/app/routers/graph/__init__.py +6 -0
- tenxgraph_api/src/app/routers/graph/realtime_guard.py +161 -0
- tenxgraph_api/src/app/routers/graph/router.py +821 -0
- tenxgraph_api/src/app/routers/graph/schemas/__init__.py +1 -0
- tenxgraph_api/src/app/routers/graph/schemas/graph_schemas.py +386 -0
- tenxgraph_api/src/app/routers/graph/services/__init__.py +1 -0
- tenxgraph_api/src/app/routers/graph/services/graph_service.py +1219 -0
- tenxgraph_api/src/app/routers/graph/services/multimodal_preprocessor.py +164 -0
- tenxgraph_api/src/app/routers/media/__init__.py +506 -0
- tenxgraph_api/src/app/routers/media/router.py +242 -0
- tenxgraph_api/src/app/routers/media/schemas.py +39 -0
- tenxgraph_api/src/app/routers/ping/__init__.py +4 -0
- tenxgraph_api/src/app/routers/ping/router.py +28 -0
- tenxgraph_api/src/app/routers/setup_router.py +60 -0
- tenxgraph_api/src/app/routers/store/__init__.py +4 -0
- tenxgraph_api/src/app/routers/store/router.py +200 -0
- tenxgraph_api/src/app/routers/store/schemas/__init__.py +28 -0
- tenxgraph_api/src/app/routers/store/schemas/store_schemas.py +200 -0
- tenxgraph_api/src/app/routers/store/services/__init__.py +4 -0
- tenxgraph_api/src/app/routers/store/services/store_service.py +203 -0
- tenxgraph_api/src/app/tasks/__init__.py +0 -0
- tenxgraph_api/src/app/tasks/user_tasks.py +38 -0
- tenxgraph_api/src/app/utils/__init__.py +12 -0
- tenxgraph_api/src/app/utils/callable_helper.py +26 -0
- tenxgraph_api/src/app/utils/media/__init__.py +15 -0
- tenxgraph_api/src/app/utils/media/extractor.py +172 -0
- tenxgraph_api/src/app/utils/media/pipeline.py +83 -0
- tenxgraph_api/src/app/utils/parse_output.py +17 -0
- tenxgraph_api/src/app/utils/response_helper.py +129 -0
- tenxgraph_api/src/app/utils/schemas/__init__.py +11 -0
- tenxgraph_api/src/app/utils/schemas/output_schemas.py +28 -0
- tenxgraph_api/src/app/utils/schemas/user_schemas.py +13 -0
- tenxgraph_api/src/app/utils/snowflake_id_generator.py +90 -0
- tenxgraph_api/src/app/utils/swagger_helper.py +160 -0
- tenxgraph_api/src/app/utils/telemetry_store.py +123 -0
- tenxgraph_api/src/app/utils/thread_name_generator.py +304 -0
- tenxgraph_api/src/app/worker.py +91 -0
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import os
|
|
3
|
+
from functools import lru_cache
|
|
4
|
+
|
|
5
|
+
from pydantic import ConfigDict, Field, field_validator, model_validator
|
|
6
|
+
from pydantic_settings import BaseSettings
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
IS_PRODUCTION = False
|
|
10
|
+
LOGGER_NAME = os.getenv("LOGGER_NAME", "10xgraph-api")
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(LOGGER_NAME)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Settings(BaseSettings):
|
|
16
|
+
"""
|
|
17
|
+
This class defines the configuration settings for the application.
|
|
18
|
+
|
|
19
|
+
Attributes:
|
|
20
|
+
APP_NAME (str): The name of the application.
|
|
21
|
+
APP_VERSION (str): The version of the application.
|
|
22
|
+
MODE (str): The mode in which the application is running (e.g., development, production).
|
|
23
|
+
LOG_LEVEL (int): The logging level for the application.
|
|
24
|
+
SUMMARY (str): A brief summary of the application. Default is "Backend Base".
|
|
25
|
+
|
|
26
|
+
ORIGINS (str): CORS allowed origins.
|
|
27
|
+
ALLOWED_HOST (str): CORS allowed hosts.
|
|
28
|
+
REDIS_URL (str): The URL for the Redis server.
|
|
29
|
+
|
|
30
|
+
SENTRY_DSN (str): The DSN for Sentry error tracking.
|
|
31
|
+
|
|
32
|
+
Config:
|
|
33
|
+
extra (str): Configuration for handling extra fields. Default is "allow".
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
APP_NAME: str = "MyApp"
|
|
37
|
+
APP_VERSION: str = "0.1.0"
|
|
38
|
+
MODE: str = "development"
|
|
39
|
+
# CRITICAL = 50
|
|
40
|
+
# FATAL = CRITICAL
|
|
41
|
+
# ERROR = 40
|
|
42
|
+
# WARNING = 30
|
|
43
|
+
# WARN = WARNING
|
|
44
|
+
# INFO = 20
|
|
45
|
+
# DEBUG = 10
|
|
46
|
+
# NOTSET = 0
|
|
47
|
+
LOG_LEVEL: str = "INFO"
|
|
48
|
+
IS_DEBUG: bool = True
|
|
49
|
+
|
|
50
|
+
#################################
|
|
51
|
+
###### Request Limits ###########
|
|
52
|
+
#################################
|
|
53
|
+
MAX_REQUEST_SIZE: int = 10 * 1024 * 1024 # 10MB default
|
|
54
|
+
|
|
55
|
+
#################################
|
|
56
|
+
###### Security Headers #########
|
|
57
|
+
#################################
|
|
58
|
+
SECURITY_HEADERS_ENABLED: bool = True
|
|
59
|
+
HSTS_ENABLED: bool = True
|
|
60
|
+
HSTS_MAX_AGE: int = 31536000 # 1 year in seconds
|
|
61
|
+
HSTS_INCLUDE_SUBDOMAINS: bool = True
|
|
62
|
+
HSTS_PRELOAD: bool = False
|
|
63
|
+
FRAME_OPTIONS: str = "DENY" # DENY, SAMEORIGIN, or ALLOW-FROM
|
|
64
|
+
CONTENT_TYPE_OPTIONS: str = "nosniff"
|
|
65
|
+
XSS_PROTECTION: str = "1; mode=block"
|
|
66
|
+
REFERRER_POLICY: str = "strict-origin-when-cross-origin"
|
|
67
|
+
PERMISSIONS_POLICY: str | None = None # Uses default if None
|
|
68
|
+
CSP_POLICY: str | None = None # Uses default if None
|
|
69
|
+
|
|
70
|
+
SUMMARY: str = "10xGraph Backend"
|
|
71
|
+
|
|
72
|
+
#################################
|
|
73
|
+
###### CORS Config ##############
|
|
74
|
+
#################################
|
|
75
|
+
ORIGINS: str = "*"
|
|
76
|
+
ALLOWED_HOST: str = "*"
|
|
77
|
+
# Whether cross-origin requests may carry credentials (cookies / auth headers).
|
|
78
|
+
#
|
|
79
|
+
# Combined with ORIGINS="*" this is the dangerous case: Starlette reflects the
|
|
80
|
+
# request's Origin back with Access-Control-Allow-Credentials: true, which
|
|
81
|
+
# effectively makes EVERY origin a trusted, credentialed origin. In production
|
|
82
|
+
# that combination is refused at startup (see setup_middleware); set explicit
|
|
83
|
+
# ORIGINS, or set CORS_ALLOW_CREDENTIALS=false to serve a public,
|
|
84
|
+
# non-credentialed API from any origin.
|
|
85
|
+
CORS_ALLOW_CREDENTIALS: bool = True
|
|
86
|
+
|
|
87
|
+
#################################
|
|
88
|
+
###### Paths ####################
|
|
89
|
+
#################################
|
|
90
|
+
ROOT_PATH: str = "/"
|
|
91
|
+
DOCS_PATH: str = "/docs"
|
|
92
|
+
REDOCS_PATH: str = "/redocs"
|
|
93
|
+
|
|
94
|
+
#################################
|
|
95
|
+
###### REDIS Config ##########
|
|
96
|
+
#################################
|
|
97
|
+
REDIS_URL: str | None = None
|
|
98
|
+
|
|
99
|
+
#################################
|
|
100
|
+
###### sentry Config ############
|
|
101
|
+
#################################
|
|
102
|
+
SENTRY_DSN: str | None = None
|
|
103
|
+
# Share of requests traced / profiled. 1.0 sends every request, which is costly and
|
|
104
|
+
# rarely wanted in production.
|
|
105
|
+
SENTRY_TRACES_SAMPLE_RATE: float = Field(default=0.1, ge=0.0, le=1.0)
|
|
106
|
+
SENTRY_PROFILES_SAMPLE_RATE: float = Field(default=0.0, ge=0.0, le=1.0)
|
|
107
|
+
|
|
108
|
+
#################################
|
|
109
|
+
###### Auth ############
|
|
110
|
+
#################################
|
|
111
|
+
SNOWFLAKE_EPOCH: int = 1609459200000
|
|
112
|
+
SNOWFLAKE_NODE_ID: int = 1
|
|
113
|
+
SNOWFLAKE_WORKER_ID: int = 2
|
|
114
|
+
SNOWFLAKE_TIME_BITS: int = 39
|
|
115
|
+
SNOWFLAKE_NODE_BITS: int = 5
|
|
116
|
+
SNOWFLAKE_WORKER_BITS: int = 8
|
|
117
|
+
|
|
118
|
+
#################################
|
|
119
|
+
###### JWT Config ###############
|
|
120
|
+
#################################
|
|
121
|
+
JWT_SECRET_KEY: str | None = None
|
|
122
|
+
JWT_ALGORITHM: str = "HS256"
|
|
123
|
+
# When set, tokens must carry a matching ``iss`` / ``aud`` claim, so a token minted for
|
|
124
|
+
# another service that shares the signing key is not accepted here.
|
|
125
|
+
JWT_ISSUER: str | None = None
|
|
126
|
+
JWT_AUDIENCE: str | None = None
|
|
127
|
+
|
|
128
|
+
#################################
|
|
129
|
+
###### OTEL Config ##############
|
|
130
|
+
#################################
|
|
131
|
+
OTEL_ENABLED: bool = False
|
|
132
|
+
OTEL_SERVICE_NAME: str = "10xgraph-api"
|
|
133
|
+
OTEL_EXPORTER_OTLP_ENDPOINT: str | None = None
|
|
134
|
+
OTEL_LEVEL: str = "standard" # spans | standard | full
|
|
135
|
+
|
|
136
|
+
@field_validator("MODE", mode="before")
|
|
137
|
+
@classmethod
|
|
138
|
+
def normalize_mode(cls, v: str | None) -> str:
|
|
139
|
+
"""Normalize MODE to lowercase."""
|
|
140
|
+
return v.lower() if v else "development"
|
|
141
|
+
|
|
142
|
+
@field_validator("ORIGINS")
|
|
143
|
+
@classmethod
|
|
144
|
+
def warn_cors_wildcard(cls, v: str) -> str:
|
|
145
|
+
"""Warn if CORS is set to wildcard in production."""
|
|
146
|
+
mode = os.environ.get("MODE", "development").lower()
|
|
147
|
+
if v == "*" and mode == "production":
|
|
148
|
+
logger.warning(
|
|
149
|
+
"⚠️ SECURITY WARNING: CORS ORIGINS='*' in production.\n"
|
|
150
|
+
" This allows any website to make requests to your API.\n"
|
|
151
|
+
" Set ORIGINS to specific domains (e.g., https://yourdomain.com)"
|
|
152
|
+
)
|
|
153
|
+
return v
|
|
154
|
+
|
|
155
|
+
@model_validator(mode="after")
|
|
156
|
+
def check_production_security(self):
|
|
157
|
+
"""Check for insecure configurations in production mode."""
|
|
158
|
+
if self.MODE == "production":
|
|
159
|
+
# Docs (and the OpenAPI schema behind them) are off in production unless a path
|
|
160
|
+
# was set explicitly.
|
|
161
|
+
for field in ("DOCS_PATH", "REDOCS_PATH"):
|
|
162
|
+
if field not in self.model_fields_set:
|
|
163
|
+
setattr(self, field, "")
|
|
164
|
+
|
|
165
|
+
warnings = []
|
|
166
|
+
|
|
167
|
+
if self.IS_DEBUG:
|
|
168
|
+
warnings.append(
|
|
169
|
+
"⚠️ DEBUG mode is enabled in production. This may expose sensitive information."
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
if self.DOCS_PATH or self.REDOCS_PATH:
|
|
173
|
+
warnings.append(
|
|
174
|
+
"⚠️ API documentation endpoints are enabled in production. "
|
|
175
|
+
"Consider disabling DOCS_PATH and REDOCS_PATH."
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
if self.ALLOWED_HOST == "*":
|
|
179
|
+
warnings.append(
|
|
180
|
+
"⚠️ ALLOWED_HOST='*' in production. "
|
|
181
|
+
"Set to specific hostnames for better security."
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
if warnings:
|
|
185
|
+
logger.warning("\n".join(["\n🔒 PRODUCTION SECURITY WARNINGS:", *warnings]))
|
|
186
|
+
|
|
187
|
+
return self
|
|
188
|
+
|
|
189
|
+
model_config = ConfigDict(extra="allow")
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
@lru_cache
|
|
193
|
+
def get_settings() -> Settings:
|
|
194
|
+
"""
|
|
195
|
+
Retrieve and return the application settings.
|
|
196
|
+
If not in production, load settings from a specific environment file.
|
|
197
|
+
Returns:
|
|
198
|
+
Settings: An instance of the Settings class containing
|
|
199
|
+
application configurations.
|
|
200
|
+
"""
|
|
201
|
+
logger.info("Loading settings from environment variables and .env if present")
|
|
202
|
+
return Settings() # type: ignore
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
from fastapi.logger import logger as fastapi_logger
|
|
5
|
+
|
|
6
|
+
from tenxgraph_api.src.app.core.config.settings import LOGGER_NAME
|
|
7
|
+
from tenxgraph_api.src.app.core.utils.log_sanitizer import SanitizingFormatter
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
# Top-level names of the loggers the API server writes to; children ("tenxgraph_api.media",
|
|
11
|
+
# "tenxgraph_api.rate_limit", ...) reach these handlers through propagation.
|
|
12
|
+
APP_LOGGER_NAMES = (LOGGER_NAME, "10xgraph-api", "tenxgraph_api", "tenxgraph_api")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def init_logger(level: int | str = logging.INFO) -> None:
|
|
16
|
+
"""
|
|
17
|
+
Initializes and configures logging for the application.
|
|
18
|
+
|
|
19
|
+
This function sets up various loggers used in the application, including
|
|
20
|
+
those for Gunicorn, Uvicorn, FastAPI, database clients, Tortoise ORM, and
|
|
21
|
+
custom loggers. It also configures a console handler to output logs to
|
|
22
|
+
stdout.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
level (int): The logging level to set for the loggers.
|
|
26
|
+
"""
|
|
27
|
+
# GCLOUD SETUP
|
|
28
|
+
# client = Client()
|
|
29
|
+
# client.get_default_handler()
|
|
30
|
+
# client.setup_logging()
|
|
31
|
+
|
|
32
|
+
# setup logging
|
|
33
|
+
gunicorn_error_logger = logging.getLogger("gunicorn.error")
|
|
34
|
+
# gunicorn_logger = logging.getLogger("gunicorn")
|
|
35
|
+
uvicorn_access_logger = logging.getLogger("uvicorn.access")
|
|
36
|
+
uvicorn_access_logger.handlers = gunicorn_error_logger.handlers
|
|
37
|
+
fastapi_logger.handlers = gunicorn_error_logger.handlers
|
|
38
|
+
fastapi_logger.setLevel(level)
|
|
39
|
+
|
|
40
|
+
# Create console handler and set level to DEBUG
|
|
41
|
+
console_handler = logging.StreamHandler(sys.stdout)
|
|
42
|
+
console_handler.setLevel(level)
|
|
43
|
+
|
|
44
|
+
# Create formatter
|
|
45
|
+
base_formatter = logging.Formatter(
|
|
46
|
+
"%(asctime)s - %(name)s - %(levelname)s - %(filename)s:%(lineno)d - %(message)s"
|
|
47
|
+
)
|
|
48
|
+
# Wrap with sanitizing formatter to prevent sensitive data in logs
|
|
49
|
+
formatter = SanitizingFormatter(base_formatter)
|
|
50
|
+
|
|
51
|
+
# Add formatter to console handler
|
|
52
|
+
console_handler.setFormatter(formatter)
|
|
53
|
+
# Add console handler to logger
|
|
54
|
+
fastapi_logger.addHandler(console_handler)
|
|
55
|
+
|
|
56
|
+
# Route application loggers through the same sanitizing console handler. They stop
|
|
57
|
+
# propagating so an unsanitized copy does not also reach the root (or last-resort) handler.
|
|
58
|
+
for logger_name in dict.fromkeys(APP_LOGGER_NAMES):
|
|
59
|
+
app_logger = logging.getLogger(logger_name)
|
|
60
|
+
app_logger.setLevel(level)
|
|
61
|
+
for handler in list(app_logger.handlers):
|
|
62
|
+
if isinstance(handler.formatter, SanitizingFormatter):
|
|
63
|
+
app_logger.removeHandler(handler) # init_logger may run more than once
|
|
64
|
+
app_logger.addHandler(console_handler)
|
|
65
|
+
app_logger.propagate = False
|