Skip to content

Add Docker validation lab - #1179

Merged
burtenshaw merged 12 commits into
mainfrom
ben/rfc008-l2-02-docker
Sep 22, 2026
Merged

burtenshaw merged 12 commits into
mainfrom
ben/rfc008-l2-02-docker

Conversation

@burtenshaw

Copy link
Copy Markdown
Collaborator

This PR adds the Docker validation lifecycle and a pinned reproduction lab with shared fixtures and retained CI evidence. Builds on #1178; second of three stacked PRs tracked in #1177.

@burtenshaw
burtenshaw added this pull request to stack #1183 September 16, 2026 10:17
Comment thread src/openenv/validation/providers/docker.py Fixed
Comment thread src/openenv/validation/providers/docker.py Fixed
Comment thread src/openenv/validation/providers/docker.py Fixed
Comment thread src/openenv/validation/providers/docker.py Fixed
Comment thread scripts/validation/reproduce.py Fixed
Comment thread scripts/validation/reproduce.py Fixed
Comment thread src/openenv/validation/providers/__init__.py
Comment thread src/openenv/validation/providers/__init__.py
Comment thread src/openenv/validation/providers/__init__.py
Comment thread src/openenv/validation/providers/__init__.py
@hf-security-analysis

hf-security-analysis Bot commented Sep 16, 2026

Copy link
Copy Markdown
Contributor

✅ Workflow security review — no issues

Scanned 1 workflow file(s) with zizmor, pinact, OSV/GHSA, Claude, in full.

@burtenshaw burtenshaw added feature size: extra-large Extra-large pull request labels Sep 16, 2026 — with Cursor
@burtenshaw burtenshaw mentioned this pull request Sep 16, 2026
13 tasks

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alignment Review Report

Scope: PR diff 5a0b6bd…e79560c — the L2-02 "Docker validation lab" slice, stacked on the L2-01 contracts PR. Reviewed against .claude/docs/PRINCIPLES.md, .claude/docs/INVARIANTS.md, and the open RFCs. manifest.py, runtime/contracts.py, and the JSON schemas are out of scope here — they belong to the base (contracts) PR.

Automated Checks

  • Lint: PASS (for this PR). Every file this PR changes passes ruff format --check, ruff check, and usort check (pinned ruff 0.16.7 / usort 1.1.3). I also ran ruff over scripts/validation/*.py (which lint.sh does not cover) — clean.
    • bash .claude/hooks/lint.sh reports "57 files would be reformatted", but all 57 are pre-existing drift under envs/** and **/README.md — none are touched by this PR. This is base-branch/tooling drift, not introduced here.
  • Debug code: CLEAN. check-debug.sh surfaces no new prints/TODOs/breakpoints in this PR's src/ files (the listed prints are all pre-existing modules; scripts/validation/reproduce.py prints are legitimate CLI output and check-debug.sh only scopes src/).
  • Tests: PASS. 47 PR unit tests green (test_docker_provider, test_reproduction, test_protocols, test_served_probe). The real-Docker suite is correctly gated behind @pytest.mark.docker and skips without an engine.

Open RFCs Context

  • RFC 008 — Environment Auto-Validation (In Review, @zkwentz). This PR implements the "Level 2 execution amendment" (Docker-local reproducible-supervision slice). Directly relevant.
  • RFC 000–005 (In Review; @Darktex et al.) are foundational; RFC 010/011 (Draft; @thegovind) are unrelated to validation.

Tier 1: Fixes Required

  • None. No mechanical bugs, missing imports, type errors, or security issues found. The provider is unusually defensive: bounded stdout/stderr draining, process-group SIGKILL on timeout, symlink-race-safe source snapshotting (O_NOFOLLOW, descriptor-relative opens), and thorough credential redaction.

Tier 2: Alignment Discussion

Principle Conflicts

None identified. The change actively reinforces two invariants worth calling out:

  • Container isolation (INVARIANTS.md → "Container isolation"): subjects run non-root (65532), read-only rootfs, --cap-drop ALL, no-new-privileges, pids/memory/swap ceilings, loopback-only publish (127.0.0.1::8000), and image-declared bind/volume mounts are rejected before start (docker.py ~L274–318). No host mounts, docker socket, or host namespaces.
  • No credential exposure (INVARIANTS.md → "No credential exposure"): all provider output is redacted (_safe_text/_TOKEN, docker.py L47–65), inspect() deliberately omits container env/command/host paths (L386–416), host env is never forwarded (LaunchSpec.env_vars only; the lab also pops PYTHONPATH), and CI sets persist-credentials: false + permissions: contents: read.

(Also consistent with the dual-API boundary: the collector drives reset/step/state over /ws as orchestration, agent_boundary: api — not agent-facing — so "agents cannot reset" is not implicated.)

RFC Conflicts

ALIGNMENT FLAG: Implements an amendment to an RFC that is still In Review

  • Principle/RFC at stake: RFC 008 (Status: In Review). The "Level 2 execution amendment" being implemented (manifest schema 2 validation.execution, the public probe sidecar, LaunchSpec, the provider protocol, the reproducibility lab) was added to RFC 008 by the PR author (@burtenshaw), on an RFC authored by @zkwentz.
  • The concern: This is not a technical conflict — the code tracks the amendment closely (public-only networking with named UnsupportedCapability refusals for no-network/allowlist/GPU; disk_mb split across /tmp + /dev/shm; idempotent owner-verified cleanup; the README/RFC caveat that one successful build ≠ static.reproducible_build). The flag is process: an In-Review RFC whose amendment is written by the implementer should get explicit sign-off that the amendment reflects consensus before/with merging its implementation. Per the review guidance, flagging this focuses the design discussion — the code may be right and the RFC simply needs to move to Accepted.
  • Suggested reviewer: @zkwentz (RFC 008 author), @Darktex (owner of the container-isolation & credential invariants this slice leans on)

Minor (non-blocking) — provider-contract churn inside the stack

  • The ValidationProvider Protocol's start() is rewritten here from the L2-01 shape start(image_ref, *, network, env_vars) to start(spec: LaunchSpec), and build / supported_network_modes / inspect / logs are added (providers/__init__.py). Since LaunchSpec already lands in L2-01 (runtime/contracts.py), reviewers may prefer the contracts PR define the final start(spec) shape so the very next PR in the stack doesn't immediately supersede it. No released API is affected (the whole stack is unmerged), so this is purely a stacking-hygiene call.
  • Suggested reviewer: @zkwentz

Summary

  • 0 mechanical issues to fix (Tier 1)
  • 1 alignment point for human review (RFC 008 amendment consensus), +1 minor stacked-interface nit
  • 0 hard RFC conflicts — the implementation aligns with the RFC 008 Level 2 amendment
Open in Web View Automation 

Sent by Cursor Automation: Pre-review

Comment thread src/openenv/validation/providers/docker.py Outdated
burtenshaw pushed a commit that referenced this pull request Sep 16, 2026
Co-authored-by: hf-security-analysis[bot] <265538906+hf-security-analysis[bot]@users.noreply.github.com>
@bot-ci-comment

Copy link
Copy Markdown

The docs for this PR live here. All of your documentation changes will be reflected on that endpoint. The docs are available until 30 days after the last update.

@burtenshaw
burtenshaw force-pushed the ben/rfc008-l2-02-docker branch from f56bc0c to e860f5a Compare September 21, 2026 12:31
@cursor cursor Bot mentioned this pull request Sep 21, 2026

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exact-head CI is red on the same inherited failure as #1178: test_write_report_validation_report_only (annotation is now ValidationReport | ValidationReportV2). Fix lands in #1178; please rebase this stack after that greens. Holding deeper review until then.

View PR

Open in Web View Automation 

Sent by Cursor Automation: Release

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exact-head CI is green at 229faafe after the #1178 annotation fix. Holding a full Docker-lab deep review for a follow-up pass; no new Tier-1 from a quick scan. Not Thursday 0.6.0 cargo.

View PR

Open in Web View Automation 

Sent by Cursor Automation: Release

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Autofix Details

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Wheel download omits newer manylinux tags
    • Added the supported manylinux_2_34 target so pip selects hash-pinned native Linux wheels such as caio instead of generic fallbacks.

Create PR

Or push these changes by commenting:

@cursor push ca2759bf2a
Preview (ca2759bf2a)
diff --git a/scripts/validation/reproduce.py b/scripts/validation/reproduce.py
--- a/scripts/validation/reproduce.py
+++ b/scripts/validation/reproduce.py
@@ -228,6 +228,8 @@
             "--implementation",
             "cp",
             "--platform",
+            f"manylinux_2_34_{arch}",
+            "--platform",
             f"manylinux_2_28_{arch}",
             "--platform",
             f"manylinux2014_{arch}",

You can send follow-ups to the cloud agent here.

Comment thread scripts/validation/reproduce.py Outdated

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

REQUEST_CHANGES at 60a96a68

New commit correctly strips uv’s wheel/.gitignore before checksumming (including failed builds). That does not address the open Medium: pip download still targets only manylinux_2_28, manylinux2014, and linux, so newer compatible tags (e.g. manylinux_2_34) can still yield an incomplete wheelhouse on a capable 3.12 slim image.

Expand the platform list from actual runtime compatibility, or download inside the target image, and add a native-wheel regression. Holding approval until that lands (exact-head CI still running).

Open in Web View Automation 

Sent by Cursor Automation: Release

Comment thread scripts/validation/reproduce.py Outdated
Base automatically changed from ben/rfc008-l2-01-contracts to main September 21, 2026 13:21
@burtenshaw
burtenshaw force-pushed the ben/rfc008-l2-02-docker branch from 60a96a6 to ff5c113 Compare September 21, 2026 13:21

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.

There are 3 total unresolved issues (including 1 from previous review).

Autofix Details

Bugbot Autofix prepared fixes for both issues found in the latest run.

  • ✅ Fixed: Secret filter excludes source modules
    • Restricted secret-name filtering to extensionless credential names so dotted source modules remain in Docker snapshots.
  • ✅ Fixed: Diff checksum uses sanitized output
    • The diff checksum now hashes the command's complete raw stdout through a temporary file without redaction, truncation, decoding, or stripping.

You can send follow-ups to the cloud agent here.

Comment thread src/openenv/validation/providers/docker.py
Comment thread scripts/validation/reproduce.py Outdated

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

REQUEST_CHANGES at ff5c113e (Bugbot refresh after #1178 rebase)

Still open (Medium): incomplete manylinux platform set for pip download.

New Medium: _SECRET_NAME excludes source modules named secret.py / credentials.py from the build snapshot.

Low (Bugbot): diff_sha256 hashes sanitized git diff output — integrity of the lab evidence can drift from the true diff. Prefer hashing raw bytes before redaction (or hash outside the secret filter).

Bugbot autofix is active. Not Thursday 0.6.0 cargo.

Open in Web View Automation 

Sent by Cursor Automation: Release

Comment thread scripts/validation/reproduce.py Outdated
Comment thread src/openenv/validation/providers/docker.py

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

REQUEST_CHANGES at 30460b0e (autofix progress)

Fixed this head:

  • _SECRET_NAME no longer matches secret.py / credentials.py (extension-bearing source kept; bare secret/secrets/credentials still excluded) — with regression.
  • diff_sha256 now hashes complete unsanitized git diff bytes via command_digest — with regression.

Still open (Medium): incomplete manylinux platform set for wheel download.

Holding approval for that. Exact-head CI in flight. Not Thursday 0.6.0 cargo.

Open in Web View Automation 

Sent by Cursor Automation: Release

Comment thread scripts/validation/reproduce.py Outdated
@burtenshaw

burtenshaw commented Sep 21, 2026

Copy link
Copy Markdown
Collaborator Author

Addressed 17 review threads, including the follow-up credential-filter findings; all 20 threads on this PR are now resolved. Final head f6371c00827eb098d486fac00a3b32b959a63fcb passes all 12 checks, including both Python test jobs, Linux Docker validation, and Bugbot.

The fixes derive wheel compatibility from the pinned target image, preserve timeout causes during failed cleanup, and match the importer's complete credential-filename policy while retaining bare source modules such as secret.py and credentials.py. Regression coverage exercises real offline pip selection and actual snapshot contents; the Linux validation job also verified and retained its evidence. Intentional Protocol declarations and string concatenation are explained in their review threads.

The earlier stack-interface nit is obsolete now that #1178 is merged. RFC 008 remains In Review; amendment consensus is still a maintainer decision.

Comment thread scripts/validation/reproduce.py

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

APPROVE @ cd28610f

Prior Medium manylinux gap is fixed: download_linux_wheels now pulls the target base image and asks host pip download for that image’s platform_tags() (so newer tags like manylinux_2_34_* are included). Parametrized native-wheel regressions cover amd64/arm64 × 2.31/2.34/2.39 success and 2.40 fail-closed.

Also verified on this head:

  • _command return annotation/tuple explicit; ProcessLookupError handlers documented
  • exec-timeout cleanup preserves the original timeout when stop verification fails (new regression)
  • prior secret-name + exact diff_sha256 fixes still present

Local: 36 passed on test_docker_provider.py + test_reproduction.py.

Nits (non-blocking): CodeQL implicit string concat in the python -c probe; snapshot still won’t exclude credentials.json / secrets.yaml by basename (only bare credentials/secrets and .pem/.key).

Not Thursday 0.6.0 cargo until merged; if it lands before the cut, refresh #1211 / TestPyPI.

View PR

Open in Web View Automation 

Sent by Cursor Automation: Release

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

APPROVE @ dfb463a2

Reconfirm after test-only follow-up: test_wheel_download_uses_target_image_compatibility now importorskip("pip") so hosts without the runtime-lab pip skip cleanly. Manylinux/platform_tags() fix from cd28610f unchanged.

Local: 8/8 compatibility regressions pass with pip present.

Not Thursday 0.6.0 cargo until merged.

View PR

Open in Web View Automation 

Sent by Cursor Automation: Release

@burtenshaw

Copy link
Copy Markdown
Collaborator Author

Addressed the credential-filename nit in 7656c56: the snapshot again excludes credentials.json and secrets.json, secrets.toml, secrets.yaml, and secrets.yml, matching the existing importer's exact list. Case-insensitive regression coverage confirms those files are omitted while secret.py and credentials.py remain in the snapshot. The 37 provider/reproduction tests and touched-file lint pass. Also refreshed from current main; watching CI on the updated head.

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

APPROVE at 7b383985

7656c565 closes the residual credential-filename nit: _SECRET_NAME now excludes credentials.json and secrets.{json,toml,yaml,yml} (case-insensitive) while still keeping secret.py / credentials.py. Parametrized snapshot regression covers both cases.

Also synced onto main after #1219. Prior manylinux/platform_tags() fix unchanged.

Local: 37 passed on docker provider + reproduction suites.

Not Thursday 0.6.0 cargo until merge; if it lands, refresh #1211 / TestPyPI.

View PR

Open in Web View Automation 

Sent by Cursor Automation: Release

@burtenshaw
burtenshaw force-pushed the ben/rfc008-l2-02-docker branch from f6371c0 to 37c7e44 Compare September 22, 2026 10:13

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Saw the rebase onto main 43aa7528 at 37c7e44f. Feature content still carries the approved credential snapshot filter (_SECRET_NAME + regressions). Exact-head CI is re-running — will re-APPROVE once green.

Not Thursday 0.6.0 package cargo unless you explicitly want L2 lab in the cut.

View PR

Open in Web View Automation 

Sent by Cursor Automation: Release

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Docker parses mixed stderr as data
    • Docker probe calls now drain stderr separately so architecture and JSON parsing receives only stdout.

You can send follow-ups to the cloud agent here.

Reviewed by Cursor Bugbot for commit 37c7e44. Configure here.

Comment thread scripts/validation/reproduce.py Outdated

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-APPROVE at 37c7e44f (rebase onto main 43aa7528)

Exact-head repository CI green, including Runtime validation / Linux Docker. Feature content for the Docker lab / credential snapshot filter matches the prior APPROVE at f6371c00 (_SECRET_NAME + regressions intact).

Bugbot medium (non-blocking): scripts/validation/reproduce.py run() still merges stderr into stdout for docker info / platform-tag JSON parses. Same helper was present on the previously approved tip; pull is already split out to avoid progress contamination. Worth a follow-up hygiene fix, not a merge gate — Autofix is in flight if you want it landed first.

Not Thursday 0.6.0 package cargo unless you explicitly fold L2 lab into the cut. Stacked #1181 still needs a conflict-free refresh onto this tip.

View PR

Open in Web View Automation 

Sent by Cursor Automation: Release

@cursor
cursor Bot force-pushed the ben/rfc008-l2-02-docker branch from 6e36285 to 1c4932f Compare September 22, 2026 10:25

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Autofix landed at 6e362856 (separate_stderr=True for docker info / platform-tag JSON probes). Looks sound on read — watching exact-head CI before re-APPROVE.

View PR

Open in Web View Automation 

Sent by Cursor Automation: Release

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tip advanced to e1e3ccf9 (fix: isolate command stdout) — always separates stderr, returns stdout only, with regression coverage for warning contamination + secret redaction. Better than the Autofix flag. Watching exact-head CI before re-APPROVE.

Note: stacked #1181 is currently based on 1c4932f2 (one commit behind this tip).

View PR

Open in Web View Automation 

Sent by Cursor Automation: Release

Comment thread tests/test_validation/test_reproduction.py
Comment thread tests/test_validation/test_reproduction.py
Comment thread tests/test_validation/test_reproduction.py
Comment thread tests/test_validation/test_reproduction.py

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-APPROVE at e1e3ccf9

Exact-head CI green (incl. Runtime validation / Linux Docker + Bugbot). run() now always isolates stderr and returns stdout only, with solid regressions for warning contamination, redaction, oversized dual-stream drain, failures, and timeouts.

Credential snapshot filter (_SECRET_NAME) still intact from earlier tips.

Non-blocking: CodeQL flags intentional adjacent string literals in the new -c test scripts — style only; no behavior risk.

Not Thursday 0.6.0 package cargo unless you fold L2 lab into the cut. Stacked #1181 still wants a base refresh onto this tip (e1e3ccf9 vs its 1c4932f2).

View PR

Open in Web View Automation 

Sent by Cursor Automation: Release

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature size: extra-large Extra-large pull request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants