Repository navigation
fix(compose): harden agent registration - #1602
Merged
Cedric Vidal (cedricvidal) merged 1 commit intoNov 5, 2026
Merged
Conversation
Test Results (Node.js 22)test: Run #443
🎉 All tests passed! |
Test Results (Node.js 22)test: Run #452
🎉 All tests passed! |
Cedric Vidal (cedricvidal)
requested a review
from Wassim Chegham (manekinekko)
November 4, 2026 01:57
6 tasks done
Test Results (Node.js 22)test: Run #460
🎉 All tests passed! |
Test Results (Node.js 22)test: Run #477
🎉 All tests passed! |
Base automatically changed from
cedricvidal-reproduce-copilot-stack-issue
to
main
November 5, 2026 00:37
Use the pinned yq image and BusyBox wget for bounded, non-root agent registration without runtime package installation. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Cedric Vidal (cedricvidal)
force-pushed
the
cedricvidal-harden-agent-registration
branch
from
November 5, 2026 00:37
cabf646 to
c9128f6
Compare
Cedric Vidal (cedricvidal)
marked this pull request as ready for review
November 5, 2026 00:37
Test Results (Node.js 22)test: Run #493
🎉 All tests passed! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
register-agentsruntime package installation with the audited multi-architecturemikefarah/yq4.54.1 OCI index pinned exactly asdocker.io/mikefarah/yq:4.54.1@sha256:4b3d9475d65571d28cbb19544d3820ec2945e4c8b2f18279394282b8dc3a592e.scripts/register-agent.shdeliberately for BusyBoxwget,timeout, and--post-filewhile preserving API readiness, exact JSON POST bytes, response/diagnostic capture, bounded retry/backoff, permanent-error fail-fast behavior, and nonzero failure.no-new-privileges, a 1 MiB/tmptmpfs, and read-only script/manifest mounts.docs/architecture/worker-requirements.mdwith the runtime contract, reviewed-image rationale, and residual security limitations.Problem
register-agentspreviously started from Alpine and ranapk add --no-cache curl yq > /dev/null 2>&1at runtime. Package-repository or network failures were therefore hidden, left the registration helper without its required tools, and caused the one-shot registration service to fail. Every scheduler/worker service that depends on successful agent registration then remained blocked even though the API and backing infrastructure were otherwise healthy.This change removes package repositories from the startup critical path. The digest-pinned
mikefarah/yqimage already contains/usr/bin/yq, BusyBox/bin/sh,/usr/bin/wget,/usr/bin/timeout, and CA certificates. The helper posts payloads from temporary JSON files withContent-Type: application/json, uses a hard total deadline around wget, and parses the finalwget -SHTTP status so redirect chains cannot be misclassified. HTTP 408/425/429/5xx outcomes and transport failures without a completed response retry with bounded exponential backoff; permanent 4xx responses fail immediately with the response body when available or a bounded diagnostic tail otherwise. A transfer that fails after receiving a 2xx/3xx header is treated as incomplete and retried rather than reported as success.The reviewed upstream image is unsigned and has no authoritative signed image SBOM. Alpine musl 1.2.6-r2 and zlib 1.3.2-r0 have known High CVEs; the documented residual assessment accepts them for this static one-shot workload because the yq binary is CGO-disabled and the vulnerable paths are not exercised by manifest conversion or the trusted registration flow. No existing internal SBOM/vulnerability scanner was found in the repository/toolchain, so this PR does not add a new scanner dependency or external service solely for scanning.
This is layer 2 of the native PR stack. It remains a draft dependent on #1601 with base
cedricvidal-reproduce-copilot-stack-issueand headcedricvidal-harden-agent-registration. The current headbe95df38c8325b05124f386695952d46a7aeedf8includes the updated lower-layer tipe5b43c0aae8eea21e40bd782cf7cbf74886ec6eethrough a normal merge.Demos
N/A — this changes local Compose startup infrastructure and has no user-visible Portal/CLI UI.
Before
N/A
After
N/A
Testing
pnpm exec vitest run scripts/register-agent.test.ts --reporter=default— PASS, 18/18 tests. Coverage includes 2xx, permanent 4xx, 408/425/429, 5xx, redirects/final status, DNS and connection failure, hard timeout, interrupted transfer after a response header, response diagnostics, availability override, URL validation, and exact--post-fileJSON bytes.sh -n scripts/register-agent.sh && git diff --check— PASS, shell syntax and whitespace validation completed with exit code 0.scripts/worktree-env.sh >/dev/null && scripts/dev-compose.sh -f docker-compose.yml -f docker-compose.dev.yml --profile copilot --profile claude-code config --quiet— PASS, merged production/development Compose configuration is valid.scripts/worktree-env.sh >/dev/null && scripts/dev-compose.sh -f docker-compose.yml -f docker-compose.dev.yml --profile copilot --profile claude-code config --format json | jq '{image: .services["register-agents"].image, user: .services["register-agents"].user, read_only: .services["register-agents"].read_only, cap_drop: .services["register-agents"].cap_drop, security_opt: .services["register-agents"].security_opt, tmpfs: .services["register-agents"].tmpfs, volumes: .services["register-agents"].volumes}'— PASS, confirmed the exact digest, no Compose user override,read_only: true,cap_drop: [ALL],no-new-privileges:true, 1 MiB/tmptmpfs, and read-only mounts.docker run --rm --entrypoint /bin/sh docker.io/mikefarah/yq:4.54.1@sha256:4b3d9475d65571d28cbb19544d3820ec2945e4c8b2f18279394282b8dc3a592e -c 'id; command -v yq; command -v wget; command -v timeout; wget --help 2>&1 | head -40; timeout --help 2>&1 | head -20'— PASS, confirmed UID/GID 1000 and the required yq, wget, and timeout binaries.docker run --rm --read-only --cap-drop ALL --security-opt no-new-privileges --tmpfs /tmp:size=1m,mode=1777 -v "$PWD/apps/workers:/workers:ro" -v "$PWD/scripts/register-agent.sh:/register-agent.sh:ro" --entrypoint /bin/sh docker.io/mikefarah/yq:4.54.1@sha256:4b3d9475d65571d28cbb19544d3820ec2945e4c8b2f18279394282b8dc3a592e /register-agent.sh http://host.docker.internal:18080 /workers/coder-acp-copilot/agent.yaml --available false /workers/coder-acp-copilot/agent-version.dev.yaml— PASS, exact pinned-image health, agent POST, and version POST flow completed under the production hardening flags.SCOPE_REGISTRATION_MAX_ATTEMPTS=1— PASS, exited 1 and reported the final BusyBox wgetHTTP/1.1 422diagnostic when wget did not expose the response body.pnpm headers:check— PASS, all 965 in-scope files have the Microsoft MIT license header after synchronizing the lower layer.41752659313atbe95df38c8325b05124f386695952d46a7aeedf8— PASS. License Headers, Third-party NOTICE, detect-changes, Unit Tests (22), Lint Code, Build Applications, CLI Bundle Integration Tests, and CI Summary succeeded; non-applicable integration, gateway, LLM-eval, and Windows jobs were skipped. Secret Scan run41752659748, PR Labeler run41752659467, gitleaks, andlicense/claalso passed.Documentation and compatibility
Updated
docs/architecture/worker-requirements.mdwith the BusyBox wget retry/deadline behavior, final-status and incomplete-transfer handling, hardened Compose runtime, exact reviewed image digest, and residual signature/SBOM/CVE limitations.No API, CLI, manifest, or registration endpoint compatibility changes. Existing retry environment variables remain supported. Runtime startup no longer depends on Alpine package repositories. The service remains non-root and receives no Docker socket, credentials, or additional host mounts.
Checklist
up()/down()and keep it CosmosDB-compatible. — N/A, no database changes.NOTICE/NOTICE-REVIEW.txtwithpnpm noticeas needed. — N/A, no dependency changes.