Skip to content
This repository was archived by the owner on Jul 19, 2026. It is now read-only.
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
5 changes: 5 additions & 0 deletions .bazelignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.git
.venv
build
dist
htmlcov
26 changes: 26 additions & 0 deletions .bazelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
common --enable_bzlmod
common --announce_rc
common --color=yes
common --terminal_columns=120

build --verbose_failures
build --experimental_repository_cache_hardlinks
build --experimental_convenience_symlinks=ignore

test --test_output=errors
test --test_summary=terse

build:remote-gcp-dev --remote_executor=grpc://127.0.0.1:8980
build:remote-gcp-dev --remote_timeout=3600
build:remote-gcp-dev --remote_download_toplevel
build:remote-gcp-dev --remote_default_exec_properties=container-image=docker://gcr.io/cloud-marketplace/google/rbe-ubuntu24-04@sha256:70a81b361f88e9bc3668e6f7f1a45e7036f15fdf073aede238d9b64c548cc0c0
build:remote-gcp-dev --host_platform=//bazel/platforms:linux_x86_64
build:remote-gcp-dev --platforms=//bazel/platforms:linux_x86_64
build:remote-gcp-dev --extra_execution_platforms=//bazel/platforms:linux_x86_64
build:remote-gcp-dev --spawn_strategy=remote
build:remote-gcp-dev --strategy=Genrule=remote
build:remote-gcp-dev --strategy=PyCompile=remote
build:remote-gcp-dev --jobs=32
test:remote-gcp-dev --test_output=errors

try-import %workspace%/.bazelrc.user
1 change: 1 addition & 0 deletions .bazelversion
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
9.1.0
5 changes: 5 additions & 0 deletions .github/actionlint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
self-hosted-runner:
labels:
- blacksmith-4vcpu-ubuntu-2404
- evalops-agent-harness-rbe
- bazel-rbe
67 changes: 67 additions & 0 deletions .github/workflows/bazel-rbe.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: Bazel RBE

on:
pull_request:
paths:
- ".bazel*"
- ".github/actionlint.yaml"
- ".github/workflows/bazel-rbe.yml"
- "BUILD.bazel"
- "MODULE.bazel"
- "MODULE.bazel.lock"
- "agent_harness.py"
- "bazel/**"
- "pyproject.toml"
- "requirements_lock.txt"
- "scripts/run-bazel-rbe.sh"
- "tests/**"
push:
branches: [main]
paths:
- ".bazel*"
- ".github/actionlint.yaml"
- ".github/workflows/bazel-rbe.yml"
- "BUILD.bazel"
- "MODULE.bazel"
- "MODULE.bazel.lock"
- "agent_harness.py"
- "bazel/**"
- "pyproject.toml"
- "requirements_lock.txt"
- "scripts/run-bazel-rbe.sh"
- "tests/**"
workflow_dispatch:

permissions:
contents: read

jobs:
smoke:
if: github.event_name == 'workflow_dispatch' || vars.BAZEL_RBE_ENABLED == 'true'
runs-on:
- self-hosted
- evalops-agent-harness-rbe
- bazel-rbe
timeout-minutes: 20
steps:
- name: Checkout
uses: actions/checkout@de0facc42343c4c3d0f2fb3f1f251f9f7e3ce75b # v6.0.2

- name: Set up Go for Bazel tools
uses: actions/setup-go@4a3601d38874680202d6939c4edd8cf679bd637a # v6.4.0
with:
go-version: "1.26.3"

- name: Install Bazel tools
env:
GOBIN: ${{ runner.temp }}/go-bin
run: |
go install github.com/bazelbuild/bazelisk@latest
go install github.com/bazelbuild/buildtools/buildifier@latest
echo "${GOBIN}" >> "${GITHUB_PATH}"

- name: Run Bazel checks
run: make bazel-check

- name: Run Bazel RBE smoke
run: make bazel-rbe-smoke
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,6 @@ claude-agent-sdk-python/
.pytest_cache/
.coverage
htmlcov/

# Bazel
/bazel-*
21 changes: 21 additions & 0 deletions BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
load("@pypi//:requirements.bzl", "requirement")
load("@rules_python//python:defs.bzl", "py_library", "py_test")

py_library(
name = "agent_harness",
srcs = ["agent_harness.py"],
imports = ["."],
visibility = ["//visibility:public"],
)

py_test(
name = "pytest",
srcs = glob(["tests/**/*.py"]),
data = ["pyproject.toml"],
main = "tests/pytest_main.py",
deps = [
":agent_harness",
requirement("pytest"),
requirement("pytest-asyncio"),
],
)
22 changes: 22 additions & 0 deletions MODULE.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
module(
name = "evalops_agent_harness",
version = "0.0.0",
)

bazel_dep(name = "platforms", version = "1.1.0")
bazel_dep(name = "rules_python", version = "1.7.0")

python = use_extension("@rules_python//python/extensions:python.bzl", "python")
python.toolchain(
is_default = True,
python_version = "3.11",
)
use_repo(python, "python_3_11")

pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip")
pip.parse(
hub_name = "pypi",
python_version = "3.11",
requirements_lock = "//:requirements_lock.txt",
)
use_repo(pip, "pypi")
451 changes: 451 additions & 0 deletions MODULE.bazel.lock

Large diffs are not rendered by default.

22 changes: 21 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: help install install-dev test lint format type-check clean
.PHONY: help install install-dev test lint format type-check requirements-lock bazel-format bazel-mod-tidy bazel-check bazel-test bazel-test-remote bazel-rbe-smoke clean

help:
@echo "Agent Harness Development Commands"
Expand Down Expand Up @@ -41,6 +41,26 @@ format-check:
type-check:
mypy agent_harness.py

requirements-lock:
uv pip compile pyproject.toml --extra dev -o requirements_lock.txt

bazel-format:
buildifier BUILD.bazel bazel/platforms/BUILD.bazel

bazel-mod-tidy:
bazelisk mod tidy

bazel-test:
bazelisk test //:pytest

bazel-test-remote:
bazelisk test //:pytest --config=remote-gcp-dev

bazel-rbe-smoke:
scripts/run-bazel-rbe.sh test //:pytest

bazel-check: requirements-lock bazel-format bazel-mod-tidy bazel-test

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

CI "check" target modifies files instead of validating

Medium Severity

The bazel-check target depends on requirements-lock, bazel-format, and bazel-mod-tidy, all of which mutate files in-place (regenerating the lock file, reformatting BUILD files, tidying MODULE.bazel) before running bazel-test. When the CI workflow runs make bazel-check, it silently fixes stale or unformatted committed files and then tests against the modified working tree, so it will never catch a PR with a stale requirements_lock.txt or unformatted BUILD files. The committed files remain incorrect but CI passes.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 3c714e9. Configure here.


clean:
rm -rf build/
rm -rf dist/
Expand Down
7 changes: 7 additions & 0 deletions bazel/platforms/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
platform(
name = "linux_x86_64",
constraint_values = [
"@platforms//cpu:x86_64",
"@platforms//os:linux",
],
)
53 changes: 53 additions & 0 deletions requirements_lock.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# This file was autogenerated by uv via the following command:
# uv pip compile pyproject.toml --extra dev -o requirements_lock.txt
ast-serialize==0.4.0
# via mypy
black==26.3.1
# via agent-harness (pyproject.toml)
click==8.3.3
# via black
coverage==7.14.0
# via pytest-cov
iniconfig==2.3.0
# via pytest
librt==0.11.0
# via mypy
mypy==2.1.0
# via agent-harness (pyproject.toml)
mypy-extensions==1.1.0
# via
# black
# mypy
packaging==26.2
# via
# black
# pytest
pathspec==1.1.1
# via
# black
# mypy
platformdirs==4.9.6
# via black
pluggy==1.6.0
# via
# pytest
# pytest-cov
pygments==2.20.0
# via pytest
pytest==9.0.3
# via
# agent-harness (pyproject.toml)
# pytest-asyncio
# pytest-cov
pytest-asyncio==1.3.0
# via agent-harness (pyproject.toml)
pytest-cov==7.1.0
# via agent-harness (pyproject.toml)
pytokens==0.4.1
# via black
ruff==0.15.13
# via agent-harness (pyproject.toml)
typing-extensions==4.15.0
# via
# mypy
# pytest-asyncio
34 changes: 34 additions & 0 deletions scripts/run-bazel-rbe.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#!/usr/bin/env bash
set -euo pipefail

PROJECT_ID="${PROJECT_ID:-evalops-dev}"
ZONE="${ZONE:-us-central1-a}"
INSTANCE="${INSTANCE:-bazel-rbe-dev-buildfarm}"
LOCAL_PORT="${LOCAL_PORT:-8980}"
REMOTE_PORT="${REMOTE_PORT:-8980}"
CONFIG="${CONFIG:-remote-gcp-dev}"

if [[ $# -eq 0 ]]; then
set -- test //...
fi

if pgrep -f "gcloud compute start-iap-tunnel ${INSTANCE} ${REMOTE_PORT}.*--local-host-port=localhost:${LOCAL_PORT}" >/dev/null; then
tunnel_pid=""
else
gcloud compute start-iap-tunnel "${INSTANCE}" "${REMOTE_PORT}" \
--project "${PROJECT_ID}" \
--zone "${ZONE}" \
--local-host-port="localhost:${LOCAL_PORT}" \
>/tmp/agent-harness-bazel-rbe-tunnel.log 2>&1 &
tunnel_pid="$!"
sleep 2
fi

cleanup() {
if [[ -n "${tunnel_pid:-}" ]]; then
kill "${tunnel_pid}" >/dev/null 2>&1 || true
fi
}
trap cleanup EXIT

bazelisk "$@" "--config=${CONFIG}"
28 changes: 28 additions & 0 deletions tests/pytest_main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from __future__ import annotations

import os
import sys
from pathlib import Path

import pytest


def main() -> int:
test_tmp = os.environ.get("TEST_TMPDIR")
if test_tmp:
os.chdir(test_tmp)

runfiles_root = Path(__file__).resolve().parents[1]
return pytest.main(
[
str(runfiles_root / "tests"),
"-c",
str(runfiles_root / "pyproject.toml"),
"-p",
"no:cacheprovider",
]
)


if __name__ == "__main__":
sys.exit(main())
Loading