From 274f7440e7422e5aa49a747d4ead1aa272900ffe Mon Sep 17 00:00:00 2001 From: LAIM69420 <290916066+LAIM69420@users.noreply.github.com> Date: Thu, 30 Jul 2026 11:22:22 +0700 Subject: [PATCH] restrict deploy command environment --- src/built/sandbox/deploy_runner.py | 4 +++- tests/integration/test_deploy_runner.py | 20 ++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/built/sandbox/deploy_runner.py b/src/built/sandbox/deploy_runner.py index fdf9718..12f8936 100644 --- a/src/built/sandbox/deploy_runner.py +++ b/src/built/sandbox/deploy_runner.py @@ -158,7 +158,9 @@ async def _run_deploy_command(deploy_config: DeployConfig, *, cwd) -> DeployRunR if not command: return DeployRunResult(success=False, message=f"no {deploy_config.kind.value} configured") - env = os.environ.copy() + # Keep ordinary command lookup working without exposing every secret held by + # the orchestrator process. Deploy credentials are opt-in via env_var_refs. + env = {"PATH": os.environ.get("PATH", os.defpath)} for ref in deploy_config.env_var_refs: if ref in os.environ: env[ref] = os.environ[ref] diff --git a/tests/integration/test_deploy_runner.py b/tests/integration/test_deploy_runner.py index 9a52e6c..dae1773 100644 --- a/tests/integration/test_deploy_runner.py +++ b/tests/integration/test_deploy_runner.py @@ -9,6 +9,7 @@ import httpx import pytest +from built.db.models import DeployConfig from built.domain.enums import DeployKind, DeployMode from built.sandbox import deploy_runner from built.sandbox.worktree import create_card_worktree, ensure_tool_worktree @@ -175,6 +176,25 @@ async def test_run_auto_main_deploy_deploy_command_failure(db_session, deployabl assert "exited 1" in result.message +async def test_deploy_command_exposes_only_explicit_environment_refs(monkeypatch, tmp_path): + monkeypatch.setenv("ALLOWED_DEPLOY_SECRET", "allowed") + monkeypatch.setenv("UNDECLARED_HOST_SECRET", "must-not-leak") + config = DeployConfig( + project_id="p", + kind=DeployKind.COMMAND, + mode=DeployMode.AUTO_MAIN, + command=( + 'test "$ALLOWED_DEPLOY_SECRET" = allowed ' + '&& test -z "${UNDECLARED_HOST_SECRET+x}"' + ), + env_var_refs=["ALLOWED_DEPLOY_SECRET"], + ) + + result = await deploy_runner._run_deploy_command(config, cwd=tmp_path) + + assert result.success is True, result.message + + async def test_run_auto_main_deploy_merge_conflict_reports_conflicted_paths( db_session, deployable_repo_remote ):