diff --git a/internal/harness/scaffold_integration_test.go b/internal/harness/scaffold_integration_test.go index 1a3bbe0cc..68b4ddcf0 100644 --- a/internal/harness/scaffold_integration_test.go +++ b/internal/harness/scaffold_integration_test.go @@ -287,9 +287,9 @@ func TestLoadRaw_GeneratedWrapperFormat(t *testing.T) { } // TestResolveForge_ScaffoldRunnerEnvMerge verifies that forge resolution -// produces the expected merged runner_env for each scaffold template, with -// both top-level (platform-neutral) and forge.github (platform-specific) -// keys present in the final merged state. +// produces the expected merged env.runner (or legacy runner_env) for each +// scaffold template, with both top-level (platform-neutral) and +// forge.github (platform-specific) keys present in the final merged state. func TestResolveForge_ScaffoldRunnerEnvMerge(t *testing.T) { dir := t.TempDir() harnessDir := extractScaffoldHarnessDir(t, dir) diff --git a/internal/scaffold/fullsend-repo/env/fix-agent.env b/internal/scaffold/fullsend-repo/env/fix-agent.env index cf5e1f14b..0a99208c2 100644 --- a/internal/scaffold/fullsend-repo/env/fix-agent.env +++ b/internal/scaffold/fullsend-repo/env/fix-agent.env @@ -1,54 +1,3 @@ -export PR_NUMBER="${PR_NUMBER}" -export REPO_FULL_NAME="${REPO_FULL_NAME}" -export TRIGGER_SOURCE="${TRIGGER_SOURCE}" -export HUMAN_INSTRUCTION="${HUMAN_INSTRUCTION}" -export FIX_ITERATION="${FIX_ITERATION}" - -# GH_TOKEN in the sandbox is a READ-ONLY scoped app installation token -# (contents:read, issues:read, pull_requests:read). Set by -# setup-agent-env.sh from FIX_GH_TOKEN. This token CANNOT push code -# or create PRs — the read-only scope is the actual enforcement layer. -# The separate write-enabled PUSH_TOKEN (runner_env) never enters the sandbox. -export GH_TOKEN="${GH_TOKEN}" - -# Author name is "fullsend-fix" (not "fullsend-code") so fix-agent -# commits are distinguishable for iteration counting. Both agents share -# the same GitHub App (coder role), so GIT_BOT_EMAIL resolves to the -# same bot noreply address. This makes the Probot DCO app auto-exempt -# agent commits (author.type === "Bot"). -export GIT_AUTHOR_NAME="fullsend-fix" -export GIT_AUTHOR_EMAIL="${GIT_BOT_EMAIL}" -export GIT_COMMITTER_NAME="fullsend-fix" -export GIT_COMMITTER_EMAIL="${GIT_BOT_EMAIL}" - -# Retry budget — the agent re-runs secret scan + tests on failure. -# Pre-commit is capped at 2 runs total (not per retry). -export MAX_RETRIES=1 - -# Hard timeout for the sandbox session in seconds. Must match -# timeout_minutes in harness/fix.yaml. -export TIMEOUT_SECONDS=1500 - -# Strategy escalation: after this many fix iterations, the agent should -# try a fundamentally different approach. -export STRATEGY_ESCALATION_THRESHOLD=3 - -# Iteration caps: bot-triggered runs (review→fix loop) have a tighter cap -# than human-triggered runs (/fix commands). When the iteration count -# approaches the bot cap, the 'needs-human' label is added and a human can -# still direct the agent with /fix up to ITERATION_CAP_HUMAN total iterations -# (bot + human combined). -export ITERATION_CAP=5 -export ITERATION_CAP_HUMAN=10 - -# Go toolchain — PATH is set in the sandbox image via Containerfile ENV. -# Do NOT set PATH here: this file uses expand: true (harness host_files), so -# ${PATH} would be replaced with the GitHub Actions runner's PATH by -# os.ExpandEnv, clobbering /sandbox/workspace/bin and breaking sandbox-local -# binaries. See code-agent.env lines 27-33 for the full explanation. -export GOPATH="/sandbox/go" -export GOMODCACHE="/sandbox/go/pkg/mod" - # SSL certs — same workaround as code agent for OpenShell TLS termination. if [ -f /etc/openshell-tls/ca-bundle.pem ]; then export GIT_SSL_CAINFO=/etc/openshell-tls/ca-bundle.pem diff --git a/internal/scaffold/fullsend-repo/harness/fix.yaml b/internal/scaffold/fullsend-repo/harness/fix.yaml index 0561abeeb..345d66269 100644 --- a/internal/scaffold/fullsend-repo/harness/fix.yaml +++ b/internal/scaffold/fullsend-repo/harness/fix.yaml @@ -42,15 +42,24 @@ host_files: skills: - skills/fix-review -runner_env: - TARGET_BRANCH: "${TARGET_BRANCH}" - TRIGGER_SOURCE: "${TRIGGER_SOURCE}" - HUMAN_INSTRUCTION: "${HUMAN_INSTRUCTION}" - FIX_ITERATION: "${FIX_ITERATION}" - REVIEW_BODY_FILE: "${REVIEW_BODY_FILE}" - PRE_AGENT_HEAD: "${PRE_AGENT_HEAD}" - FULLSEND_OUTPUT_SCHEMA: ${FULLSEND_DIR}/schemas/fix-result.schema.json - FULLSEND_OUTPUT_FILE: fix-result.json +env: + runner: + TARGET_BRANCH: "${TARGET_BRANCH}" + TRIGGER_SOURCE: "${TRIGGER_SOURCE}" + HUMAN_INSTRUCTION: "${HUMAN_INSTRUCTION}" + FIX_ITERATION: "${FIX_ITERATION}" + REVIEW_BODY_FILE: "${REVIEW_BODY_FILE}" + PRE_AGENT_HEAD: "${PRE_AGENT_HEAD}" + FULLSEND_OUTPUT_SCHEMA: ${FULLSEND_DIR}/schemas/fix-result.schema.json + FULLSEND_OUTPUT_FILE: fix-result.json + sandbox: + MAX_RETRIES: "1" + TIMEOUT_SECONDS: "1500" + STRATEGY_ESCALATION_THRESHOLD: "3" + ITERATION_CAP: "5" + ITERATION_CAP_HUMAN: "10" + GOPATH: "/sandbox/go" + GOMODCACHE: "/sandbox/go/pkg/mod" timeout_minutes: 25 @@ -58,9 +67,21 @@ forge: github: pre_script: scripts/pre-fix.sh post_script: scripts/post-fix.sh - runner_env: - PUSH_TOKEN: "${PUSH_TOKEN}" - PUSH_TOKEN_SOURCE: "${PUSH_TOKEN_SOURCE}" - REPO_FULL_NAME: "${REPO_FULL_NAME}" - PR_NUMBER: "${PR_NUMBER}" - REPO_DIR: "${GITHUB_WORKSPACE}/target-repo" + env: + runner: + PUSH_TOKEN: "${PUSH_TOKEN}" + PUSH_TOKEN_SOURCE: "${PUSH_TOKEN_SOURCE}" + REPO_FULL_NAME: "${REPO_FULL_NAME}" + PR_NUMBER: "${PR_NUMBER}" + REPO_DIR: "${GITHUB_WORKSPACE}/target-repo" + sandbox: + PR_NUMBER: "${PR_NUMBER}" + REPO_FULL_NAME: "${REPO_FULL_NAME}" + TRIGGER_SOURCE: "${TRIGGER_SOURCE}" + HUMAN_INSTRUCTION: "${HUMAN_INSTRUCTION}" + FIX_ITERATION: "${FIX_ITERATION}" + GH_TOKEN: "${GH_TOKEN}" + GIT_AUTHOR_NAME: "fullsend-fix" + GIT_AUTHOR_EMAIL: "${GIT_BOT_EMAIL}" + GIT_COMMITTER_NAME: "fullsend-fix" + GIT_COMMITTER_EMAIL: "${GIT_BOT_EMAIL}"