From 7a4e44a0363e4578ea635c2b7ec903fe8dfe916c Mon Sep 17 00:00:00 2001 From: Ambient Code Bot Date: Mon, 20 Apr 2026 12:26:59 -0400 Subject: [PATCH 1/2] feat(runner): add git safety guardrails to system prompt Inject concise git safety rules into the session system prompt when repos are configured. Covers force push, ref deletion, main branch protection, destructive operations, and token exposure. Replaces the over-engineered approach from #1225 (307-line regex module + 344-line test suite) with 15 lines of prompt text and 2 tests. Closes #1111 Co-Authored-By: Claude Opus 4.6 (1M context) --- .../ambient_runner/platform/prompts.py | 21 +++++++++++++ .../ambient-runner/tests/test_auto_push.py | 31 +++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/components/runners/ambient-runner/ambient_runner/platform/prompts.py b/components/runners/ambient-runner/ambient_runner/platform/prompts.py index d30d01031..08f8bd069 100644 --- a/components/runners/ambient-runner/ambient_runner/platform/prompts.py +++ b/components/runners/ambient-runner/ambient_runner/platform/prompts.py @@ -68,6 +68,24 @@ "the feature branch (`{branch}`). If push fails, do NOT fall back to main.\n\n" ) +GIT_SAFETY_INSTRUCTIONS = ( + "## Git Safety Guardrails\n\n" + "### Hard Rules\n\n" + "1. **NEVER delete remote branches or refs** — do NOT use " + "`git push --delete`, `git push origin :branch`, or " + "`gh api -X DELETE .../git/refs/...`.\n" + "2. **NEVER manipulate git refs via the GitHub/GitLab REST API** — if " + "`git push` fails, report the failure and stop.\n" + "3. **NEVER force push** — do not use `git push --force` or `-f`. " + "Use `--force-with-lease` only with explicit user approval.\n" + "4. **NEVER push to main/master** — treat them as read-only.\n" + "5. **NEVER run destructive operations without a backup** — before " + "`git reset --hard`, `git clean -fd`, or `git checkout -- .`, " + "create a backup branch first.\n" + "6. **NEVER embed tokens in commands** — use environment variables.\n\n" + "When a git operation fails: stop, diagnose, report, wait for the user.\n\n" +) + RUBRIC_EVALUATION_HEADER = "## Rubric Evaluation\n\n" RUBRIC_EVALUATION_INTRO = ( @@ -215,6 +233,9 @@ def build_workspace_context_prompt( prompt += f"- **repos/{repo_name}/**\n" prompt += GIT_PUSH_STEPS.format(branch=push_branch) + if repos_cfg: + prompt += GIT_SAFETY_INSTRUCTIONS + # Human-in-the-loop instructions prompt += HUMAN_INPUT_INSTRUCTIONS diff --git a/components/runners/ambient-runner/tests/test_auto_push.py b/components/runners/ambient-runner/tests/test_auto_push.py index 7ce0225e3..b5d8e9d99 100644 --- a/components/runners/ambient-runner/tests/test_auto_push.py +++ b/components/runners/ambient-runner/tests/test_auto_push.py @@ -317,6 +317,37 @@ def test_prompt_includes_multiple_autopush_repos(self): # repo3 should not be in git instructions since autoPush=false # (but it will be in the general repos list) + def test_prompt_includes_git_safety_with_repos(self): + """Git safety guardrails are included when repos are present.""" + repos_cfg = [ + { + "name": "my-repo", + "url": "https://github.com/owner/my-repo.git", + "branch": "main", + "autoPush": False, + } + ] + prompt = build_workspace_context_prompt( + repos_cfg=repos_cfg, + workflow_name=None, + artifacts_path="artifacts", + ambient_config={}, + workspace_path="/workspace", + ) + assert "Git Safety Guardrails" in prompt + assert "NEVER force push" in prompt + + def test_prompt_excludes_git_safety_without_repos(self): + """Git safety guardrails are excluded when no repos are present.""" + prompt = build_workspace_context_prompt( + repos_cfg=[], + workflow_name=None, + artifacts_path="artifacts", + ambient_config={}, + workspace_path="/workspace", + ) + assert "Git Safety Guardrails" not in prompt + def test_prompt_without_repos(self): """Test prompt generation when no repos are configured.""" prompt = build_workspace_context_prompt( From 33051326a94e93d911c10f326bad24443fddc976 Mon Sep 17 00:00:00 2001 From: Ambient Code Bot Date: Mon, 20 Apr 2026 13:17:29 -0400 Subject: [PATCH 2/2] fix: trim git safety to universal rules only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Keep only token redaction and escalation protocol — these are universally correct. Remove opinionated rules (force push policy, backup branches, ref deletion) that should be opt-in per-project. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../ambient_runner/platform/prompts.py | 21 ++++++------------- .../ambient-runner/tests/test_auto_push.py | 9 ++++---- 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/components/runners/ambient-runner/ambient_runner/platform/prompts.py b/components/runners/ambient-runner/ambient_runner/platform/prompts.py index 08f8bd069..2e30097b4 100644 --- a/components/runners/ambient-runner/ambient_runner/platform/prompts.py +++ b/components/runners/ambient-runner/ambient_runner/platform/prompts.py @@ -69,21 +69,12 @@ ) GIT_SAFETY_INSTRUCTIONS = ( - "## Git Safety Guardrails\n\n" - "### Hard Rules\n\n" - "1. **NEVER delete remote branches or refs** — do NOT use " - "`git push --delete`, `git push origin :branch`, or " - "`gh api -X DELETE .../git/refs/...`.\n" - "2. **NEVER manipulate git refs via the GitHub/GitLab REST API** — if " - "`git push` fails, report the failure and stop.\n" - "3. **NEVER force push** — do not use `git push --force` or `-f`. " - "Use `--force-with-lease` only with explicit user approval.\n" - "4. **NEVER push to main/master** — treat them as read-only.\n" - "5. **NEVER run destructive operations without a backup** — before " - "`git reset --hard`, `git clean -fd`, or `git checkout -- .`, " - "create a backup branch first.\n" - "6. **NEVER embed tokens in commands** — use environment variables.\n\n" - "When a git operation fails: stop, diagnose, report, wait for the user.\n\n" + "## Git Safety\n\n" + "**NEVER embed tokens or credentials in commands** — use environment " + "variables (`$GITHUB_TOKEN`, `$GITLAB_TOKEN`) instead of inline PATs.\n\n" + "**When a git operation fails**: stop, diagnose, report the error to the " + "user, and wait. Do NOT autonomously escalate to force pushes, API " + "workarounds, or more aggressive retry variants.\n\n" ) RUBRIC_EVALUATION_HEADER = "## Rubric Evaluation\n\n" diff --git a/components/runners/ambient-runner/tests/test_auto_push.py b/components/runners/ambient-runner/tests/test_auto_push.py index b5d8e9d99..744fab786 100644 --- a/components/runners/ambient-runner/tests/test_auto_push.py +++ b/components/runners/ambient-runner/tests/test_auto_push.py @@ -334,11 +334,12 @@ def test_prompt_includes_git_safety_with_repos(self): ambient_config={}, workspace_path="/workspace", ) - assert "Git Safety Guardrails" in prompt - assert "NEVER force push" in prompt + assert "Git Safety" in prompt + assert "NEVER embed tokens" in prompt + assert "Do NOT autonomously escalate" in prompt def test_prompt_excludes_git_safety_without_repos(self): - """Git safety guardrails are excluded when no repos are present.""" + """Git safety instructions are excluded when no repos are present.""" prompt = build_workspace_context_prompt( repos_cfg=[], workflow_name=None, @@ -346,7 +347,7 @@ def test_prompt_excludes_git_safety_without_repos(self): ambient_config={}, workspace_path="/workspace", ) - assert "Git Safety Guardrails" not in prompt + assert "Git Safety" not in prompt def test_prompt_without_repos(self): """Test prompt generation when no repos are configured."""