Phase B remainder: daemon scoping, limits identity, staging tests, attestation, CI image - #40
Conversation
…ing tests, attestation, CI image - DOCKER_HOST only for docker spawns, never plugin inheritance. - RuntimeDescriptor carries container limits (digest-covered). - package_file/entrypoint confinement tests (traversal, symlink, absolute path). - or_audit.eval.attestation: HMAC stamp + verify contract for hosted executor (minting lives in cloud tree). - plugin-image.yml: CI builds sandbox image, live-tests backend digest-pinned.
|
Droid finished @txmed82's task —— View job This PR tightens sandbox execution and adds CI coverage for the digest-pinned container path. The main risks are (1) the workflow’s digest resolution can produce |
| DIGEST=$(docker images --digests --format '{{.Repository}}@{{.Digest}}' | grep '^localhost:5000/surgeval-plugin@' | head -n 1) | ||
| test -n "$DIGEST" | ||
| echo "value=$DIGEST" >> "$GITHUB_OUTPUT" | ||
| echo "Sandbox image: $DIGEST" >> "$GITHUB_STEP_SUMMARY" |
There was a problem hiding this comment.
[P1] Ensure CI resolves a real image digest
docker images --digests can yield localhost:5000/surgeval-plugin@<none> even after a push, which is non-empty but fails the SURGEVAL_TEST_PLUGIN_IMAGE=image@sha256:... contract that the live backend test enforces; resolve the pushed image’s RepoDigest via docker inspect and validate it’s @sha256: before exporting.
| DIGEST=$(docker images --digests --format '{{.Repository}}@{{.Digest}}' | grep '^localhost:5000/surgeval-plugin@' | head -n 1) | |
| test -n "$DIGEST" | |
| echo "value=$DIGEST" >> "$GITHUB_OUTPUT" | |
| echo "Sandbox image: $DIGEST" >> "$GITHUB_STEP_SUMMARY" | |
| DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' localhost:5000/surgeval-plugin:ci) | |
| case "$DIGEST" in | |
| localhost:5000/surgeval-plugin@sha256:*) ;; | |
| *) echo "Unexpected RepoDigest: $DIGEST" >&2; exit 1 ;; | |
| esac | |
| echo "value=$DIGEST" >> "$GITHUB_OUTPUT" | |
| echo "Sandbox image: $DIGEST" >> "$GITHUB_STEP_SUMMARY" |
There was a problem hiding this comment.
Addressed in this branch: digest resolved via docker inspect RepoDigests with @sha256: validation; container limits clamped executor-side (64m..16g, 0.1..16, 16..4096) with refusal tests.
| sandbox_policy_digest: str = "" | ||
| #: Container resource envelope, part of the digest-covered identity so a | ||
| #: run cannot claim different limits than it executed under (B4). | ||
| container_memory: str = "2g" |
There was a problem hiding this comment.
[P1] [security] Validate container limits from untrusted packages
RuntimeDescriptor is loaded from agent.toml, so untrusted submissions can now set container_memory/container_cpus/container_pids_limit to values that disable or greatly expand resource caps (for example container_pids_limit="-1"), enabling host DoS when the container runtime is used; enforce these limits via trusted policy (clamp/validate to safe ranges, or require they match executor-configured limits) before passing them into docker run.
There was a problem hiding this comment.
Addressed in this branch: digest resolved via docker inspect RepoDigests with @sha256: validation; container limits clamped executor-side (64m..16g, 0.1..16, 16..4096) with refusal tests.
There was a problem hiding this comment.
Already implemented in this branch: _clamp_container_limits is invoked in _container_command (plugins.py) with executor-side bounds and refusal tests. No change made.
What: closes the review gaps — DOCKER_HOST scoped to container spawns; container limits in digest-covered identity; confinement tests; HMAC attestation contract (OSS verify side); CI builds + live-tests the sandbox image digest-pinned.
Why: limits outside identity, CI-skipped container test, untested staging checks, and absent B5 contract.
Verify: full suite green; ruff + format + mypy clean; live container test passes locally digest-pinned. CI + review pending. Remaining B5: cloud executor minting (private tree).