Repository: harbor-framework/harbor
Issue: Bug: Harden Docker `upload_dir` so `/tests` always works
Root cause: Validation Gap

In reference to the original find: https://github.com/badlogic/pi-terminal-bench

## Summary
- Normalize `DockerEnvironment.upload_dir` so Docker copies the contents of the host `tests/` directory into `/tests` even when that directory already exists in the container.
- Add regression tests that lock in the `/.` suffix handling for plain paths, trailing slashes, and pre-normalized inputs.
- Document that `/tests` is harness-owned, so agent implementations should treat it as read-only.

## Problem Statement
- `harbor/src/harbor/verifier/verifier.py` always executes the verifier payload from `/tests/...`.
- Agents are allowed to create `/tests` during task execution. When that happens, `docker cp <host/tests> main:/tests` copies the entire directory (not its contents) into the *existing* `/tests`, producing `/tests/tests/...`.
- The verifier still runs `/tests/test.sh`, so the copy “succeeds” yet the script is missing at the expected path, causing grading to fail.

### Log Evidence
Representative Harbor job logs show the verifier looking for `/tests/test.sh` immediately after the copy step and failing:

> `bash: /tests/test.sh: No such file or directory`

This line reoccurs across unrelated tasks and agents, which is only possible if the harness misplaced the verifier payload after copying.

## Proposed Fix
1. **Source normalization**
   - In `harbor/src/harbor/environments/docker/docker.py`, coerce `source_dir` to a string, strip any trailing `/` or `\`, and append `/.` unless the caller already provided it. Pass that to `_run_docker_compose_command(["cp", normalized_source, f"main:{target_dir}"])`.
   - Docker then copies the directory *contents*, so `/tests` contains the expected files regardless of whether it existed beforehand.
2. **Regression tests**
   - Add `tests/unit/environments/test_docker_upload_dir.py`:
     - Build a minimal `DockerEnvironment`.
     - Stub `_run_docker_compose_command` and assert the generated command is `["cp", "<src>/.", "main:/tests"]` for paths and trailing slashes.
     - Verify inputs that already end with `/.` pass through untouched (no duplicate suffix).

## End-to-End Validation
```bash
cd harbor
pip install -e .[dev]
pytest tests/unit/environments/test_docker_upload_dir.py
```

Only the Docker environment copy path changes; other environment backends already stream individual files and are unaffected. Once merged, verifier uploads remain reliable even when agents manipulate `/tests` earlier in their run.

## Fixes attached for reference
# Replace Instructions – Harbor Docker `/tests` Fix

## 1. Normalize `DockerEnvironment.upload_dir`

```
@@@ REPLACE @@@
path: harbor/src/harbor/environments/docker/docker.py
@@@
    async def upload_dir(self, source_dir: Path | str, target_dir: str):
        await self._run_docker_compose_command(
            [
                "cp",
                str(source_dir),
                f"main:{target_dir}",
            ],
            check=True,
        )
@@@
    async def upload_dir(self, source_dir: Path | str, target_dir: str):
        source_str = os.fspath(source_dir)

        if source_str.endswith(("/.", "\\.")):
            normalized_source = source_str
        else:
            stripped = source_str.rstrip("/\\") or source_str
            normalized_source = os.path.join(stripped, ".")

        await self._run_docker_compose_command(
            [
                "cp",
                normalized_source,
                f"main:{target_dir}",
            ],
            check=True,
        )
@@@
```

## 2. Add regression tests

```
@@@ ADD @@@
path: harbor/tests/unit/environments/test_docker_upload_dir.py
@@@
import os
from pathlib import Path
from typing import Any

import pytest

from harbor.environments.base import ExecResult
from harbor.environments.docker.docker import DockerEnvironment
from harbor.models.task.config import EnvironmentConfig
from harbor.models.trial.paths import TrialPaths


def _build_environment(tmp_path: Path) -> DockerEnvironment:
    env_dir = tmp_path / "env"
    env_dir.mkdir()
    (env_dir / "Dockerfile").write_text("FROM scratch\\n", encoding="utf-8")

    trial_dir = tmp_path / "trial"
    trial_dir.mkdir()

    return DockerEnvironment(
        environment_dir=env_dir,
        environment_name="test-env",
        session_id="session-id",
        trial_paths=TrialPaths(trial_dir=trial_dir),
        task_env_config=EnvironmentConfig(),
    )


def _make_recorder():
    recorded: dict[str, Any] = {}

    async def _record(command, check=True, timeout_sec=None):
        recorded["command"] = command
        return ExecResult(stdout=None, stderr=None, return_code=0)

    return recorded, _record


@pytest.mark.asyncio
async def test_upload_dir_appends_contents_suffix(tmp_path):
    env = _build_environment(tmp_path)
    tests_dir = tmp_path / "tests_src"
    tests_dir.mkdir()
    recorded, recorder = _make_recorder()
    env._run_docker_compose_command = recorder  # type: ignore[attr-defined]

    await env.upload_dir(tests_dir, "/tests")

    assert recorded["command"][0] == "cp"
    assert recorded["command"][1] == os.path.join(str(tests_dir), ".")
    assert recorded["command"][2] == "main:/tests"


@pytest.mark.asyncio
async def test_upload_dir_skips_extra_suffix_if_present(tmp_path):
    env = _build_environment(tmp_path)
    tests_dir = tmp_path / "tests_src"
    tests_dir.mkdir()
    recorded, recorder = _make_recorder()
    env._run_docker_compose_command = recorder  # type: ignore[attr-defined]

    explicit_suffix = f"{tests_dir}{os.sep}."
    await env.upload_dir(explicit_suffix, "/tests")

    assert recorded["command"][1] == explicit_suffix


@pytest.mark.asyncio
async def test_upload_dir_handles_trailing_slashes(tmp_path):
    env = _build_environment(tmp_path)
    tests_dir = tmp_path / "tests_src"
    tests_dir.mkdir()
    recorded, recorder = _make_recorder()
    env._run_docker_compose_command = recorder  # type: ignore[attr-defined]

    path_with_slash = f"{tests_dir}{os.sep}"
    await env.upload_dir(path_with_slash, "/tests")

    assert recorded["command"][1] == os.path.join(str(tests_dir), ".")
@@@
```