Skip to content

Commit d629994

Browse files
committed
Add Gradle project support for Kotlin/Java tasks and expand agent allowed hosts
- Require Gradle project structure for Kotlin/Java tasks with offline-compatible dependencies. - Extend default agent allowed hosts to include Maven, Gradle, Kotlin, and related build-tool documentation. - Adjust default retry policy: set `n_attempts=3` and `max_retries=2`. - Update templates and Dockerfile to reflect Gradle integration. - Introduce new dependencies (`ipykernel`, `matplotlib`, `pandas`) in `pyproject.toml`. - Expand test coverage for Gradle enforcement, allowed hosts, and policy adjustments.
1 parent 93c8bf7 commit d629994

8 files changed

Lines changed: 1716 additions & 26 deletions

File tree

‎pyproject.toml‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ dependencies = [
1717
"tqdm>=4",
1818
"rich>=13",
1919
"huggingface_hub>=0.20",
20+
"ipykernel>=7.3.0",
21+
"matplotlib>=3.10.9",
22+
"pandas>=2.3.3",
2023
]
2124

2225
[project.scripts]

‎scripts/language_comparison/config.yaml‎

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,14 @@ agent:
1010
name: codex
1111
model_name: openai/gpt-5.6-luna
1212

13+
#agent:
14+
# name: claude-code
15+
# model_name: claude-sonnet-5
16+
# kwargs:
17+
# max_budget_usd: "20"
18+
1319
tasks:
1420
task_names:
15-
# - ammarabouzor__tui-journal.2b4540d
16-
# - jesseduffield__lazygit.1d0db51
1721
- nikolassv__bartib.6b9b5ce
1822
- svenstaro__genact.16f96e3
1923
- svenstaro__miniserve.8449e8b
@@ -30,4 +34,6 @@ tasks:
3034
# Optional settings copied into the generated Harbor job config. Job name,
3135
# output paths, concurrency, agents, and datasets are generated by the harness.
3236
harbor:
33-
n_attempts: 1
37+
n_attempts: 3
38+
retry:
39+
max_retries: 2

‎src/kotlinai/README.md‎

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,12 @@ uv run programbench harbor export ./out <id> --agent-user root
5252
The agent phase runs as the cleanroom image's non-root `agent` user, so the
5353
mode-111 reference binary at `/workspace/executable` can be executed but not
5454
read, copied, or statically inspected; the generated agent image also drops the
55-
image's NOPASSWD sudo grant, which would otherwise hand root back. The agent's
56-
network allowlist covers the model API only — Harbor installs the agent CLI
57-
during *setup*, which runs before the agent-phase policy applies, so no
58-
package-registry or source-hosting host belongs on that list.
55+
image's NOPASSWD sudo grant, which would otherwise hand root back. The default
56+
agent network allowlist covers model APIs plus Maven, Gradle, Kotlin, Android,
57+
and related build-tool hosts so dependencies can be stored in `/workspace` for
58+
the offline verifier build. Source-hosting hosts remain blocked. Harbor installs
59+
the agent CLI during *setup*, before the agent-phase policy applies, so its
60+
installer hosts do not belong on the task allowlist.
5961

6062
## Language comparison experiment
6163

@@ -162,4 +164,4 @@ harbor trials start --path ./out/<instance_id> --agent oracle
162164

163165
A literal 100% oracle pass is not reachable for every task in a single-container
164166
Harbor run — some tests fail on the true reference binary itself in the sandbox
165-
(missing OS facilities, TUI hangs, snapshot date-drift).
167+
(missing OS facilities, TUI hangs, snapshot date-drift).

‎src/kotlinai/data/templates/harbor_instruction.md.j2‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ reproduces its observable behavior.
1010
{% if target_language %}
1111
You MUST implement the deliverable in {{ target_language }}. Write all source code in {{ target_language }}. Do not reimplement the program in another language.
1212
{% endif %}
13+
{% if use_gradle %}
14+
You MUST structure the implementation as a Gradle project. `compile.sh` MUST invoke
15+
Gradle to build the program. Include the Gradle wrapper and vendor the Gradle
16+
distribution and all project dependencies needed for `compile.sh` to run without
17+
network access.
18+
{% endif %}
1319
## What to deliver
1420

1521
Work inside `/workspace`. When you are done, that directory must contain:

‎src/kotlinai/data/templates/harbor_task.toml.j2‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,11 @@ build_timeout_sec = {{ build_timeout }}
3131
cpus = {{ env_cpus }}
3232
network_mode = "public"
3333

34-
# No network during inference beyond the model API: the agent must
35-
# reverse-engineer the binary, not fetch upstream source. Overriding the baseline
36-
# per phase requires a dynamic_network_policy environment backend (e.g.
37-
# Docker/OrbStack on Linux with nftables).
34+
# During inference, the agent can reach only the configured model, package,
35+
# build-tool, and toolchain documentation hosts. Source hosting stays blocked:
36+
# the agent must reverse-engineer the binary, not fetch upstream source.
37+
# Overriding the baseline per phase requires a dynamic_network_policy
38+
# environment backend (e.g. Docker/OrbStack on Linux with nftables).
3839
#
3940
# The agent runs as {{ agent_user }}. The default is a non-root user, so the
4041
# mode-111 reference binary at /workspace/executable can be executed but not

‎src/kotlinai/harbor.py‎

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,16 +44,40 @@
4444
AGENT_TIMEOUT_SEC = 10800.0
4545
KOTLIN_VERSION = "2.4.10"
4646
KOTLIN_COMPILER_SHA256 = "473dd66c7a3ef4b182065b3da670466c1bf2773a9dbb0ed8b33a39fe9d4f876d"
47-
# The agent phase reaches the model API and nothing else: fetching upstream
48-
# source would defeat the black-box task. The npm/nvm hosts Harbor's Codex
49-
# installer needs are deliberately absent — agent setup runs outside the
50-
# agent-phase policy (Harbor's `Trial._setup_agent` is not wrapped by
51-
# `_phase_network_policy`), so it installs under the `[environment]` public
52-
# baseline. Language toolchains are baked in while Harbor builds the task images.
53-
# Parameterized per runner (override with `harbor export --allowed-host`).
47+
# The agent phase can reach model APIs and the package, build-tool, and
48+
# toolchain documentation hosts needed to assemble an offline JVM submission.
49+
# Source-hosting and agent-installer hosts remain absent: fetching upstream
50+
# source would defeat the black-box task, while agent setup runs outside the
51+
# agent-phase policy under the `[environment]` public baseline. Parameterized
52+
# per runner (override with `harbor export --allowed-host`).
5453
DEFAULT_AGENT_ALLOWED_HOSTS = [
5554
"api.openai.com",
5655
"api.anthropic.com",
56+
"repo.maven.apache.org",
57+
"repo1.maven.org",
58+
"plugins.gradle.org",
59+
"services.gradle.org",
60+
"downloads.gradle.org",
61+
"maven.google.com",
62+
"maven.pkg.jetbrains.space",
63+
"maven.reposilite.com",
64+
"oss.sonatype.org",
65+
"kotlinlang.org",
66+
"*.kotlinlang.org",
67+
"kotl.in",
68+
"*.jetbrains.com",
69+
"docs.gradle.org",
70+
"docs.gradle.com",
71+
"gradle.com",
72+
"gradle.org",
73+
"scans.gradle.com",
74+
"help.gradle.org",
75+
"developer.android.com",
76+
"schemas.android.com",
77+
"pub.dartlang.org",
78+
"pub.dev",
79+
"pnpm.js.org",
80+
"ant.apache.org",
5781
]
5882
# The cleanroom image's uid-1000 user. It owns /workspace but, unlike root,
5983
# cannot read the execute-only reference binary at /workspace/executable.
@@ -136,7 +160,10 @@ def convert_instance(
136160
)
137161
)
138162
(out / "instruction.md").write_text(
139-
_env.get_template("harbor_instruction.md.j2").render(target_language=target_language)
163+
_env.get_template("harbor_instruction.md.j2").render(
164+
target_language=target_language,
165+
use_gradle=install_jdk,
166+
)
140167
)
141168
(out / "environment" / "Dockerfile").write_text(
142169
_env.get_template("harbor_environment.Dockerfile.j2").render(

‎tests/test_harbor.py‎

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,18 @@ def test_convert_instance_instructs_agent_to_use_target_language(tmp_path):
7777
assert "You MUST implement the deliverable in Kotlin." in instruction
7878
assert "Write all source code in Kotlin." in instruction
7979
assert "Do not reimplement the program in another language." in instruction
80+
assert "You MUST structure the implementation as a Gradle project." in instruction
81+
assert "`compile.sh` MUST invoke\nGradle to build the program." in instruction
82+
assert "vendor the Gradle\ndistribution and all project dependencies" in instruction
83+
assert "run without\nnetwork access" in instruction
84+
85+
86+
def test_convert_instance_only_requires_gradle_for_jvm_targets(tmp_path):
87+
java_out = convert_instance(_calc_instance(), tmp_path / "java", target_language="Java")
88+
rust_out = convert_instance(_calc_instance(), tmp_path / "rust", target_language="Rust")
89+
90+
assert "Gradle project" in (java_out / "instruction.md").read_text()
91+
assert "Gradle project" not in (rust_out / "instruction.md").read_text()
8092

8193

8294
def test_convert_instance_adds_kotlin_toolchain_to_agent_and_verifier(tmp_path):
@@ -113,15 +125,52 @@ def test_convert_instance_does_not_add_jvm_toolchain_for_other_targets(tmp_path)
113125
assert "kotlin-compiler" not in contents
114126

115127

116-
def test_default_agent_allowlist_does_not_expose_toolchain_or_source_hosts(tmp_path):
128+
def test_default_agent_allowlist_exposes_build_hosts_but_not_source_hosts(tmp_path):
117129
out = convert_instance(_calc_instance(), tmp_path, target_language="Kotlin")
118130
allowed_hosts = tomllib.loads((out / "task.toml").read_text())["agent"]["allowed_hosts"]
119131

132+
assert allowed_hosts == harbor.DEFAULT_AGENT_ALLOWED_HOSTS == [
133+
"api.openai.com",
134+
"api.anthropic.com",
135+
"repo.maven.apache.org",
136+
"repo1.maven.org",
137+
"plugins.gradle.org",
138+
"services.gradle.org",
139+
"downloads.gradle.org",
140+
"maven.google.com",
141+
"maven.pkg.jetbrains.space",
142+
"maven.reposilite.com",
143+
"oss.sonatype.org",
144+
"kotlinlang.org",
145+
"*.kotlinlang.org",
146+
"kotl.in",
147+
"*.jetbrains.com",
148+
"docs.gradle.org",
149+
"docs.gradle.com",
150+
"gradle.com",
151+
"gradle.org",
152+
"scans.gradle.com",
153+
"help.gradle.org",
154+
"developer.android.com",
155+
"schemas.android.com",
156+
"pub.dartlang.org",
157+
"pub.dev",
158+
"pnpm.js.org",
159+
"ant.apache.org",
160+
]
120161
assert "archive.ubuntu.com" not in allowed_hosts
121-
assert "repo.maven.apache.org" not in allowed_hosts
122-
assert "services.gradle.org" not in allowed_hosts
162+
assert "repo.maven.apache.org" in allowed_hosts
163+
assert "repo1.maven.org" in allowed_hosts
164+
assert "plugins.gradle.org" in allowed_hosts
165+
assert "services.gradle.org" in allowed_hosts
166+
assert "downloads.gradle.org" in allowed_hosts
167+
assert "maven.google.com" in allowed_hosts
168+
assert "maven.pkg.jetbrains.space" in allowed_hosts
169+
assert "maven.reposilite.com" in allowed_hosts
170+
assert "oss.sonatype.org" in allowed_hosts
123171
# Agent setup installs the CLI before the agent-phase policy applies, so
124-
# these are not needed here and would let the agent fetch upstream source.
172+
# its package and source hosts are not needed here. Source hosting stays
173+
# blocked so the agent cannot fetch the upstream implementation.
125174
assert "raw.githubusercontent.com" not in allowed_hosts
126175
assert "nodejs.org" not in allowed_hosts
127176
assert "registry.npmjs.org" not in allowed_hosts
@@ -131,7 +180,7 @@ def test_convert_instance_task_toml_enforces_programbench_policy(tmp_path):
131180
out = convert_instance(_calc_instance(), tmp_path, allowed_hosts=["api.example.com"])
132181
cfg = tomllib.loads((out / "task.toml").read_text())
133182

134-
# Inference is offline; only the model API host is reachable in the agent phase.
183+
# An explicit allowlist replaces the defaults for the agent phase.
135184
assert cfg["environment"]["network_mode"] == "public"
136185
assert cfg["agent"]["network_mode"] == "allowlist"
137186
assert cfg["agent"]["allowed_hosts"] == ["api.example.com"]

0 commit comments

Comments
 (0)