@evalops/maestro 0.10.49 → 0.10.50

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.
@@ -1 +1 @@
1
- {"version":3,"file":"load-env.js","sourceRoot":"","sources":["../src/load-env.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { config } from \"dotenv\";\nimport { ENV_VARS } from \"./config/env-vars.js\";\n\nconst ENV_FILES = [\".env.local\", \".env\"];\n\n// Keys that must never be sourced from a repo-controlled dotenv file. These are\n// stripped immediately at load time so they can never reach process.env.\nconst BLOCKED_DOTENV_KEYS = new Set([\n\t\"HOME\",\n\t\"FACTORY_HOME\",\n\t\"MAESTRO_HOME\",\n\t\"MAESTRO_CONFIG\",\n\t\"MAESTRO_PROFILE\",\n\t\"MAESTRO_LLM_GATEWAY_URL\",\n\t\"MAESTRO_MODELS_FILE\",\n\t\"MAESTRO_TRUST_PROJECT_MODEL_CONFIG\",\n\t\"USERPROFILE\",\n\t// Agent-directory overrides decide where the \"global\" APPEND_SYSTEM.md and\n\t// other agent-scoped files are loaded from. A repo-controlled value can\n\t// redirect that fallback back into the workspace, bypassing the\n\t// untrusted-project gate. See resolveLoadedAppendSystemPromptPath.\n\t\"MAESTRO_AGENT_DIR\",\n\t\"PLAYWRIGHT_AGENT_DIR\",\n\t\"CODING_AGENT_DIR\",\n]);\n\n// Security-relevant settings that may legitimately come from a user's real\n// shell environment but must not be silently set by a repo-controlled dotenv\n// file. These are loaded normally and then scrubbed via\n// scrubLoadedSecurityOverrideEnv() once trust has been established.\nconst DOTENV_SECURITY_OVERRIDE_KEYS = [\n\tENV_VARS.PROFILE,\n\t\"MAESTRO_WEB_PROFILE\",\n\tENV_VARS.APPROVAL_POLICY,\n\t\"MAESTRO_APPROVAL_MODE\",\n\tENV_VARS.SANDBOX_MODE,\n\tENV_VARS.SAFE_MODE,\n\t\"MAESTRO_SAFE_REQUIRE_PLAN\",\n\t\"MAESTRO_SAFE_VALIDATORS\",\n\tENV_VARS.CONTEXT_FIREWALL_BLOCKING,\n\t\"MAESTRO_HOME\",\n\t\"MAESTRO_AGENT_DIR\",\n\t\"PLAYWRIGHT_AGENT_DIR\",\n\t\"CODING_AGENT_DIR\",\n\t\"NODE_OPTIONS\",\n\t\"MAESTRO_CONFIG\",\n\t\"MAESTRO_MODELS_FILE\",\n\t\"MAESTRO_NOTIFY_EVENTS\",\n\t\"MAESTRO_NOTIFY_PROGRAM\",\n\t\"MAESTRO_ENTERPRISE_POLICY_PATH\",\n\t\"MAESTRO_POLICY_PATH\",\n\t\"MAESTRO_PROMPT_HISTORY_FILE\",\n\t\"MAESTRO_TOOL_HISTORY_FILE\",\n\t\"MAESTRO_TUI_TIP_HISTORY_FILE\",\n\t\"MAESTRO_BASH_HISTORY\",\n\t\"MAESTRO_PLATFORM_BASE_URL\",\n\t\"MAESTRO_EVALOPS_BASE_URL\",\n\t\"EVALOPS_BASE_URL\",\n\t// EvalOps identity service URL: `bootstrapEvalOpsAgent()` and the OAuth\n\t// flow honor these aliases before the stored/derived URL. A repo .env\n\t// could otherwise point identity at an attacker service and capture the\n\t// user's OAuth bearer during agent bootstrap.\n\t\"MAESTRO_IDENTITY_URL\",\n\t\"EVALOPS_IDENTITY_URL\",\n\t\"MAESTRO_EVALOPS_ACCESS_TOKEN\",\n\t\"EVALOPS_TOKEN\",\n\t// EvalOps tenant identity aliases: any of these can scope durable-memory\n\t// writes (`X-Organization-ID`), remote-runner workspace selection, and\n\t// managed-context lookups. A repo-controlled dotenv must not be able to\n\t// redirect those tenant identifiers when a real EvalOps token is present.\n\t\"MAESTRO_EVALOPS_ORG_ID\",\n\t\"EVALOPS_ORGANIZATION_ID\",\n\t\"EVALOPS_ORG_ID\",\n\t\"MAESTRO_ENTERPRISE_ORG_ID\",\n\t\"MAESTRO_EVALOPS_WORKSPACE_ID\",\n\t\"EVALOPS_WORKSPACE_ID\",\n\t\"MAESTRO_WORKSPACE_ID\",\n\t\"MAESTRO_REMOTE_RUNNER_WORKSPACE_ID\",\n\t\"MAESTRO_EVALOPS_USER_ID\",\n\t\"EVALOPS_USER_ID\",\n\t\"MAESTRO_USER_ID\",\n\t\"EVALOPS_NATS_URL\",\n\t\"NATS_URL\",\n\t\"NATS_TOKEN\",\n\t\"NATS_USER\",\n\t\"NATS_PASSWORD\",\n\t\"MAESTRO_WEB_REQUIRE_KEY\",\n\t\"MAESTRO_WEB_REQUIRE_CSRF\",\n\t\"MAESTRO_WEB_REQUIRE_REDIS\",\n\t\"MAESTRO_WEB_ROOT\",\n\t// CORS / WebSocket origin policy: a repo-controlled dotenv must not be\n\t// able to broaden cross-origin browser access to the local API by\n\t// setting `MAESTRO_WEB_ORIGIN=*` (or an attacker-controlled origin)\n\t// before the user's real env is checked.\n\t\"MAESTRO_WEB_ORIGIN\",\n\t// Content-Security-Policy override: web-server.ts prefers a non-empty\n\t// MAESTRO_WEB_CSP over the prod default when building SECURITY_HEADERS,\n\t// so a repo .env could otherwise weaken the browser policy in any\n\t// hardened profile.\n\t\"MAESTRO_WEB_CSP\",\n\t\"MAESTRO_STRICT_SESSION_ACCESS\",\n\t// Session scoping controls: a repo-controlled dotenv must not be able to\n\t// collapse authenticated web sessions back to the global file store.\n\tENV_VARS.SESSION_SCOPE,\n\tENV_VARS.MULTI_USER,\n\t\"MAESTRO_REDIS_URL\",\n\t\"MAESTRO_DATABASE_URL\",\n\t\"DATABASE_URL\",\n\t\"MAESTRO_HOSTED_SESSION_STORAGE\",\n\t\"MAESTRO_SESSION_STORAGE\",\n\t\"MAESTRO_TRUST_PROXY\",\n\t\"MAESTRO_TRUST_PROXY_HOPS\",\n\t// Web/auth secret material: a repo-controlled dotenv must not be able to\n\t// choose a known API key, CSRF token, JWT signing secret, or shared secret\n\t// for endpoints that are supposed to require a user-provided credential.\n\t\"MAESTRO_WEB_API_KEY\",\n\t\"MAESTRO_WEB_CSRF_TOKEN\",\n\t\"MAESTRO_JWT_SECRET\",\n\t// `JWT_SECRET` is the unprefixed fallback honored by src/auth/jwt.ts when\n\t// `MAESTRO_JWT_SECRET` is not set; a repo-controlled dotenv must not be\n\t// able to choose the signing key for enterprise auth via this fallback.\n\t\"JWT_SECRET\",\n\t// OAuth credential file overrides: `src/providers/openai-auth.ts:91`\n\t// binds AUTH_FILE to OPENAI_OAUTH_FILE, and `saveOpenAIOAuthCredential()`\n\t// then writes access/refresh/ID tokens and the derived API key to that\n\t// path. A repo .env must not be able to redirect fresh OAuth credentials\n\t// into the checkout where they can be read on the next install.\n\t\"OPENAI_OAUTH_FILE\",\n\t\"MAESTRO_AUTH_SHARED_SECRET\",\n\t\"MAESTRO_DEVICE_IDENTITY_HELPER\",\n\t\"MAESTRO_DEVICE_IDENTITY_ALLOW_TEST_HELPER\",\n\t\"MAESTRO_USER_MCP_PATH\",\n\t\"MAESTRO_ENTERPRISE_MCP_PATH\",\n\t\"MAESTRO_MCP_PROJECT_APPROVALS_FILE\",\n\t\"MAESTRO_MCP_WORKSPACE_TRUST_FILE\",\n\t\"MAESTRO_PACKAGE_CACHE_DIR\",\n\t\"MAESTRO_RUN_SCRIPT_ALLOWLIST\",\n\t\"MAESTRO_SCRIPT_RUNNER\",\n\t// Session storage location: a repo-controlled dotenv must not be able to\n\t// redirect where session transcripts are read from or written to.\n\tENV_VARS.SESSION_DIR,\n\t// Local-state file/dir overrides: a repo-controlled dotenv must not be\n\t// able to redirect where the todo store or background-task logs are\n\t// written, which would otherwise let a checkout capture future task\n\t// content or command output for files that live outside the workspace\n\t// by default. Same reasoning extends to the web queue store and\n\t// automations store, which write user prompt/output text to env-selected\n\t// paths.\n\t\"MAESTRO_TODO_FILE\",\n\t\"MAESTRO_BACKGROUND_LOG_DIR\",\n\t\"MAESTRO_QUEUE_STATE\",\n\t\"MAESTRO_AUTOMATIONS_STATE\",\n\t// Sandbox enforcement opt-out: a repo-controlled dotenv must not be able to\n\t// enable unsandboxed fallback execution.\n\t\"MAESTRO_ALLOW_UNSANDBOXED_SANDBOX_FALLBACK\",\n\t// Bash guard / shell egress / allowlist controls: a repo-controlled dotenv\n\t// must not be able to disable command approvals or widen the allowlist.\n\t\"MAESTRO_BASH_GUARD\",\n\t\"MAESTRO_ALLOW_EGRESS_SHELL\",\n\t\"MAESTRO_FAIL_UNTAGGED_EGRESS\",\n\t\"MAESTRO_BACKGROUND_SHELL_DISABLE\",\n\t\"MAESTRO_BASH_ALLOWLIST_PATHS\",\n\t\"MAESTRO_GUARDIAN\",\n\t\"MAESTRO_MARKITDOWN\",\n\t\"MAESTRO_EVENT_BUS\",\n\t\"MAESTRO_AUDIT_BUS\",\n\t\"MAESTRO_TELEMETRY\",\n\t\"PLAYWRIGHT_TELEMETRY\",\n\t\"MAESTRO_OTEL\",\n\t// Auto-verify custom command: a repo-controlled dotenv must not be able to\n\t// inject an arbitrary shell command that AutoVerifyService runs after edits.\n\t\"MAESTRO_AUTO_TEST_COMMAND\",\n] as const;\n\nconst normalizeEnvKey = (key: string) => key.toUpperCase();\nconst DOTENV_SECURITY_OVERRIDE_KEY_SET = new Set<string>(\n\tDOTENV_SECURITY_OVERRIDE_KEYS.map(normalizeEnvKey),\n);\nconst DOTENV_SECURITY_OVERRIDE_PREFIXES = [\n\t\"APPROVALS_SERVICE_\",\n\t\"MAESTRO_ARTIFACT_ACCESS_\",\n\t\"MAESTRO_APPROVALS_\",\n\t\"MAESTRO_AGENT_MCP_\",\n\t\"MAESTRO_BEACON_\",\n\t\"MAESTRO_CEREBRO_MCP_\",\n\t\"MAESTRO_EVENT_BUS_\",\n\t\"MAESTRO_EVALOPS_AGENT_MCP_\",\n\t\"GOVERNANCE_SERVICE_\",\n\t\"MAESTRO_GOVERNANCE_\",\n\t// Internal service clients must not accept repo-selected endpoints while\n\t// falling back to user-provided bearer tokens or tenant headers.\n\t\"PIPELINE_\",\n\t\"MAESTRO_AGENT_REGISTRY_\",\n\t\"AGENT_REGISTRY_\",\n\t\"PLATFORM_AGENT_REGISTRY_\",\n\t\"MAESTRO_PLATFORM_A2A_\",\n\t\"MAESTRO_A2A_\",\n\t\"MAESTRO_AGENT_RUNTIME_\",\n\t\"AGENT_RUNTIME_\",\n\t\"PLATFORM_AGENT_RUNTIME_\",\n\t// Platform tool-execution bridge: a repo .env must not be able to point\n\t// the Connect endpoint, auth token, or tenant identifiers at an\n\t// attacker-controlled service, or bash/MCP tool args and observation\n\t// output get posted there with the user's real credentials.\n\t\"TOOL_EXECUTION_SERVICE_\",\n\t\"MAESTRO_TOOL_EXECUTION_\",\n\t\"MAESTRO_GUARDIAN_\",\n\t\"MAESTRO_HISTORY_\",\n\t\"MAESTRO_HOOKS_\",\n\t\"MAESTRO_JWT_\",\n\t\"MAESTRO_MARKITDOWN_\",\n\t\"MAESTRO_MEMORY_\",\n\t\"MAESTRO_OTEL_\",\n\t// Web rate-limit controls: `session-rate-limit.ts` and\n\t// `session-share-store.ts` read these at module load when web-server.ts\n\t// imports its handlers. A repo .env could otherwise weaken per-session\n\t// or share rate limits even in a hardened web profile.\n\t\"MAESTRO_RATE_LIMIT_\",\n\t\"MAESTRO_SHARE_RATE_LIMIT_\",\n\t\"MAESTRO_PLATFORM_MCP_\",\n\t// Prompt-service controls: these can redirect system prompt resolution and\n\t// credential-bearing service calls to a repo-selected endpoint.\n\t\"PROMPTS_SERVICE_\",\n\t\"MAESTRO_PROMPTS_\",\n\t\"MAESTRO_SAFE_\",\n\t\"MAESTRO_SCENARIO_\",\n\t\"MAESTRO_SESSION_BACKUP_\",\n\t\"MAESTRO_SESSION_RECOVERY_\",\n\t\"MAESTRO_SHARED_MEMORY_\",\n\t\"MAESTRO_TELEMETRY_\",\n\t\"OTEL_\",\n\t\"PLAYWRIGHT_TELEMETRY_\",\n\t\"SENTRY_\",\n] as const;\nconst isDotenvSecurityOverrideKey = (key: string): boolean => {\n\tconst normalizedKey = normalizeEnvKey(key);\n\treturn (\n\t\tDOTENV_SECURITY_OVERRIDE_KEY_SET.has(normalizedKey) ||\n\t\tDOTENV_SECURITY_OVERRIDE_PREFIXES.some((prefix) =>\n\t\t\tnormalizedKey.startsWith(prefix),\n\t\t)\n\t);\n};\nconst loadedEnvKeys = new Set<string>();\n\nexport function loadEnv(): string[] {\n\tconst newlyLoadedKeys = new Set<string>();\n\tfor (const file of ENV_FILES) {\n\t\tconst resolved = join(process.cwd(), file);\n\t\tif (existsSync(resolved)) {\n\t\t\tconst before = new Set(Object.keys(process.env));\n\t\t\tconst beforeNormalized = new Set([...before].map(normalizeEnvKey));\n\t\t\tconst result = config({ path: resolved, override: false });\n\t\t\tconst after = new Set(Object.keys(process.env));\n\t\t\tfor (const key of Object.keys(result.parsed ?? {})) {\n\t\t\t\tconst normalizedKey = normalizeEnvKey(key);\n\t\t\t\tconst wasLoadedByDotenv = !before.has(key) && after.has(key);\n\t\t\t\tif (!wasLoadedByDotenv) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (BLOCKED_DOTENV_KEYS.has(normalizedKey)) {\n\t\t\t\t\tReflect.deleteProperty(process.env, key);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t// Track newly loaded keys so they can be scrubbed later. For\n\t\t\t\t// security override keys we record the exact dotenv-loaded key even\n\t\t\t\t// when a differently cased variant already existed in the real\n\t\t\t\t// environment: env names are case-sensitive on POSIX, so dotenv can\n\t\t\t\t// create a distinct uppercase `MAESTRO_PROFILE` alongside a user's\n\t\t\t\t// `maestro_profile`, and that repo-controlled value must still be\n\t\t\t\t// scrubbed rather than survive due to the normalized collision.\n\t\t\t\tif (\n\t\t\t\t\t!beforeNormalized.has(normalizedKey) ||\n\t\t\t\t\tisDotenvSecurityOverrideKey(normalizedKey)\n\t\t\t\t) {\n\t\t\t\t\tnewlyLoadedKeys.add(key);\n\t\t\t\t\tloadedEnvKeys.add(key);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn [...newlyLoadedKeys];\n}\n\nexport function getLoadedEnvKeys(): string[] {\n\treturn [...loadedEnvKeys];\n}\n\nexport function scrubLoadedSecurityOverrideEnv(): string[] {\n\tconst scrubbed: string[] = [];\n\tfor (const key of DOTENV_SECURITY_OVERRIDE_KEYS) {\n\t\tconst matchingLoadedKeys = [...loadedEnvKeys].filter(\n\t\t\t(loadedKey) => normalizeEnvKey(loadedKey) === normalizeEnvKey(key),\n\t\t);\n\t\tif (matchingLoadedKeys.length === 0) {\n\t\t\tcontinue;\n\t\t}\n\t\tfor (const loadedKey of matchingLoadedKeys) {\n\t\t\tReflect.deleteProperty(process.env, loadedKey);\n\t\t\tloadedEnvKeys.delete(loadedKey);\n\t\t\tscrubbed.push(loadedKey);\n\t\t}\n\t}\n\tfor (const loadedKey of [...loadedEnvKeys]) {\n\t\tif (!isDotenvSecurityOverrideKey(loadedKey)) {\n\t\t\tcontinue;\n\t\t}\n\t\tReflect.deleteProperty(process.env, loadedKey);\n\t\tloadedEnvKeys.delete(loadedKey);\n\t\tscrubbed.push(loadedKey);\n\t}\n\treturn scrubbed;\n}\n"]}
1
+ {"version":3,"file":"load-env.js","sourceRoot":"","sources":["../src/load-env.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { config } from \"dotenv\";\nimport { ENV_VARS } from \"./config/env-vars.js\";\nimport { resetDefaultRuntimeEnv } from \"./runtime/env.js\";\n\nconst ENV_FILES = [\".env.local\", \".env\"];\n\n// Keys that must never be sourced from a repo-controlled dotenv file. These are\n// stripped immediately at load time so they can never reach process.env.\nconst BLOCKED_DOTENV_KEYS = new Set([\n\t\"HOME\",\n\t\"FACTORY_HOME\",\n\t\"MAESTRO_HOME\",\n\t\"MAESTRO_CONFIG\",\n\t\"MAESTRO_PROFILE\",\n\t\"MAESTRO_LLM_GATEWAY_URL\",\n\t\"MAESTRO_MODELS_FILE\",\n\t\"MAESTRO_TRUST_PROJECT_MODEL_CONFIG\",\n\t\"USERPROFILE\",\n\t// Agent-directory overrides decide where the \"global\" APPEND_SYSTEM.md and\n\t// other agent-scoped files are loaded from. A repo-controlled value can\n\t// redirect that fallback back into the workspace, bypassing the\n\t// untrusted-project gate. See resolveLoadedAppendSystemPromptPath.\n\t\"MAESTRO_AGENT_DIR\",\n\t\"PLAYWRIGHT_AGENT_DIR\",\n\t\"CODING_AGENT_DIR\",\n]);\n\n// Security-relevant settings that may legitimately come from a user's real\n// shell environment but must not be silently set by a repo-controlled dotenv\n// file. These are loaded normally and then scrubbed via\n// scrubLoadedSecurityOverrideEnv() once trust has been established.\nconst DOTENV_SECURITY_OVERRIDE_KEYS = [\n\tENV_VARS.PROFILE,\n\t\"MAESTRO_WEB_PROFILE\",\n\tENV_VARS.APPROVAL_POLICY,\n\t\"MAESTRO_APPROVAL_MODE\",\n\tENV_VARS.SANDBOX_MODE,\n\tENV_VARS.SAFE_MODE,\n\t\"MAESTRO_SAFE_REQUIRE_PLAN\",\n\t\"MAESTRO_SAFE_VALIDATORS\",\n\tENV_VARS.CONTEXT_FIREWALL_BLOCKING,\n\t\"MAESTRO_HOME\",\n\t\"MAESTRO_AGENT_DIR\",\n\t\"PLAYWRIGHT_AGENT_DIR\",\n\t\"CODING_AGENT_DIR\",\n\t\"NODE_OPTIONS\",\n\t\"MAESTRO_CONFIG\",\n\t\"MAESTRO_MODELS_FILE\",\n\t\"MAESTRO_NOTIFY_EVENTS\",\n\t\"MAESTRO_NOTIFY_PROGRAM\",\n\t\"MAESTRO_ENTERPRISE_POLICY_PATH\",\n\t\"MAESTRO_POLICY_PATH\",\n\t\"MAESTRO_PROMPT_HISTORY_FILE\",\n\t\"MAESTRO_TOOL_HISTORY_FILE\",\n\t\"MAESTRO_TUI_TIP_HISTORY_FILE\",\n\t\"MAESTRO_BASH_HISTORY\",\n\t\"MAESTRO_PLATFORM_BASE_URL\",\n\t\"MAESTRO_EVALOPS_BASE_URL\",\n\t\"EVALOPS_BASE_URL\",\n\t// EvalOps identity service URL: `bootstrapEvalOpsAgent()` and the OAuth\n\t// flow honor these aliases before the stored/derived URL. A repo .env\n\t// could otherwise point identity at an attacker service and capture the\n\t// user's OAuth bearer during agent bootstrap.\n\t\"MAESTRO_IDENTITY_URL\",\n\t\"EVALOPS_IDENTITY_URL\",\n\t\"MAESTRO_EVALOPS_ACCESS_TOKEN\",\n\t\"EVALOPS_TOKEN\",\n\t// EvalOps tenant identity aliases: any of these can scope durable-memory\n\t// writes (`X-Organization-ID`), remote-runner workspace selection, and\n\t// managed-context lookups. A repo-controlled dotenv must not be able to\n\t// redirect those tenant identifiers when a real EvalOps token is present.\n\t\"MAESTRO_EVALOPS_ORG_ID\",\n\t\"EVALOPS_ORGANIZATION_ID\",\n\t\"EVALOPS_ORG_ID\",\n\t\"MAESTRO_ENTERPRISE_ORG_ID\",\n\t\"MAESTRO_EVALOPS_WORKSPACE_ID\",\n\t\"EVALOPS_WORKSPACE_ID\",\n\t\"MAESTRO_WORKSPACE_ID\",\n\t\"MAESTRO_REMOTE_RUNNER_WORKSPACE_ID\",\n\t\"MAESTRO_EVALOPS_USER_ID\",\n\t\"EVALOPS_USER_ID\",\n\t\"MAESTRO_USER_ID\",\n\t\"EVALOPS_NATS_URL\",\n\t\"NATS_URL\",\n\t\"NATS_TOKEN\",\n\t\"NATS_USER\",\n\t\"NATS_PASSWORD\",\n\t\"MAESTRO_WEB_REQUIRE_KEY\",\n\t\"MAESTRO_WEB_REQUIRE_CSRF\",\n\t\"MAESTRO_WEB_REQUIRE_REDIS\",\n\t\"MAESTRO_WEB_ROOT\",\n\t// CORS / WebSocket origin policy: a repo-controlled dotenv must not be\n\t// able to broaden cross-origin browser access to the local API by\n\t// setting `MAESTRO_WEB_ORIGIN=*` (or an attacker-controlled origin)\n\t// before the user's real env is checked.\n\t\"MAESTRO_WEB_ORIGIN\",\n\t// Content-Security-Policy override: web-server.ts prefers a non-empty\n\t// MAESTRO_WEB_CSP over the prod default when building SECURITY_HEADERS,\n\t// so a repo .env could otherwise weaken the browser policy in any\n\t// hardened profile.\n\t\"MAESTRO_WEB_CSP\",\n\t\"MAESTRO_STRICT_SESSION_ACCESS\",\n\t// Session scoping controls: a repo-controlled dotenv must not be able to\n\t// collapse authenticated web sessions back to the global file store.\n\tENV_VARS.SESSION_SCOPE,\n\tENV_VARS.MULTI_USER,\n\t\"MAESTRO_REDIS_URL\",\n\t\"MAESTRO_DATABASE_URL\",\n\t\"DATABASE_URL\",\n\t\"MAESTRO_HOSTED_SESSION_STORAGE\",\n\t\"MAESTRO_SESSION_STORAGE\",\n\t\"MAESTRO_TRUST_PROXY\",\n\t\"MAESTRO_TRUST_PROXY_HOPS\",\n\t// Web/auth secret material: a repo-controlled dotenv must not be able to\n\t// choose a known API key, CSRF token, JWT signing secret, or shared secret\n\t// for endpoints that are supposed to require a user-provided credential.\n\t\"MAESTRO_WEB_API_KEY\",\n\t\"MAESTRO_WEB_CSRF_TOKEN\",\n\t\"MAESTRO_JWT_SECRET\",\n\t// `JWT_SECRET` is the unprefixed fallback honored by src/auth/jwt.ts when\n\t// `MAESTRO_JWT_SECRET` is not set; a repo-controlled dotenv must not be\n\t// able to choose the signing key for enterprise auth via this fallback.\n\t\"JWT_SECRET\",\n\t// OAuth credential file overrides: `src/providers/openai-auth.ts:91`\n\t// binds AUTH_FILE to OPENAI_OAUTH_FILE, and `saveOpenAIOAuthCredential()`\n\t// then writes access/refresh/ID tokens and the derived API key to that\n\t// path. A repo .env must not be able to redirect fresh OAuth credentials\n\t// into the checkout where they can be read on the next install.\n\t\"OPENAI_OAUTH_FILE\",\n\t\"MAESTRO_AUTH_SHARED_SECRET\",\n\t\"MAESTRO_DEVICE_IDENTITY_HELPER\",\n\t\"MAESTRO_DEVICE_IDENTITY_ALLOW_TEST_HELPER\",\n\t\"MAESTRO_USER_MCP_PATH\",\n\t\"MAESTRO_ENTERPRISE_MCP_PATH\",\n\t\"MAESTRO_MCP_PROJECT_APPROVALS_FILE\",\n\t\"MAESTRO_MCP_WORKSPACE_TRUST_FILE\",\n\t\"MAESTRO_PACKAGE_CACHE_DIR\",\n\t\"MAESTRO_RUN_SCRIPT_ALLOWLIST\",\n\t\"MAESTRO_SCRIPT_RUNNER\",\n\t// Session storage location: a repo-controlled dotenv must not be able to\n\t// redirect where session transcripts are read from or written to.\n\tENV_VARS.SESSION_DIR,\n\t// Local-state file/dir overrides: a repo-controlled dotenv must not be\n\t// able to redirect where the todo store or background-task logs are\n\t// written, which would otherwise let a checkout capture future task\n\t// content or command output for files that live outside the workspace\n\t// by default. Same reasoning extends to the web queue store and\n\t// automations store, which write user prompt/output text to env-selected\n\t// paths.\n\t\"MAESTRO_TODO_FILE\",\n\t\"MAESTRO_BACKGROUND_LOG_DIR\",\n\t\"MAESTRO_QUEUE_STATE\",\n\t\"MAESTRO_AUTOMATIONS_STATE\",\n\t// Sandbox enforcement opt-out: a repo-controlled dotenv must not be able to\n\t// enable unsandboxed fallback execution.\n\t\"MAESTRO_ALLOW_UNSANDBOXED_SANDBOX_FALLBACK\",\n\t// Bash guard / shell egress / allowlist controls: a repo-controlled dotenv\n\t// must not be able to disable command approvals or widen the allowlist.\n\t\"MAESTRO_BASH_GUARD\",\n\t\"MAESTRO_ALLOW_EGRESS_SHELL\",\n\t\"MAESTRO_FAIL_UNTAGGED_EGRESS\",\n\t\"MAESTRO_BACKGROUND_SHELL_DISABLE\",\n\t\"MAESTRO_BASH_ALLOWLIST_PATHS\",\n\t\"MAESTRO_GUARDIAN\",\n\t\"MAESTRO_MARKITDOWN\",\n\t\"MAESTRO_EVENT_BUS\",\n\t\"MAESTRO_AUDIT_BUS\",\n\t\"MAESTRO_TELEMETRY\",\n\t\"PLAYWRIGHT_TELEMETRY\",\n\t\"MAESTRO_OTEL\",\n\t// Auto-verify custom command: a repo-controlled dotenv must not be able to\n\t// inject an arbitrary shell command that AutoVerifyService runs after edits.\n\t\"MAESTRO_AUTO_TEST_COMMAND\",\n] as const;\n\nconst normalizeEnvKey = (key: string) => key.toUpperCase();\nconst DOTENV_SECURITY_OVERRIDE_KEY_SET = new Set<string>(\n\tDOTENV_SECURITY_OVERRIDE_KEYS.map(normalizeEnvKey),\n);\nconst DOTENV_SECURITY_OVERRIDE_PREFIXES = [\n\t\"APPROVALS_SERVICE_\",\n\t\"MAESTRO_ARTIFACT_ACCESS_\",\n\t\"MAESTRO_APPROVALS_\",\n\t\"MAESTRO_AGENT_MCP_\",\n\t\"MAESTRO_BEACON_\",\n\t\"MAESTRO_CEREBRO_MCP_\",\n\t\"MAESTRO_EVENT_BUS_\",\n\t\"MAESTRO_EVALOPS_AGENT_MCP_\",\n\t\"GOVERNANCE_SERVICE_\",\n\t\"MAESTRO_GOVERNANCE_\",\n\t// Internal service clients must not accept repo-selected endpoints while\n\t// falling back to user-provided bearer tokens or tenant headers.\n\t\"PIPELINE_\",\n\t\"MAESTRO_AGENT_REGISTRY_\",\n\t\"AGENT_REGISTRY_\",\n\t\"PLATFORM_AGENT_REGISTRY_\",\n\t\"MAESTRO_PLATFORM_A2A_\",\n\t\"MAESTRO_A2A_\",\n\t\"MAESTRO_AGENT_RUNTIME_\",\n\t\"AGENT_RUNTIME_\",\n\t\"PLATFORM_AGENT_RUNTIME_\",\n\t// Platform tool-execution bridge: a repo .env must not be able to point\n\t// the Connect endpoint, auth token, or tenant identifiers at an\n\t// attacker-controlled service, or bash/MCP tool args and observation\n\t// output get posted there with the user's real credentials.\n\t\"TOOL_EXECUTION_SERVICE_\",\n\t\"MAESTRO_TOOL_EXECUTION_\",\n\t\"MAESTRO_GUARDIAN_\",\n\t\"MAESTRO_HISTORY_\",\n\t\"MAESTRO_HOOKS_\",\n\t\"MAESTRO_JWT_\",\n\t\"MAESTRO_MARKITDOWN_\",\n\t\"MAESTRO_MEMORY_\",\n\t\"MAESTRO_OTEL_\",\n\t// Web rate-limit controls: `session-rate-limit.ts` and\n\t// `session-share-store.ts` read these at module load when web-server.ts\n\t// imports its handlers. A repo .env could otherwise weaken per-session\n\t// or share rate limits even in a hardened web profile.\n\t\"MAESTRO_RATE_LIMIT_\",\n\t\"MAESTRO_SHARE_RATE_LIMIT_\",\n\t\"MAESTRO_PLATFORM_MCP_\",\n\t// Prompt-service controls: these can redirect system prompt resolution and\n\t// credential-bearing service calls to a repo-selected endpoint.\n\t\"PROMPTS_SERVICE_\",\n\t\"MAESTRO_PROMPTS_\",\n\t\"MAESTRO_SAFE_\",\n\t\"MAESTRO_SCENARIO_\",\n\t\"MAESTRO_SESSION_BACKUP_\",\n\t\"MAESTRO_SESSION_RECOVERY_\",\n\t\"MAESTRO_SHARED_MEMORY_\",\n\t\"MAESTRO_TELEMETRY_\",\n\t\"OTEL_\",\n\t\"PLAYWRIGHT_TELEMETRY_\",\n\t\"SENTRY_\",\n] as const;\nconst isDotenvSecurityOverrideKey = (key: string): boolean => {\n\tconst normalizedKey = normalizeEnvKey(key);\n\treturn (\n\t\tDOTENV_SECURITY_OVERRIDE_KEY_SET.has(normalizedKey) ||\n\t\tDOTENV_SECURITY_OVERRIDE_PREFIXES.some((prefix) =>\n\t\t\tnormalizedKey.startsWith(prefix),\n\t\t)\n\t);\n};\nconst loadedEnvKeys = new Set<string>();\n\nexport function loadEnv(): string[] {\n\tconst newlyLoadedKeys = new Set<string>();\n\tfor (const file of ENV_FILES) {\n\t\tconst resolved = join(process.cwd(), file);\n\t\tif (existsSync(resolved)) {\n\t\t\tconst before = new Set(Object.keys(process.env));\n\t\t\tconst beforeNormalized = new Set([...before].map(normalizeEnvKey));\n\t\t\tconst result = config({ path: resolved, override: false });\n\t\t\tconst after = new Set(Object.keys(process.env));\n\t\t\tfor (const key of Object.keys(result.parsed ?? {})) {\n\t\t\t\tconst normalizedKey = normalizeEnvKey(key);\n\t\t\t\tconst wasLoadedByDotenv = !before.has(key) && after.has(key);\n\t\t\t\tif (!wasLoadedByDotenv) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (BLOCKED_DOTENV_KEYS.has(normalizedKey)) {\n\t\t\t\t\tReflect.deleteProperty(process.env, key);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t// Track newly loaded keys so they can be scrubbed later. For\n\t\t\t\t// security override keys we record the exact dotenv-loaded key even\n\t\t\t\t// when a differently cased variant already existed in the real\n\t\t\t\t// environment: env names are case-sensitive on POSIX, so dotenv can\n\t\t\t\t// create a distinct uppercase `MAESTRO_PROFILE` alongside a user's\n\t\t\t\t// `maestro_profile`, and that repo-controlled value must still be\n\t\t\t\t// scrubbed rather than survive due to the normalized collision.\n\t\t\t\tif (\n\t\t\t\t\t!beforeNormalized.has(normalizedKey) ||\n\t\t\t\t\tisDotenvSecurityOverrideKey(normalizedKey)\n\t\t\t\t) {\n\t\t\t\t\tnewlyLoadedKeys.add(key);\n\t\t\t\t\tloadedEnvKeys.add(key);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn [...newlyLoadedKeys];\n}\n\nexport function getLoadedEnvKeys(): string[] {\n\treturn [...loadedEnvKeys];\n}\n\nexport function scrubLoadedSecurityOverrideEnv(): string[] {\n\tconst scrubbed: string[] = [];\n\tfor (const key of DOTENV_SECURITY_OVERRIDE_KEYS) {\n\t\tconst matchingLoadedKeys = [...loadedEnvKeys].filter(\n\t\t\t(loadedKey) => normalizeEnvKey(loadedKey) === normalizeEnvKey(key),\n\t\t);\n\t\tif (matchingLoadedKeys.length === 0) {\n\t\t\tcontinue;\n\t\t}\n\t\tfor (const loadedKey of matchingLoadedKeys) {\n\t\t\tReflect.deleteProperty(process.env, loadedKey);\n\t\t\tloadedEnvKeys.delete(loadedKey);\n\t\t\tscrubbed.push(loadedKey);\n\t\t}\n\t}\n\tfor (const loadedKey of [...loadedEnvKeys]) {\n\t\tif (!isDotenvSecurityOverrideKey(loadedKey)) {\n\t\t\tcontinue;\n\t\t}\n\t\tReflect.deleteProperty(process.env, loadedKey);\n\t\tloadedEnvKeys.delete(loadedKey);\n\t\tscrubbed.push(loadedKey);\n\t}\n\treturn scrubbed;\n}\n\nexport interface FinalizedEnvLoad {\n\tloadedEnvKeys: string[];\n\tscrubbedEnvKeys: string[];\n}\n\n/**\n * Finish dotenv bootstrap after any trust-sensitive keys have been loaded.\n *\n * The order is load -> scrub -> reset RuntimeEnv. Resetting before the scrub\n * can preserve repo-controlled security overrides in the cached runtime\n * snapshot, which is exactly the bug class closed by the OTel follow-up.\n */\nexport function finalizeLoadedEnv(\n\tloadedEnvKeys: string[] = [],\n): FinalizedEnvLoad {\n\tconst scrubbedEnvKeys = scrubLoadedSecurityOverrideEnv();\n\tresetDefaultRuntimeEnv();\n\treturn { loadedEnvKeys, scrubbedEnvKeys };\n}\n\nexport function loadAndFinalizeEnv(): FinalizedEnvLoad {\n\treturn finalizeLoadedEnv(loadEnv());\n}\n"]}
package/dist/main.js CHANGED
@@ -98,7 +98,7 @@ import { printHelp } from "./cli/help.js";
98
98
  import { detectRuntimeConstraintContext } from "./cli/system-prompt.js";
99
99
  import { validateFrameworkPreference } from "./config/framework.js";
100
100
  import { buildCliConfigOverrides, loadRuntimeConfig, } from "./config/runtime-config.js";
101
- import { loadEnv, scrubLoadedSecurityOverrideEnv } from "./load-env.js";
101
+ import { loadAndFinalizeEnv } from "./load-env.js";
102
102
  import { bootstrapLsp } from "./lsp/bootstrap.js";
103
103
  import { createLazyAutoMemoryCoordinators } from "./memory/lazy-auto-memory.js";
104
104
  import { ensureModelsLoaded } from "./models/builtin.js";
@@ -460,13 +460,13 @@ export async function main(args) {
460
460
  // ─────────────────────────────────────────────────────────────────────────────
461
461
  // PHASE 0: Early Exit Checks (before any async initialization)
462
462
  // ─────────────────────────────────────────────────────────────────────────────
463
- // Load environment variables from .env files (project and user level)
464
- loadEnv();
463
+ // Load environment variables from .env files (project and user level),
464
+ // scrub repo-controlled security overrides, then refresh RuntimeEnv.
465
+ loadAndFinalizeEnv();
465
466
  const startupProfiler = createStartupProfilerFromEnv();
466
467
  startupProfiler.checkpoint("process:start");
467
468
  // Parse arguments early to check for version/help flags before heavy initialization
468
469
  const parsed = parseArgs(args);
469
- scrubLoadedSecurityOverrideEnv();
470
470
  startupProfiler.checkpoint("cli:parsed");
471
471
  const startupTelemetry = import("./telemetry/cli-startup.js")
472
472
  .then(({ recordCliStartupTelemetry }) => recordCliStartupTelemetry({