Skip to content

Commit a089bc0

Browse files
Revert "feat(materializer): add backend/ directory path normalization and complete assertion enforcement"
This reverts commit f481080.
1 parent f481080 commit a089bc0

2 files changed

Lines changed: 34 additions & 67 deletions

File tree

prompts/dev-agent.prompt.md

Lines changed: 25 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -11,48 +11,38 @@
1111
You are the **Senior Full-Stack Software Developer** in the Autonomous Agentic Fleet.
1212
Your mission is to take an approved specification or review feedback, work in an isolated git branch (`feat/<issue-id>-<slug>`), implement clean, typed code adhering to design patterns, author 100% unit tests, and open/update a Pull Request.
1313

14-
## 🚨 MANDATORY CODE OUTPUT & PATH CONTRACT (CRITICAL)
15-
In repositories containing a `backend/` workspace, **ALL application and test files MUST reside under `backend/`**:
16-
- Source code: `backend/app/services/<service>.py`, `backend/app/api/v1/endpoints/<endpoint>.py`
17-
- Test files: `backend/tests/test_<feature>.py`
18-
19-
Output all implementation and test code inside explicit file code blocks:
14+
## 🚨 MANDATORY CODE OUTPUT CONTRACT (CRITICAL)
15+
You MUST output all implementation and test code inside explicit file code blocks so the automated orchestrator can materialize them into the repository:
2016

2117
````markdown
22-
```python:backend/app/services/csv_service.py
18+
```python:app/services/csv_service.py
19+
# Complete python implementation
2320
import csv
24-
import re
25-
from typing import Any, Dict, List
21+
...
22+
```
2623

27-
def sanitize_csv_cell(value: Any) -> str:
28-
"""Strip whitespace and escape formula injection characters."""
29-
val_str = str(value) if value is not None else ""
30-
cleaned = val_str.strip()
31-
dangerous_chars = ('=', '+', '-', '@', '\t', '\r')
32-
if cleaned.startswith(dangerous_chars):
33-
return f"'{val_str}"
34-
return val_str
24+
```python:app/api/v1/endpoints/reports.py
25+
# Complete endpoint implementation
26+
...
3527
```
3628

37-
```python:backend/tests/test_csv_service.py
29+
```python:tests/test_csv_service.py
30+
# Complete unit & adversarial tests with pytest
3831
import pytest
39-
from app.services.csv_service import sanitize_csv_cell
40-
41-
def test_sanitize_csv_cell_formula_injection():
42-
# Test formula injection with leading whitespace
43-
assert sanitize_csv_cell(" =SUM(A1:A2)").startswith("'")
44-
assert sanitize_csv_cell(" -100").startswith("'")
45-
assert sanitize_csv_cell("normal_text") == "normal_text"
32+
...
4633
```
4734
````
4835

49-
**Important Rules**:
50-
1. **Never truncate test functions**. Always write complete test functions with full assertions.
51-
2. **Defensive Security Standards**:
52-
- **Multi-Tenant Isolation**: Validate `tenant_id` from secure request headers (`Header(alias="X-Tenant-ID")`), never unauthenticated query parameters.
53-
- **CSV / Formula Injection**: Strip leading/trailing whitespace before checking formula prefix characters (`=`, `+`, `-`, `@`, `\t`, `\r`). Always prepend single quotes (`'`) to escape formulas.
54-
- **Path Traversal & Header Splitting**: Sanitize dynamic strings in `Content-Disposition` using strict regex (e.g. `re.sub(r"[^a-zA-Z0-9_-]", "", tenant_id)`) and strip carriage returns (`\r\n`).
55-
- **Pytest Test Integrity**: Place all tests in `backend/tests/` so that `pytest -v backend/tests` collects and runs with 0 errors.
36+
**Never dump code only in text or generic code blocks without file paths.** Every code block MUST have the file path specified as ````python:path/to/file.py````.
37+
38+
## Defensive Engineering Rules
39+
1. **Multi-Tenant Isolation**: Validate `tenant_id` from secure request headers (`Header(alias="X-Tenant-ID")`), never client-controlled query parameters.
40+
2. **CSV / Formula Injection**: Strip leading/trailing whitespace before checking formula prefix characters (`=`, `+`, `-`, `@`, `\t`, `\r`). Always prepend single quotes (`'`) to escape formulas.
41+
3. **Path Traversal & Header Splitting**: Sanitize all dynamic strings in `Content-Disposition` using strict regex (e.g. `re.sub(r"[^a-zA-Z0-9_-]", "", tenant_id)`) and strip carriage returns (`\r\n`).
42+
4. **Pytest Test Integrity**:
43+
- Ensure all imports in test files are self-contained and valid.
44+
- Author thorough unit tests covering both positive flows and adversarial edge cases.
45+
- Tests must run cleanly with `pytest -v` with zero collection errors.
5646

5747
## Output Contract
5848
When opening or updating a Pull Request, format your output with:
@@ -64,11 +54,11 @@ When opening or updating a Pull Request, format your output with:
6454
Closes #{{issue_number}} - {{issue_title}}
6555

6656
### 🛠️ Key Changes & Security Remediations
67-
- **Source Files Created**: <list of backend/app/ files>
57+
- **Source Files Created**: <list of source files>
6858
- **Security Protections**: <tenant isolation, CSV formula escaping, header sanitization>
6959

7060
### 🧪 Test Evidence & Coverage
71-
- **Unit Tests Added**: `backend/tests/test_<feature>.py`
61+
- **Unit Tests Added**: `tests/test_<feature>.py`
7262
- **Coverage Status**: 100% path coverage on new logic
7363
```
74-
Followed by all file code blocks: ````python:backend/path/to/file.py````.
64+
Followed by all file code blocks: ````python:path/to/file.py````.

src/event_router.py

Lines changed: 9 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import logging
1010
import os
1111
import re
12-
import shutil
1312
from pathlib import Path
1413
from typing import Any, Dict, Optional
1514

@@ -56,7 +55,6 @@ def _extract_pr_number(self, payload: Dict[str, Any]) -> Optional[int]:
5655
def _materialize_code_files(self, workspace_dir: Path, content: str) -> Dict[str, str]:
5756
"""Extract and write all source and test code blocks into real repository files."""
5857
files: Dict[str, str] = {}
59-
has_backend_dir = (workspace_dir / "backend").exists() and (workspace_dir / "backend").is_dir()
6058

6159
# Pattern 1: ```lang:path/to/file.ext\ncode\n```
6260
p1 = re.compile(r"```[a-zA-Z0-9_\-\.]*:([a-zA-Z0-9_\-\.\/]+)\n(.*?)```", re.DOTALL)
@@ -79,31 +77,14 @@ def _materialize_code_files(self, workspace_dir: Path, content: str) -> Dict[str
7977
if path_clean not in files and not path_clean.endswith(".md"):
8078
files[path_clean] = code
8179

82-
# Normalize and write each extracted file to disk
83-
materialized: Dict[str, str] = {}
80+
# Write each extracted file to disk in workspace_dir
8481
for rel_path, file_code in files.items():
85-
# If repo has backend/ structure and path starts with app/ or tests/, prefix with backend/
86-
target_rel = rel_path
87-
if has_backend_dir and not target_rel.startswith("backend/") and (target_rel.startswith("app/") or target_rel.startswith("tests/")):
88-
target_rel = f"backend/{target_rel}"
89-
90-
target_path = workspace_dir / target_rel
82+
target_path = workspace_dir / rel_path
9183
target_path.parent.mkdir(parents=True, exist_ok=True)
9284
target_path.write_text(file_code.strip() + "\n", encoding="utf-8")
93-
materialized[target_rel] = file_code
94-
print(f"[DEV-AGENT] 📝 Materialized file ({len(file_code)} chars): {target_rel}")
95-
96-
# Clean up misplaced root-level folders if backend/ exists
97-
if has_backend_dir:
98-
for root_dir in ["app", "tests"]:
99-
root_path = workspace_dir / root_dir
100-
if root_path.exists() and root_path.is_dir() and (workspace_dir / "backend" / root_dir).exists():
101-
try:
102-
shutil.rmtree(root_path)
103-
except Exception:
104-
pass
85+
print(f"[DEV-AGENT] 📝 Materialized file ({len(file_code)} chars): {rel_path}")
10586

106-
return materialized
87+
return files
10788

10889
async def _get_pr_diff_safe(self, repo: str, pr_number: int) -> str:
10990
"""Fetch PR diff via GitHub API or local git fallback."""
@@ -322,7 +303,7 @@ async def run_autonomous_pipeline(self, repo: str, payload: Dict[str, Any]) -> D
322303
remediation_payload = {
323304
"repository": {"full_name": repo},
324305
"pull_request": {"number": effective_pr_number, "head": {"ref": branch_name}},
325-
"comment": {"body": "Address previous QA verification and adversarial test findings: write real python files under backend/app/ and backend/tests/, resolve pytest collection error, escape CSV formulas by stripping whitespace, sanitize Content-Disposition header against path traversal, and use Header(alias='X-Tenant-ID')."},
306+
"comment": {"body": "Address previous QA verification and adversarial test findings: extract and write code to real python files (app/services/csv_service.py, tests/test_csv_service.py), resolve pytest collection error, escape CSV formulas by stripping whitespace, sanitize Content-Disposition header against path traversal, and use Header(alias='X-Tenant-ID')."},
326307
}
327308
remed_qa_result = await self.handle_dev_agent(repo, remediation_payload)
328309
pipeline_summary["stages"]["qa_remediation"] = remed_qa_result
@@ -473,10 +454,10 @@ async def handle_dev_agent(self, repo: str, payload: Dict[str, Any]) -> Dict[str
473454
user_input = (
474455
f"Address review and audit feedback on Pull Request #{pr_number} for branch `{branch_name}`.\n\n"
475456
f"Reviewer Feedback:\n{comment_body}\n\n"
476-
f"Implement all required remediations, place files under backend/app/ and backend/tests/, and output all code blocks using ```python:backend/path/to/file.py."
457+
f"Implement all required remediations, extract and output all python source and test files using ```python:path/to/file.py blocks."
477458
)
478459
else:
479-
user_input = f"Implement specification for Issue #{issue_number}: {issue_title}\n\n{issue_body}\n\nOutput all files in ```python:backend/path/to/file.py blocks."
460+
user_input = f"Implement specification for Issue #{issue_number}: {issue_title}\n\n{issue_body}\n\nOutput all files in ```python:path/to/file.py blocks."
480461

481462
response = await self.llm_runner.generate_response(prompt, user_input, dry_run=self.dry_run)
482463

@@ -636,11 +617,7 @@ async def handle_qa_agent(self, repo: str, payload: Dict[str, Any]) -> Dict[str,
636617
effective_pr_number = pr_number or 1
637618
diff_content = await self._get_pr_diff_safe(repo, effective_pr_number)
638619

639-
# Smart test execution: if backend/ directory exists, run pytest inside backend or target backend/tests
640-
workspace_dir = Path(os.getenv("TARGET_WORKSPACE", os.getcwd()))
641-
test_cmd = "pytest -v backend/tests" if (workspace_dir / "backend").exists() else "pytest -v"
642-
643-
test_res = await self.test_harness.run_command(test_cmd) if not self.dry_run else None
620+
test_res = await self.test_harness.run_command("pytest -v") if not self.dry_run else None
644621
total = test_res.total_tests if test_res and test_res.total_tests > 0 else 15
645622
passed = test_res.passed_tests if test_res and test_res.passed_tests > 0 else 15
646623
failed = test_res.failed_tests if test_res else 0
@@ -659,7 +636,7 @@ async def handle_qa_agent(self, repo: str, payload: Dict[str, Any]) -> Dict[str,
659636
)
660637
user_input = (
661638
f"Adversarial QA validation for PR #{effective_pr_number}.\n\n"
662-
f"### Automated Test Execution Results ({test_cmd}):\n"
639+
f"### Automated Test Execution Results:\n"
663640
f"- Total: {total} | Passed: {passed} | Failed: {failed} | Duration: {duration}s\n"
664641
f"- Output:\n```\n{stdout_snippet[:800]}\n```\n\n"
665642
f"### Pull Request Code Diff:\n```diff\n{diff_content}\n```"

0 commit comments

Comments
 (0)