Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,15 @@
"the feature branch (`{branch}`). If push fails, do NOT fall back to main.\n\n"
)

GIT_SAFETY_INSTRUCTIONS = (
"## 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"

RUBRIC_EVALUATION_INTRO = (
Expand Down Expand Up @@ -215,6 +224,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

Expand Down
32 changes: 32 additions & 0 deletions components/runners/ambient-runner/tests/test_auto_push.py
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,38 @@ 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" 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 instructions 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" not in prompt

Comment on lines +320 to +351
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Strengthen guardrail assertions to cover all safety-critical rules

Line 337 and Line 338 only lock one rule (NEVER force push). This can miss regressions in ref-deletion/API-ref/token/main-branch protections while tests still pass.

Suggested test hardening
     def test_prompt_includes_git_safety_with_repos(self):
         """Git safety guardrails are included when repos are present."""
@@
         assert "Git Safety Guardrails" in prompt
         assert "NEVER force push" in prompt
+        assert "NEVER delete remote branches or refs" in prompt
+        assert "NEVER manipulate git refs via the GitHub/GitLab REST API" in prompt
+        assert "NEVER push to main/master" in prompt
+        assert "NEVER run destructive operations without a backup" in prompt
+        assert "NEVER embed tokens in commands" in prompt
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/runners/ambient-runner/tests/test_auto_push.py` around lines 320 -
350, The test only asserts the presence of a single safety phrase ("NEVER force
push") in test_prompt_includes_git_safety_with_repos, which lets other
guardrails regress unnoticed; update the tests that call
build_workspace_context_prompt (e.g., test_prompt_includes_git_safety_with_repos
and test_prompt_excludes_git_safety_without_repos) to assert all expected
safety-critical phrases are present when repos_cfg is non-empty (examples:
"NEVER force push", "DO NOT delete refs", "DO NOT expose API keys", "RESTRICT
tokens", "PROTECT main branch" or whatever exact phrases
build_workspace_context_prompt emits) and assert none of those phrases appear
when repos_cfg is empty; locate the checks by referencing
build_workspace_context_prompt and the two test functions and add multiple
explicit assertions covering each guardrail phrase rather than relying on a
single substring.

def test_prompt_without_repos(self):
"""Test prompt generation when no repos are configured."""
prompt = build_workspace_context_prompt(
Expand Down