Files
hack/tools/scripts/llm-key-hunter/results/_cache/content/akcayfx_sentrix.json
T
OpenCode 68a9071cf1 feat: reconcile local master with origin (exa/hot-platform hunters, leaks ledger, latest results)
Local branch had diverged from origin/master (sibling commits on the same base). Rewrote local history linearly on top of origin/master, folding in all local content: exa/hot-platform discovery hunters, leaks ledger, nightly sweep orchestrator, updated .gitignore and skill docs, plus the latest hunt output and vault state. Remote-only files (vault keys, channel scripts) were restored rather than dropped, so the resulting tree is a full union of both sides.
2026-08-07 12:53:47 +08:00

1 line
21 KiB
JSON

{"repo": "akcayfx/sentrix", "files": {"backend/internal/config/config.go": {"0e83d2fbd9c17aa860cc50700bf824e0e3921e72": {"t": 1785745642.235369, "n": 8291, "h": "e01c9afabf5ff4ed", "c": "package config\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n)\n\ntype Config struct {\n\tServer ServerConfig\n\tDatabase DatabaseConfig\n\tAuth AuthConfig\n\tLog LogConfig\n\tLLM LLMConfig\n\tAgent AgentConfig\n\tSearch SearchConfig\n\tDocker DockerConfig\n\tEmbedding EmbeddingConfig\n\tObservability ObservabilityConfig\n\tScraper ScraperConfig\n}\n\ntype ScraperConfig struct {\n\tPublicURL string // Full base URL for public targets, may include credentials\n\tPrivateURL string // Full base URL for private/internal targets, may include credentials\n}\n\ntype DockerConfig struct {\n\tEnabled bool\n\tSocketPath string\n\tDefaultImage string\n\tNetwork string\n\tDataDir string\n\tCPULimit float64\n\tMemoryLimitMB int\n\tContainerTimeout int // seconds\n\tInside bool // true when sentrix itself runs inside Docker\n}\n\ntype EmbeddingConfig struct {\n\tProvider string // \"openai\", \"ollama\", \"none\"\n\tModel string\n\tAPIKey string\n\tBaseURL string\n\tDimensions int\n\tBatchSize int\n}\n\ntype ObservabilityConfig struct {\n\tEnabled bool\n\tServiceName string\n\tOTLPEndpoint string\n\tTraceSampleRate float64\n\tLangfuseEnabled bool\n\tLangfusePublicKey string\n\tLangfuseSecretKey string\n\tLangfuseHost string\n}\n\ntype AgentConfig struct {\n\tWorkers int\n\tSameToolLimit int\n\tTotalToolLimit int\n\tTaskToolLimit int // max total tool calls across all subtasks in one task (0 = TotalToolLimit * 3)\n\tSqlmapTimeoutSeconds int\n}\n\ntype LLMConfig struct {\n\tOpenAIKey string\n\tAnthropicKey string\n\tGeminiKey string\n\tDeepSeekKey string\n\tOllamaURL string\n\tCustomURL string\n\tCustomModel string\n\tCustomAPIKey string\n\tDefaultProvider string\n}\n\ntype SearchConfig struct {\n\tDefaultMaxResults int\n\tTimeoutSeconds int\n\tProviderPriority []string\n\n\tDuckDuckGoEnabled bool\n\n\tGoogleAPIKey string\n\tGoogleCX string\n\n\tTavilyAPIKey string\n\n\tTraversaalAPIKey string\n\n\tPerplexityAPIKey string\n\tPerplexityModel string\n\n\tSearxngURL string\n\tSearxngLanguage string\n\tSearxngCategories string\n\tSearxngSafeSearch string\n\n\tSploitusEnabled bool\n\n\tBrowserUserAgent string\n}\n\ntype ServerConfig struct {\n\tHost string\n\tPort int\n\tAllowedOrigins string\n}\n\ntype DatabaseConfig struct {\n\tHost string\n\tPort int\n\tUser string\n\tPassword string\n\tName string\n\tSSLMode string\n}\n\ntype AuthConfig struct {\n\tJWTSecret string\n\tTokenExpiry int\n}\n\ntype LogConfig struct {\n\tLevel string\n\tFormat string\n}\n\nfunc Load() (*Config, error) {\n\tcfg := &Config{\n\t\tServer: ServerConfig{\n\t\t\tHost: env(\"SERVER_HOST\", \"0.0.0.0\"),\n\t\t\tPort: envInt(\"SERVER_PORT\", 8080),\n\t\t\tAllowedOrigins: env(\"ALLOWED_ORIGINS\", \"*\"),\n\t\t},\n\t\tDatabase: DatabaseConfig{\n\t\t\tHost: env(\"DB_HOST\", \"localhost\"),\n\t\t\tPort: envInt(\"DB_PORT\", 5432),\n\t\t\tUser: env(\"DB_USER\", \"sentrix\"),\n\t\t\tPassword: env(\"DB_PASSWORD\", \"sentrix\"),\n\t\t\tName: env(\"DB_NAME\", \"sentrix\"),\n\t\t\tSSLMode: env(\"DB_SSLMODE\", \"disable\"),\n\t\t},\n\t\tAuth: AuthConfig{\n\t\t\tJWTSecret: env(\"JWT_SECRET\", \"\"),\n\t\t\tTokenExpiry: envInt(\"JWT_EXPIRY_HOURS\", 24),\n\t\t},\n\t\tLog: LogConfig{\n\t\t\tLevel: env(\"LOG_LEVEL\", \"info\"),\n\t\t\tFormat: env(\"LOG_FORMAT\", \"text\"),\n\t\t},\n\t\tLLM: LLMConfig{\n\t\t\tOpenAIKey: env(\"OPENAI_API_KEY\", \"\"),\n\t\t\tAnthropicKey: env(\"ANTHROPIC_API_KEY\", \"\"),\n\t\t\tGeminiKey: env(\"GEMINI_API_KEY\", \"\"),\n\t\t\tDeepSeekKey: env(\"DEEPSEEK_API_KEY\", \"\"),\n\t\t\tOllamaURL: env(\"OLLAMA_URL\", \"\"),\n\t\t\tCustomURL: env(\"CUSTOM_LLM_URL\", \"\"),\n\t\t\tCustomModel: env(\"CUSTOM_LLM_MODEL\", \"\"),\n\t\t\tCustomAPIKey: env(\"CUSTOM_LLM_API_KEY\", \"\"),\n\t\t\tDefaultProvider: env(\"DEFAULT_LLM_PROVIDER\", \"\"),\n\t\t},\n\t\tAgent: AgentConfig{\n\t\t\tWorkers: envInt(\"AGENT_WORKERS\", 2),\n\t\t\tSameToolLimit: envInt(\"AGENT_SAME_TOOL_LIMIT\", 4),\n\t\t\tTotalToolLimit: envInt(\"AGENT_TOTAL_TOOL_LIMIT\", 20),\n\t\t\tTaskToolLimit: envInt(\"AGENT_TASK_TOOL_LIMIT\", 60),\n\t\t\tSqlmapTimeoutSeconds: envInt(\"SQLMAP_DEFAULT_TIMEOUT_SECONDS\", 180),\n\t\t},\n\t\tSearch: SearchConfig{\n\t\t\tDefaultMaxResults: envInt(\"SEARCH_DEFAULT_MAX_RESULTS\", 5),\n\t\t\tTimeoutSeconds: envInt(\"SEARCH_TIMEOUT_SECONDS\", 30),\n\t\t\tProviderPriority: envCSV(\n\t\t\t\t\"SEARCH_PROVIDER_PRIORITY\",\n\t\t\t\t[]string{\"duckduckgo\", \"tavily\", \"searxng\", \"google\", \"perplexity\", \"traversaal\", \"sploitus\"},\n\t\t\t),\n\t\t\tDuckDuckGoEnabled: envBool(\"DUCKDUCKGO_ENABLED\", true),\n\t\t\tGoogleAPIKey: env(\"GOOGLE_SEARCH_API_KEY\", \"\"),\n\t\t\tGoogleCX: env(\"GOOGLE_SEARCH_CX\", \"\"),\n\t\t\tTavilyAPIKey: env(\"TAVILY_API_KEY\", \"\"),\n\t\t\tTraversaalAPIKey: env(\"TRAVERSAAL_API_KEY\", \"\"),\n\t\t\tPerplexityAPIKey: env(\"PERPLEXITY_API_KEY\", \"\"),\n\t\t\tPerplexityModel: env(\"PERPLEXITY_MODEL\", \"sonar\"),\n\t\t\tSearxngURL: env(\"SEARXNG_URL\", \"\"),\n\t\t\tSearxngLanguage: env(\"SEARXNG_LANGUAGE\", \"en\"),\n\t\t\tSearxngCategories: env(\"SEARXNG_CATEGORIES\", \"general\"),\n\t\t\tSearxngSafeSearch: env(\"SEARXNG_SAFE_SEARCH\", \"1\"),\n\t\t\tSploitusEnabled: envBool(\"SPLOITUS_ENABLED\", true),\n\t\t\tBrowserUserAgent: env(\"BROWSER_USER_AGENT\", \"Sentrix/0.7\"),\n\t\t},\n\t\tDocker: DockerConfig{\n\t\t\tEnabled: envBool(\"DOCKER_ENABLED\", false),\n\t\t\tSocketPath: env(\"DOCKER_SOCKET\", \"/var/run/docker.sock\"),\n\t\t\tDefaultImage: env(\"DOCKER_DEFAULT_IMAGE\", \"sentrix-tools:latest\"),\n\t\t\tNetwork: env(\"DOCKER_NETWORK\", \"sentrix-sandbox\"),\n\t\t\tDataDir: env(\"DOCKER_DATA_DIR\", \"./data/sandbox\"),\n\t\t\tCPULimit: envFloat(\"DOCKER_CPU_LIMIT\", 1.0),\n\t\t\tMemoryLimitMB: envInt(\"DOCKER_MEMORY_LIMIT_MB\", 512),\n\t\t\tContainerTimeout: envInt(\"DOCKER_CONTAINER_TIMEOUT\", 1800),\n\t\t\tInside: envBool(\"DOCKER_INSIDE\", false),\n\t\t},\n\t\tEmbedding: EmbeddingConfig{\n\t\t\tProvider: env(\"EMBEDDING_PROVIDER\", \"none\"),\n\t\t\tModel: env(\"EMBEDDING_MODEL\", \"text-embedding-3-small\"),\n\t\t\tAPIKey: env(\"EMBEDDING_API_KEY\", \"\"),\n\t\t\tBaseURL: env(\"EMBEDDING_BASE_URL\", \"\"),\n\t\t\tDimensions: envInt(\"EMBEDDING_DIMENSIONS\", 1536),\n\t\t\tBatchSize: envInt(\"EMBEDDING_BATCH_SIZE\", 100),\n\t\t},\n\t\tScraper: ScraperConfig{\n\t\t\tPublicURL: env(\"SCRAPER_PUBLIC_URL\", \"\"),\n\t\t\tPrivateURL: env(\"SCRAPER_PRIVATE_URL\", \"\"),\n\t\t},\n\t\tObservability: ObservabilityConfig{\n\t\t\tEnabled: envBool(\"OBSERVABILITY_ENABLED\", false),\n\t\t\tServiceName: env(\"OTEL_SERVICE_NAME\", \"sentrix\"),\n\t\t\tOTLPEndpoint: env(\"OTEL_EXPORTER_OTLP_ENDPOINT\", \"localhost:4317\"),\n\t\t\tTraceSampleRate: envFloat(\"OTEL_TRACE_SAMPLE_RATE\", 1.0),\n\t\t\tLangfuseEnabled: envBool(\"LANGFUSE_ENABLED\", false),\n\t\t\tLangfusePublicKey: env(\"LANGFUSE_PUBLIC_KEY\", \"\"),\n\t\t\tLangfuseSecretKey: env(\"LANGFUSE_SECRET_KEY\", \"\"),\n\t\t\tLangfuseHost: env(\"LANGFUSE_HOST\", \"https://cloud.langfuse.com\"),\n\t\t},\n\t}\n\n\t// Fall back embedding API key to OpenAI key if not set.\n\tif cfg.Embedding.APIKey == \"\" {\n\t\tcfg.Embedding.APIKey = cfg.LLM.OpenAIKey\n\t}\n\n\tif cfg.Auth.JWTSecret == \"\" {\n\t\treturn nil, fmt.Errorf(\"JWT_SECRET environment variable is required\")\n\t}\n\n\treturn cfg, nil\n}\n\nfunc (d DatabaseConfig) DSN() string {\n\treturn fmt.Sprintf(\n\t\t\"host=%s port=%d user=%s password=%s dbname=%s sslmode=%s\",\n\t\td.Host, d.Port, d.User, d.Password, d.Name, d.SSLMode,\n\t)\n}\n\nfunc env(key, fallback string) string {\n\tif v := os.Getenv(key); v != \"\" {\n\t\treturn v\n\t}\n\treturn fallback\n}\n\nfunc envInt(key string, fallback int) int {\n\tif v := os.Getenv(key); v != \"\" {\n\t\tif i, err := strconv.Atoi(v); err == nil {\n\t\t\treturn i\n\t\t}\n\t}\n\treturn fallback\n}\n\nfunc envFloat(key string, fallback float64) float64 {\n\tif v := os.Getenv(key); v != \"\" {\n\t\tif f, err := strconv.ParseFloat(v, 64); err == nil {\n\t\t\treturn f\n\t\t}\n\t}\n\treturn fallback\n}\n\nfunc envBool(key string, fallback bool) bool {\n\tif v := os.Getenv(key); v != \"\" {\n\t\tswitch v {\n\t\tcase \"1\", \"true\", \"TRUE\", \"True\", \"yes\", \"YES\", \"on\", \"ON\":\n\t\t\treturn true\n\t\tcase \"0\", \"false\", \"FALSE\", \"False\", \"no\", \"NO\", \"off\", \"OFF\":\n\t\t\treturn false\n\t\t}\n\t}\n\treturn fallback\n}\n\nfunc envCSV(key string, fallback []string) []string {\n\tv := os.Getenv(key)\n\tif v == \"\" {\n\t\treturn append([]string{}, fallback...)\n\t}\n\n\tparts := strings.Split(v, \",\")\n\tout := make([]string, 0, len(parts))\n\tfor _, part := range parts {\n\t\tpart = strings.TrimSpace(part)\n\t\tif part != \"\" {\n\t\t\tout = append(out, part)\n\t\t}\n\t}\n\tif len(out) == 0 {\n\t\treturn append([]string{}, fallback...)\n\t}\n\treturn out\n}\n"}, "4ada86e2edd3114e68e926abdaf26a21a4eb82c7": {"t": 1785755220.3041015, "n": 8291, "h": "e01c9afabf5ff4ed", "c": "package config\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n)\n\ntype Config struct {\n\tServer ServerConfig\n\tDatabase DatabaseConfig\n\tAuth AuthConfig\n\tLog LogConfig\n\tLLM LLMConfig\n\tAgent AgentConfig\n\tSearch SearchConfig\n\tDocker DockerConfig\n\tEmbedding EmbeddingConfig\n\tObservability ObservabilityConfig\n\tScraper ScraperConfig\n}\n\ntype ScraperConfig struct {\n\tPublicURL string // Full base URL for public targets, may include credentials\n\tPrivateURL string // Full base URL for private/internal targets, may include credentials\n}\n\ntype DockerConfig struct {\n\tEnabled bool\n\tSocketPath string\n\tDefaultImage string\n\tNetwork string\n\tDataDir string\n\tCPULimit float64\n\tMemoryLimitMB int\n\tContainerTimeout int // seconds\n\tInside bool // true when sentrix itself runs inside Docker\n}\n\ntype EmbeddingConfig struct {\n\tProvider string // \"openai\", \"ollama\", \"none\"\n\tModel string\n\tAPIKey string\n\tBaseURL string\n\tDimensions int\n\tBatchSize int\n}\n\ntype ObservabilityConfig struct {\n\tEnabled bool\n\tServiceName string\n\tOTLPEndpoint string\n\tTraceSampleRate float64\n\tLangfuseEnabled bool\n\tLangfusePublicKey string\n\tLangfuseSecretKey string\n\tLangfuseHost string\n}\n\ntype AgentConfig struct {\n\tWorkers int\n\tSameToolLimit int\n\tTotalToolLimit int\n\tTaskToolLimit int // max total tool calls across all subtasks in one task (0 = TotalToolLimit * 3)\n\tSqlmapTimeoutSeconds int\n}\n\ntype LLMConfig struct {\n\tOpenAIKey string\n\tAnthropicKey string\n\tGeminiKey string\n\tDeepSeekKey string\n\tOllamaURL string\n\tCustomURL string\n\tCustomModel string\n\tCustomAPIKey string\n\tDefaultProvider string\n}\n\ntype SearchConfig struct {\n\tDefaultMaxResults int\n\tTimeoutSeconds int\n\tProviderPriority []string\n\n\tDuckDuckGoEnabled bool\n\n\tGoogleAPIKey string\n\tGoogleCX string\n\n\tTavilyAPIKey string\n\n\tTraversaalAPIKey string\n\n\tPerplexityAPIKey string\n\tPerplexityModel string\n\n\tSearxngURL string\n\tSearxngLanguage string\n\tSearxngCategories string\n\tSearxngSafeSearch string\n\n\tSploitusEnabled bool\n\n\tBrowserUserAgent string\n}\n\ntype ServerConfig struct {\n\tHost string\n\tPort int\n\tAllowedOrigins string\n}\n\ntype DatabaseConfig struct {\n\tHost string\n\tPort int\n\tUser string\n\tPassword string\n\tName string\n\tSSLMode string\n}\n\ntype AuthConfig struct {\n\tJWTSecret string\n\tTokenExpiry int\n}\n\ntype LogConfig struct {\n\tLevel string\n\tFormat string\n}\n\nfunc Load() (*Config, error) {\n\tcfg := &Config{\n\t\tServer: ServerConfig{\n\t\t\tHost: env(\"SERVER_HOST\", \"0.0.0.0\"),\n\t\t\tPort: envInt(\"SERVER_PORT\", 8080),\n\t\t\tAllowedOrigins: env(\"ALLOWED_ORIGINS\", \"*\"),\n\t\t},\n\t\tDatabase: DatabaseConfig{\n\t\t\tHost: env(\"DB_HOST\", \"localhost\"),\n\t\t\tPort: envInt(\"DB_PORT\", 5432),\n\t\t\tUser: env(\"DB_USER\", \"sentrix\"),\n\t\t\tPassword: env(\"DB_PASSWORD\", \"sentrix\"),\n\t\t\tName: env(\"DB_NAME\", \"sentrix\"),\n\t\t\tSSLMode: env(\"DB_SSLMODE\", \"disable\"),\n\t\t},\n\t\tAuth: AuthConfig{\n\t\t\tJWTSecret: env(\"JWT_SECRET\", \"\"),\n\t\t\tTokenExpiry: envInt(\"JWT_EXPIRY_HOURS\", 24),\n\t\t},\n\t\tLog: LogConfig{\n\t\t\tLevel: env(\"LOG_LEVEL\", \"info\"),\n\t\t\tFormat: env(\"LOG_FORMAT\", \"text\"),\n\t\t},\n\t\tLLM: LLMConfig{\n\t\t\tOpenAIKey: env(\"OPENAI_API_KEY\", \"\"),\n\t\t\tAnthropicKey: env(\"ANTHROPIC_API_KEY\", \"\"),\n\t\t\tGeminiKey: env(\"GEMINI_API_KEY\", \"\"),\n\t\t\tDeepSeekKey: env(\"DEEPSEEK_API_KEY\", \"\"),\n\t\t\tOllamaURL: env(\"OLLAMA_URL\", \"\"),\n\t\t\tCustomURL: env(\"CUSTOM_LLM_URL\", \"\"),\n\t\t\tCustomModel: env(\"CUSTOM_LLM_MODEL\", \"\"),\n\t\t\tCustomAPIKey: env(\"CUSTOM_LLM_API_KEY\", \"\"),\n\t\t\tDefaultProvider: env(\"DEFAULT_LLM_PROVIDER\", \"\"),\n\t\t},\n\t\tAgent: AgentConfig{\n\t\t\tWorkers: envInt(\"AGENT_WORKERS\", 2),\n\t\t\tSameToolLimit: envInt(\"AGENT_SAME_TOOL_LIMIT\", 4),\n\t\t\tTotalToolLimit: envInt(\"AGENT_TOTAL_TOOL_LIMIT\", 20),\n\t\t\tTaskToolLimit: envInt(\"AGENT_TASK_TOOL_LIMIT\", 60),\n\t\t\tSqlmapTimeoutSeconds: envInt(\"SQLMAP_DEFAULT_TIMEOUT_SECONDS\", 180),\n\t\t},\n\t\tSearch: SearchConfig{\n\t\t\tDefaultMaxResults: envInt(\"SEARCH_DEFAULT_MAX_RESULTS\", 5),\n\t\t\tTimeoutSeconds: envInt(\"SEARCH_TIMEOUT_SECONDS\", 30),\n\t\t\tProviderPriority: envCSV(\n\t\t\t\t\"SEARCH_PROVIDER_PRIORITY\",\n\t\t\t\t[]string{\"duckduckgo\", \"tavily\", \"searxng\", \"google\", \"perplexity\", \"traversaal\", \"sploitus\"},\n\t\t\t),\n\t\t\tDuckDuckGoEnabled: envBool(\"DUCKDUCKGO_ENABLED\", true),\n\t\t\tGoogleAPIKey: env(\"GOOGLE_SEARCH_API_KEY\", \"\"),\n\t\t\tGoogleCX: env(\"GOOGLE_SEARCH_CX\", \"\"),\n\t\t\tTavilyAPIKey: env(\"TAVILY_API_KEY\", \"\"),\n\t\t\tTraversaalAPIKey: env(\"TRAVERSAAL_API_KEY\", \"\"),\n\t\t\tPerplexityAPIKey: env(\"PERPLEXITY_API_KEY\", \"\"),\n\t\t\tPerplexityModel: env(\"PERPLEXITY_MODEL\", \"sonar\"),\n\t\t\tSearxngURL: env(\"SEARXNG_URL\", \"\"),\n\t\t\tSearxngLanguage: env(\"SEARXNG_LANGUAGE\", \"en\"),\n\t\t\tSearxngCategories: env(\"SEARXNG_CATEGORIES\", \"general\"),\n\t\t\tSearxngSafeSearch: env(\"SEARXNG_SAFE_SEARCH\", \"1\"),\n\t\t\tSploitusEnabled: envBool(\"SPLOITUS_ENABLED\", true),\n\t\t\tBrowserUserAgent: env(\"BROWSER_USER_AGENT\", \"Sentrix/0.7\"),\n\t\t},\n\t\tDocker: DockerConfig{\n\t\t\tEnabled: envBool(\"DOCKER_ENABLED\", false),\n\t\t\tSocketPath: env(\"DOCKER_SOCKET\", \"/var/run/docker.sock\"),\n\t\t\tDefaultImage: env(\"DOCKER_DEFAULT_IMAGE\", \"sentrix-tools:latest\"),\n\t\t\tNetwork: env(\"DOCKER_NETWORK\", \"sentrix-sandbox\"),\n\t\t\tDataDir: env(\"DOCKER_DATA_DIR\", \"./data/sandbox\"),\n\t\t\tCPULimit: envFloat(\"DOCKER_CPU_LIMIT\", 1.0),\n\t\t\tMemoryLimitMB: envInt(\"DOCKER_MEMORY_LIMIT_MB\", 512),\n\t\t\tContainerTimeout: envInt(\"DOCKER_CONTAINER_TIMEOUT\", 1800),\n\t\t\tInside: envBool(\"DOCKER_INSIDE\", false),\n\t\t},\n\t\tEmbedding: EmbeddingConfig{\n\t\t\tProvider: env(\"EMBEDDING_PROVIDER\", \"none\"),\n\t\t\tModel: env(\"EMBEDDING_MODEL\", \"text-embedding-3-small\"),\n\t\t\tAPIKey: env(\"EMBEDDING_API_KEY\", \"\"),\n\t\t\tBaseURL: env(\"EMBEDDING_BASE_URL\", \"\"),\n\t\t\tDimensions: envInt(\"EMBEDDING_DIMENSIONS\", 1536),\n\t\t\tBatchSize: envInt(\"EMBEDDING_BATCH_SIZE\", 100),\n\t\t},\n\t\tScraper: ScraperConfig{\n\t\t\tPublicURL: env(\"SCRAPER_PUBLIC_URL\", \"\"),\n\t\t\tPrivateURL: env(\"SCRAPER_PRIVATE_URL\", \"\"),\n\t\t},\n\t\tObservability: ObservabilityConfig{\n\t\t\tEnabled: envBool(\"OBSERVABILITY_ENABLED\", false),\n\t\t\tServiceName: env(\"OTEL_SERVICE_NAME\", \"sentrix\"),\n\t\t\tOTLPEndpoint: env(\"OTEL_EXPORTER_OTLP_ENDPOINT\", \"localhost:4317\"),\n\t\t\tTraceSampleRate: envFloat(\"OTEL_TRACE_SAMPLE_RATE\", 1.0),\n\t\t\tLangfuseEnabled: envBool(\"LANGFUSE_ENABLED\", false),\n\t\t\tLangfusePublicKey: env(\"LANGFUSE_PUBLIC_KEY\", \"\"),\n\t\t\tLangfuseSecretKey: env(\"LANGFUSE_SECRET_KEY\", \"\"),\n\t\t\tLangfuseHost: env(\"LANGFUSE_HOST\", \"https://cloud.langfuse.com\"),\n\t\t},\n\t}\n\n\t// Fall back embedding API key to OpenAI key if not set.\n\tif cfg.Embedding.APIKey == \"\" {\n\t\tcfg.Embedding.APIKey = cfg.LLM.OpenAIKey\n\t}\n\n\tif cfg.Auth.JWTSecret == \"\" {\n\t\treturn nil, fmt.Errorf(\"JWT_SECRET environment variable is required\")\n\t}\n\n\treturn cfg, nil\n}\n\nfunc (d DatabaseConfig) DSN() string {\n\treturn fmt.Sprintf(\n\t\t\"host=%s port=%d user=%s password=%s dbname=%s sslmode=%s\",\n\t\td.Host, d.Port, d.User, d.Password, d.Name, d.SSLMode,\n\t)\n}\n\nfunc env(key, fallback string) string {\n\tif v := os.Getenv(key); v != \"\" {\n\t\treturn v\n\t}\n\treturn fallback\n}\n\nfunc envInt(key string, fallback int) int {\n\tif v := os.Getenv(key); v != \"\" {\n\t\tif i, err := strconv.Atoi(v); err == nil {\n\t\t\treturn i\n\t\t}\n\t}\n\treturn fallback\n}\n\nfunc envFloat(key string, fallback float64) float64 {\n\tif v := os.Getenv(key); v != \"\" {\n\t\tif f, err := strconv.ParseFloat(v, 64); err == nil {\n\t\t\treturn f\n\t\t}\n\t}\n\treturn fallback\n}\n\nfunc envBool(key string, fallback bool) bool {\n\tif v := os.Getenv(key); v != \"\" {\n\t\tswitch v {\n\t\tcase \"1\", \"true\", \"TRUE\", \"True\", \"yes\", \"YES\", \"on\", \"ON\":\n\t\t\treturn true\n\t\tcase \"0\", \"false\", \"FALSE\", \"False\", \"no\", \"NO\", \"off\", \"OFF\":\n\t\t\treturn false\n\t\t}\n\t}\n\treturn fallback\n}\n\nfunc envCSV(key string, fallback []string) []string {\n\tv := os.Getenv(key)\n\tif v == \"\" {\n\t\treturn append([]string{}, fallback...)\n\t}\n\n\tparts := strings.Split(v, \",\")\n\tout := make([]string, 0, len(parts))\n\tfor _, part := range parts {\n\t\tpart = strings.TrimSpace(part)\n\t\tif part != \"\" {\n\t\t\tout = append(out, part)\n\t\t}\n\t}\n\tif len(out) == 0 {\n\t\treturn append([]string{}, fallback...)\n\t}\n\treturn out\n}\n"}}, "docker-compose.yml": {"0e83d2fbd9c17aa860cc50700bf824e0e3921e72": {"t": 1786068608.5824196, "n": 2453, "h": "da3ca7b91fbc7e50", "c": "services:\n postgres:\n image: pgvector/pgvector:pg16\n environment:\n POSTGRES_USER: sentrix\n POSTGRES_PASSWORD: sentrix\n POSTGRES_DB: sentrix\n ports:\n - \"5432:5432\"\n volumes:\n - pgdata:/var/lib/postgresql/data\n healthcheck:\n test: [\"CMD-SHELL\", \"pg_isready -U sentrix\"]\n interval: 5s\n timeout: 5s\n retries: 5\n networks:\n - sentrix-net\n\n scraper:\n image: vxcontrol/scraper:latest\n environment:\n USERNAME: ${LOCAL_SCRAPER_USERNAME:-sentrix}\n PASSWORD: ${LOCAL_SCRAPER_PASSWORD:-sentrix}\n MAX_CONCURRENT_SESSIONS: ${LOCAL_SCRAPER_MAX_CONCURRENT_SESSIONS:-5}\n shm_size: 2g\n networks:\n - sentrix-net\n\n app:\n build: .\n # Local Docker socket access on Docker Desktop typically requires root\n # inside the container so the sandbox can start tool containers.\n user: \"0:0\"\n ports:\n - \"8080:8080\"\n environment:\n SERVER_HOST: 0.0.0.0\n SERVER_PORT: 8080\n DB_HOST: postgres\n DB_PORT: 5432\n DB_USER: sentrix\n DB_PASSWORD: sentrix\n DB_NAME: sentrix\n DB_SSLMODE: disable\n JWT_SECRET: ${JWT_SECRET:-change-me-in-production}\n LOG_LEVEL: ${LOG_LEVEL:-info}\n DEEPSEEK_API_KEY: ${DEEPSEEK_API_KEY:-}\n DEFAULT_LLM_PROVIDER: ${DEFAULT_LLM_PROVIDER:-deepseek}\n # Sandbox (Docker-in-Docker)\n DOCKER_ENABLED: ${DOCKER_ENABLED:-false}\n DOCKER_SOCKET: /var/run/docker.sock\n DOCKER_DEFAULT_IMAGE: ${DOCKER_DEFAULT_IMAGE:-sentrix-tools:latest}\n DOCKER_NETWORK: sentrix-sandbox\n DOCKER_DATA_DIR: /app/data/sandbox\n DOCKER_INSIDE: \"true\"\n # Embedding (Phase 8)\n EMBEDDING_PROVIDER: ${EMBEDDING_PROVIDER:-none}\n EMBEDDING_API_KEY: ${EMBEDDING_API_KEY:-}\n # Scraper (embedded)\n SCRAPER_PRIVATE_URL: https://${LOCAL_SCRAPER_USERNAME:-sentrix}:${LOCAL_SCRAPER_PASSWORD:-sentrix}@scraper/\n SCRAPER_PUBLIC_URL: ${SCRAPER_PUBLIC_URL:-}\n depends_on:\n postgres:\n condition: service_healthy\n scraper:\n condition: service_started\n healthcheck:\n test: [\"CMD-SHELL\", \"wget -qO- http://localhost:8080/health || exit 1\"]\n interval: 15s\n timeout: 5s\n retries: 5\n start_period: 20s\n volumes:\n - /var/run/docker.sock:/var/run/docker.sock\n - sandbox-data:/app/data/sandbox\n networks:\n - sentrix-net\n\nvolumes:\n pgdata:\n sandbox-data:\n\nnetworks:\n sentrix-net:\n driver: bridge\n"}}}}