From 0ac6be1a3de38a1c84ee128768ae0e692b99411c Mon Sep 17 00:00:00 2001 From: Edgar Arakelyan Date: Thu, 5 Nov 2026 09:53:53 -0800 Subject: [PATCH] ci(environment): pin the real agentenv lane to agentenv-framework 0.9.1431 (#8865) * ci(environment): pin the real agentenv lane to agentenv-framework 0.9.1431 The real-agentenv lane, its identity check and the docs pinned agentenv-framework 0.9.1334, 97 releases behind the current 0.9.1431. Recorded verification notes keep the versions they ran with; the website catalogs change only the placeholder comment that shows the version. Co-Authored-By: Claude Opus 5.5 * docs(environment): describe 0.9.1431's pulled infra images; keep the site on the release 0.9.1431 pulls its gateway and service-db images from ghcr.io by the digests its release records and builds one only when that pull fails, so the lane docs, the export guide and the verifier's comments now say so, and the mirror step fetches only the bases those builds name. The public site describes the released package, which still runs 0.9.1334, so its guide and evidence page keep that version until a release ships the new pin. Co-Authored-By: Claude Opus 5.5 --------- Co-authored-by: Claude Opus 5.5 --- .github/workflows/real-agentenv.yml | 15 ++++++------ docs/agent-environments-quickstart.md | 2 +- docs/agent-environments.md | 5 ++-- .../environment-export/spec.md | 2 +- docs/testing-lanes.md | 24 +++++++++++-------- scripts/verify-agentenv-environment.mjs | 10 ++++---- .../process/agentenvVerifierIdentity.test.ts | 6 ++--- 7 files changed, 35 insertions(+), 29 deletions(-) diff --git a/.github/workflows/real-agentenv.yml b/.github/workflows/real-agentenv.yml index a252eb691c..6121fea671 100644 --- a/.github/workflows/real-agentenv.yml +++ b/.github/workflows/real-agentenv.yml @@ -54,10 +54,11 @@ jobs: - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: "3.12" - # Public ECR caps anonymous pulls by data per source IP and hosted runners share IPs, so the - # framework's image builds can fail here for hours. mirror.gcr.io serves the same Docker - # official images under the same digests, so each base image the pinned framework builds from - # is pulled there and named as its Dockerfile names it, as the framework's own CI does. + # The pinned framework builds its gateway and service-db images only when pulling them from + # ghcr.io fails, from public ECR base images; public ECR caps anonymous pulls by data per source + # IP and hosted runners share IPs, so such a build can fail here for hours. mirror.gcr.io serves + # the same Docker official images under the same digests, so each base image those Dockerfiles + # name is pulled there and named as its Dockerfile names it, as the framework's own CI does. # Digest-pinned names are set in containerd, whose images Docker reads only on the containerd # image store; switching stores restarts dockerd, so it happens before anything uses Docker. - name: Use the containerd image store @@ -72,16 +73,16 @@ jobs: run: | runner_root="${RUNNER_TEMP}/rea-agentenv-runner" python -m venv "${runner_root}" - "${runner_root}/bin/python" -m pip install --require-virtualenv --no-cache-dir 'agentenv-framework==0.9.1334' + "${runner_root}/bin/python" -m pip install --require-virtualenv --no-cache-dir 'agentenv-framework==0.9.1431' "${runner_root}/bin/agent-env" --version docker version --format '{{.Server.Version}}' echo "REA_AGENT_ENV_COMMAND=${runner_root}/bin/agent-env" >> "${GITHUB_ENV}" echo "REA_DOCKER_COMMAND=$(command -v docker)" >> "${GITHUB_ENV}" - - name: Pull the pinned framework's public ECR base images from mirror.gcr.io + - name: Pull the gateway and service-db public ECR base images from mirror.gcr.io shell: bash run: | package="$("${REA_AGENT_ENV_COMMAND%/agent-env}/python" -c 'import agent_env, pathlib; print(pathlib.Path(agent_env.__file__).parent)')" - grep -rhoE '^FROM +public\.ecr\.aws/docker/library/[^ ]+' --include='Dockerfile*' "${package}" | awk '{print $2}' | sort -u | + grep -rhoE '^FROM +public\.ecr\.aws/docker/library/[^ ]+' --include='Dockerfile*' "${package}/env/gateway" "${package}/env/envs/service_db" | awk '{print $2}' | sort -u | while read -r image; do name=${image#public.ecr.aws/docker/library/} source=mirror.gcr.io/library/$name diff --git a/docs/agent-environments-quickstart.md b/docs/agent-environments-quickstart.md index 251afd1447..4e64305714 100644 --- a/docs/agent-environments-quickstart.md +++ b/docs/agent-environments-quickstart.md @@ -19,7 +19,7 @@ records the app you provide; you start it and prepare its test data. To run the exported environment, install the [AgentEnv framework](https://github.com/scaleapi/agentenv-framework#install) and start Docker. REA's [compatibility check](testing.md#exported-environment-bundles) -uses AgentEnv version `0.9.1334` with Python 3.12. +uses AgentEnv version `0.9.1431` with Python 3.12. There are two ways to build an environment: ask your agent to record the app, or start from a recording you already have. diff --git a/docs/agent-environments.md b/docs/agent-environments.md index 71fd35bd65..be11df05db 100644 --- a/docs/agent-environments.md +++ b/docs/agent-environments.md @@ -1049,8 +1049,9 @@ unknown recorded status stays unknown; it is not borrowed from another record). A bundle with no such tool yields a verifier that checks the count only and says so. `tasks/smoke.json` deploys the env on the local sandbox and runs that verifier against the env's MCP endpoint; the first run -also builds the framework's own infrastructure, and the run tears everything -down when it ends. +also pulls the framework's published infrastructure images from `ghcr.io`, +building one only if its pull fails, and the run tears everything down when it +ends. The README written into the bundle records the capture artifact's SHA-256, the capture and manifest Evidence ids, the manifest view digest, the served tool diff --git a/docs/specs/agent-environments/environment-export/spec.md b/docs/specs/agent-environments/environment-export/spec.md index e36a4c57f5..2b1c2f98c7 100644 --- a/docs/specs/agent-environments/environment-export/spec.md +++ b/docs/specs/agent-environments/environment-export/spec.md @@ -69,7 +69,7 @@ previous increment. - Add the `agentenv` CI scope, the reusable `real-agentenv.yml` workflow (`workflow_dispatch` and `workflow_call` with `build_cache_artifact`, `ubuntu-24.04`, SHA-pinned actions, `setup-python` 3.12, a virtual - environment with `agentenv-framework==0.9.1334`, the runner's Docker, 30 + environment with `agentenv-framework==0.9.1431`, the runner's Docker, 30 minutes), the `verify:agentenv:environment` script and `scripts/verify-agentenv-environment.mjs`, which requires absolute `REA_AGENT_ENV_COMMAND` and `REA_DOCKER_COMMAND` like every other lane diff --git a/docs/testing-lanes.md b/docs/testing-lanes.md index d96cd9f629..ff3cd9d5ea 100644 --- a/docs/testing-lanes.md +++ b/docs/testing-lanes.md @@ -1172,9 +1172,10 @@ installed package entrypoint as the script's first argument for package coverage `npm run verify:agentenv:environment` is the `real-agentenv` lane. It requires the host's Docker CLI named by absolute `REA_DOCKER_COMMAND`, Python 3.12 with -`agentenv-framework==0.9.1334` installed in a virtual environment whose +`agentenv-framework==0.9.1431` installed in a virtual environment whose `agent-env` binary is named by absolute `REA_AGENT_ENV_COMMAND`, and outbound -network for `pip` on the runner and for `npm` inside the image build. Both +network for `pip` on the runner, for the framework's image pulls from `ghcr.io` +and for `npm` inside the image build. Both variables are required; neither upstream executable is resolved from `PATH`, and the verifier installs nothing. Packing uses the shared npm helper, honoring `npm_execpath` from the caller's selected npm. Direct Node invocations without @@ -1186,11 +1187,12 @@ storage, exports both paths and uses the runner's own Docker; no developer host configuration changes. `agent-env run` attempts share one 22-minute budget inside the 30-minute job (the first attempt at most 15 minutes), so a hung or retried run ends with the verifier's failed receipt rather than the runner's -kill. The framework builds its gateway and service-db -images from `public.ecr.aws` on every fresh runner, and hosted runners share -that registry's anonymous pull quota, so the lane first pulls the base images -the pinned framework's Dockerfiles name from `mirror.gcr.io`, which serves the -same Docker official images under the same digests, and names them as those +kill. The pinned framework pulls its gateway and service-db images from +`ghcr.io/scaleapi` by the digests its release records and builds one only when +its pull fails. Those builds start from `public.ecr.aws` base images, and hosted +runners share that registry's anonymous pull quota, so the lane first pulls the +base images the gateway and service-db Dockerfiles name from `mirror.gcr.io`, +which serves the same Docker official images under the same digests, and names them as those Dockerfiles do (on Docker's containerd image store, so digest-pinned names resolve), as the framework's own CI does. The quota handling below covers anything still pulled from that registry. The receipt's `agent_env_run` records the @@ -1218,9 +1220,11 @@ that served tool count, and that no container exists after the run that did not exist before; the container inventory runs even when the run fails or times out, so a failed receipt still lists what it left. The one exception is the framework's own image-store helper, `agentenv-registry` (or `agentenv-registry-`), -a `registry:2` container the local provider starts on first use and keeps -running across runs; a first run on a fresh host creates it, so the receipt -lists it under `image_store_helpers` instead of counting it as a leak. Images +a `registry:2` container the local provider starts when it first stores an image +it built and keeps running across runs. The pinned framework registers its +published infra images, and a deploy that cannot pull one builds it into the +host's Docker, so a fresh run does not normally create the helper; if one does, +the receipt lists it under `image_store_helpers` instead of counting it as a leak. Images built by the run remain and are counted in the receipt. Pass an installed package entrypoint as the script's first argument for package coverage. diff --git a/scripts/verify-agentenv-environment.mjs b/scripts/verify-agentenv-environment.mjs index 49e786ee7e..7d96a2ff29 100644 --- a/scripts/verify-agentenv-environment.mjs +++ b/scripts/verify-agentenv-environment.mjs @@ -8,10 +8,10 @@ import { PrivateRuntimeRoot } from "../dist/process/PrivateRuntimeRoot.js"; import { createVerifierRun, completeVerifierRun } from "./lib/verifier-run.mjs"; import { createPackageVerifierCommands } from "./lib/verify-package-commands.mjs"; -const AGENTENV_VERSION = "0.9.1334"; +const AGENTENV_VERSION = "0.9.1431"; const AGENTENV_PIN = `agentenv-framework ${AGENTENV_VERSION}`; -// The framework builds its infra images from public ECR, whose anonymous pull quota hosted -// runners share; a rate refusal earns one retry, anything else fails at once. +// Only an infra image whose pull fails is built, from public ECR, whose anonymous pull quota +// hosted runners share; a rate refusal earns one retry, anything else fails at once. const PUBLIC_ECR_QUOTA = /public\.ecr\.aws[\s\S]{0,400}?(?:429 Too Many Requests|toomanyrequests)/u; // The anonymous data-transfer cap is counted per source IP, so a pause on the same runner @@ -31,8 +31,8 @@ for (const key of ["REA_AGENT_ENV_COMMAND", "REA_DOCKER_COMMAND"]) ); const agentEnv = process.env.REA_AGENT_ENV_COMMAND; const docker = process.env.REA_DOCKER_COMMAND; -// The framework's local image store keeps its registry:2 helper running across runs; a first -// run on a fresh host creates it, so it is reported separately rather than counted as a leak. +// The framework's local image store keeps its registry:2 helper running across runs; a run that +// first stores a build there creates it, so it is reported separately rather than counted as a leak. const IMAGE_STORE_HELPER = /^agentenv-registry(?:-\d+)?$/u; await Promise.all([access(agentEnv), access(docker)]); const entrypoint = diff --git a/tests/boundary/process/agentenvVerifierIdentity.test.ts b/tests/boundary/process/agentenvVerifierIdentity.test.ts index c6cf96541c..ecbd82353b 100644 --- a/tests/boundary/process/agentenvVerifierIdentity.test.ts +++ b/tests/boundary/process/agentenvVerifierIdentity.test.ts @@ -29,7 +29,7 @@ it.skipIf(process.platform === "win32")( ); await writeFile( runner, - "#!/usr/bin/env node\nprocess.stdout.write('agent-env 0.9.1334\\n');\n", + "#!/usr/bin/env node\nprocess.stdout.write('agent-env 0.9.1431\\n');\n", { mode: 0o755 }, ); await writeFile(docker, "#!/usr/bin/env node\nprocess.exit(0);\n", { @@ -70,8 +70,8 @@ it.skipIf(process.platform === "win32")( // The local framework and these executable shebang fixtures target POSIX hosts. it.skipIf(process.platform === "win32").each([ ["agent-env 0.9.9999", false], - ["other-runner 0.9.1334", false], - ["agent-env 0.9.1334", true], + ["other-runner 0.9.1431", false], + ["agent-env 0.9.1431", true], ] as const)( "admits the observed executable identity %s before Docker: %s", async (version, accepted) => {