Repository navigation
Conversation
Each docker run call site spelled its own --network and hardening flags. Task containers bypassed ContainerPolicy with a module constant. ContainerPolicy and docker_cmd.run_spec(policy, layout, image, command) now build the argv for the repo container, the example runner, the fidelity capture and the solver's task container. A layout names the flag groups in call order, so every argv keeps its order. Behaviour is unchanged. tests/test_docker_run_argv_differential.py replays the grid of inputs through the public entry points and compares the argv byte for byte with tests/fixtures/docker/run_argv_golden.json, captured from the base commit. Out of scope: network_policy.build_args still passes proxy values inline as --build-arg NAME=value, and sidecar create calls stay inline. Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
There was a problem hiding this comment.
🟢 Approval recommended
No active review issues were identified for the shared Docker argument-builder refactor.
No open issues 🎉
What changed in this PR
0 new findings; nothing to fix.
This PR centralizes Docker run argument construction in docker_cmd.run_spec, using ContainerPolicy flag groups while preserving each caller’s existing argument order.
Changes:
- Migrates repository containers, example execution, fidelity capture, and task containers to the shared builder.
- Adds capability groups and task-container policy defaults; changes network selection to return a network name.
- Adds golden argument fixtures and differential tests to check byte-for-byte compatibility.
| File | Description |
|---|---|
dokimi/tests/test_docker_run_argv_differential.py |
Adds cross-caller argument comparisons against golden fixtures. |
dokimi/tests/test_container_policy.py |
Tests capability flags, resource values, and named groups. |
dokimi/tests/fixtures/docker/run_argv_golden.json |
Records expected arguments and errors for the input grid. |
dokimi/dokimi/repos/container.py |
Uses the shared builder for repository containers. |
dokimi/dokimi/metrics/example_runner.py |
Uses the shared builder for Docker-backed examples. |
dokimi/dokimi/harnesses/network_policy.py |
Returns the starting network name instead of flags. |
dokimi/dokimi/harnesses/fidelity.py |
Uses shared run and environment argument builders. |
dokimi/dokimi/harnesses/docker_solver.py |
Builds task-container arguments from policy and ordered groups. |
dokimi/dokimi/harnesses/container_agent.py |
Uses policy-generated sandbox network flags. |
dokimi/dokimi/docker_cmd.py |
Adds the shared run_spec argument builder. |
dokimi/dokimi/container_policy.py |
Adds named flag groups, capabilities, and task-container defaults. |
Review effort: Balanced
|
OpenCodeReview: Commit f57fd1a was not reviewed. This PR has reached its review limit (6 reviews). CI at `f57fd1a`: 15 still running, 6 passing, 2 skipped
5 more not listed. To review this commit: re-request review from exai-bot in the Reviewers list. <details><summary>Last review (6e42b32): no findings</summary> Open threads from the bot: 0 </details> |
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #623 +/- ##
=======================================
Coverage 95.71% 95.72%
=======================================
Files 415 415
Lines 55346 55373 +27
Branches 9514 9512 -2
=======================================
+ Hits 52977 53004 +27
Misses 1466 1466
Partials 903 903
🚀 New features to boost your workflow:
|
vlad-perevezentsev
left a comment
There was a problem hiding this comment.
Review at 8cc918b. The refactor keeps every docker run argv as it was, and the real launch confirms it. What is left is small: one stale doc name, one argv part the golden does not pin, and some cleanups, all in the line comments.
What I ran, at 8cc918b:
make ci-local --offline: 18,397 passed, 0 failed, 72 skipped. The only FAIL is the changelog fragment check, which does not see theskip-changeloglabel.- The differential test and its golden against the merge-base
ead342e: it passes, so the golden is the base output. - CI's
external-catalog-smoke(docker-oracle and docker-probe ononetbb-histogram-local-aggregation): 1/1 pass each, every isolation probe closed. The task container started with the same flags in the same order as before, both onbridgeand inside the egress sandbox. - A mutation that moves the task container's
-eflags after the image: all 515 tests in the docker, container, network-policy and tbench files still pass (see the line comment).
Checked, no issues
- Call sites: the repo container, the example runner, the fidelity client and the task container build the same flags in the same order as on the base;
memory=f"{mem_mb}m"cannot get aNone, because_run_dockerreturns before it whenmem_mbis unset. bridged:network == "bridge"gives the same answer as"bridge" in net_argswith and without a sandbox;test_network_policy.pyfails if it is broken.- Removed names: nothing in the tree or on current
mainstill importsTASK_CONTAINER_HARDENING,start_args,docker_cmd.PIDS_LIMITormemory_mb=; no call builds aContainerPolicyby position, so the newcap_addfield moves nothing. - Changelog: no fragment, under
skip-changelog; that fits, since no argv changes and the removed names are internal.
|
|
||
| A layout item is either the name of a :class:`ContainerPolicy` group (``"init"``, ``"hardening"``, | ||
| ``"network"``, ...), or an argv list already spelled: :func:`mount_args`, :func:`env_args`, or | ||
| the caller's own flags (``["--rm"]``, ``["--entrypoint", ""]``). A bare string is always a group | ||
| name, so a flag is never written bare. Each caller lists its groups in the order its argv has |
There was a problem hiding this comment.
Nit: Question: once this lands, does each call site still need its own flag order?
Docker does not care about the order of options before the image. The layouts, the group names and the split of hardening into security / cap_drop exist only to keep four old orders byte-identical. With one fixed group order in run_spec (then the caller's own flags), a later change could drop the layouts, at the cost of one golden refresh.
There was a problem hiding this comment.
Keeping the per-call-site layouts in this PR: the golden pins each argv's flag order, and dropping the order changes every key. With the refresh script that is cheap as a follow-up, which I will open once this lands.
Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com> # Conflicts: # dokimi/dokimi/repos/container.py
coding-harnesses.md named TASK_CONTAINER_HARDENING in docker_cmd.py, which this refactor removed. The test checks the prose for the removed name, since the code-ref check only reads code spans. Thread: PRRT_kwDOVBg7g862m5Jm Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
The sidecar still spells --network inline, and the module holds the task container's defaults, so the docstring says both. Docstring only. Thread: PRRT_kwDOVBg7g862m5J0 Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
run_spec took any str as a group name and raised KeyError only on the path that ran it. ContainerPolicy.group now takes the Group Literal, run_spec's layout is Iterable[Group | list[str]], and the call sites that build a layout annotate it, so mypy checks every name. Thread: PRRT_kwDOVBg7g862m5KG Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
…licy The repo container's four hardening fields were spelled twice: in DockerRunner.argv and in task_container_policy. repo_container_policy(network) now holds them; task_container_policy is that policy plus the task's capabilities, cpus and memory, and DockerRunner.argv uses repo_container_policy. Argv unchanged. Thread: PRRT_kwDOVBg7g862m5J9 Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
…work The solver passed the policy network=None and the sandbox's run_args added --network, so the policy did not hold the container's real network. The policy now takes sandbox.network; run_args returns the label and tmpfs only. The task/sandboxed argv is unchanged; the sandbox/run_args golden entry loses the --network pair it no longer returns. Thread: PRRT_kwDOVBg7g862m5Ju Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
The golden had no refresh path, so a planned argv change meant editing a 3,000-line JSON by hand. scripts/refresh_docker_run_golden.py replays the differential grid and writes the golden; a refactor leaves the file byte-identical. The test checks that a re-take reproduces the committed file. Thread: PRRT_kwDOVBg7g862m5Js Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
No grid case had container_env, so moving the -e flags after the image kept every test green while the container exited at once. The grid adds a terminal-bench task (its TEST_DIR and GREETING come from compose), a test asserts every argv that carries TEST_DIR puts it before the image, and the golden is re-taken with scripts/refresh_docker_run_golden.py: 38 added lines, none changed. Thread: PRRT_kwDOVBg7g862m5Je Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
The task policy spells --network from sandbox.network, so the sandbox's run_args no longer carries it, and the layout takes the network once. Folds the split test back to the main line count and drops two blank lines in _start_container so both files sit at the growth baseline. Thread: PRRT_kwDOVBg7g862m5Ju Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
…den script The Removed fragment lists the docker builder names that moved, since the package's importable names changed. deptry flags the refresh script's import of the grid in tests/, so the ignore lists that module, as audit_mocks is. Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
|
Round 5 is pushed at a357159 (8cc918b..a357159).
|
Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
vchamarthi
left a comment
There was a problem hiding this comment.
Review at e5379c3. 2 new findings: 1 must-fix, 1 nit. In the line comments. The change moves every docker run argv the package builds onto one run_spec builder over ContainerPolicy, and the argv stays byte-identical in the tested grid. The changelog fragment's list of removed importable names omits five names this PR removes or renames.
Verified
- Argv byte identity: On
e5379c3the argv for every tested input, including repo, example and fidelity, is byte-for-byte identical to main's, and the golden refresh script's output matches the committed golden. - Task env pinning: The
-eflags of the task start indokimi/dokimi/harnesses/docker_solver.pyputTEST_DIR=/testsbefore the image. - Network:
run_args()no longer adds--network. The task start indokimi/dokimi/harnesses/docker_solver.pytakes the network from the task policy instead. - Mount path comma: A
,in a mount host path makesDockerRunner.argvraiseContainerErrorbefore it returns any argv, on3b61dd0and one5379c3alike. - Static checks: On
e5379c3merged onto current main38d07f9, ruff, the schema check, mypy, deptry, the comment-block check, schema compatibility, the mkdocs build, the CLI snapshot and the fidelity golden all pass. The typedGroupliteral is part of the passing mypy run. - Merge onto main:
e5379c3merges onto current main38d07f9with no conflict.
The grid masked every ':/work:ro' argument to <tmp>, so a broken mount source (/missing:/work:ro) produced the committed golden. The mask now applies only to a source that holds the snippet, checked while the temp dir still exists. Thread: PRRT_kwDOVBg7g862yBwq Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
The golden holds POSIX paths; on Windows the grid's Path('/h/run') serialises
with backslashes, so the byte-identity test fails there and a refresh would
write platform-specific arguments into the shared golden. The refresh script
exits 2 on Windows, and the byte-identity test is skipped there.
Thread: PRRT_kwDOVBg7g862y5dE
Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
The refresh script exits 2 on Windows, so this test would fail there rather than skip. Found by the self-review of e4793aa; probe: IS_WINDOWS=True makes main() return 2. Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
|
Re: review by vlad-perevezentsev
|
…pr623-r5 Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
…ngelog Thread: PRRT_kwDOVBg7g8627Mje Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
…hangelog Thread: PRRT_kwDOVBg7g8627Mjh Thread: PRR_kwDOVBg7g88AAAABXsbQsg Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
|
…ippet Signed-off-by: Vladislav Perevezentsev <vladislav.perevezentsev@intel.com>
vlad-perevezentsev
left a comment
There was a problem hiding this comment.
LGTM
I checked 6e42b32. Every point from my first round is fixed, and the argv each call site builds is still byte-identical to main. Keeping the per-call-site layouts for a follow-up is fine with me.
Merge: safe now: it merges cleanly into current main, 10 commits behind, and its docker, container, network-policy, tbench and docs-refs tests pass on the merge (351 passed). Once it is in, #695 conflicts with it in the import block of docker_solver.py and needs a rebase.
What I ran, at 6e42b32:
make ci-local --offline: 18,946 passed, 0 failed, 72 skipped; every check passes.- The first round's mutation (the task container's
-eflags moved after the image) fails the golden test, the new-eposition test and the refresh re-take test. - The golden against the merge-base
cb6cead: onlysandbox/run_argsdiffers, the one key changed on purpose. - CI's
external-catalog-smoke(docker-oracle and docker-probe), at bc35c8b: 1/1 pass each, every isolation probe closed; the sandboxed task container starts with the same flags as before. - On Windows (Server 2025, Python 3.13): not run. The VM venv cannot be built from the base's
requirements.lock.txt(filelock==4.2.4withlitellm==1.106.4, which needsfilelock<4); this PR does not touch the lock.
Checked, no issues
- The fixes: 4ce67d1, f088901, e036691, e86cc3f, fed7d97, 948153c and 61bf42e each do what their thread asked.
- Changelog: the
Removedfragment names the five moved names with their replacements, and no name that main never exported.
Fixed in this branch, up to 6e42b32:
- The example's
/workmount was masked whenever a file with the snippet's name was there, so a mount of another directory with a different snippet still matched the golden (the open exai-bot thread): 6e42b32 masks it only when the file holds this run's code, and a new test redirects the mount to such a directory.
The new test fails with the oldis_file()check.
Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
Thread: PRRT_kwDOVBg7g863BiVp: already fixed in 6e42b32 Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
The Removed bullet names docker_solver.start_args and TASK_CONTAINER_HARDENING, and says the replacement returns a ContainerPolicy rather than a flag list. Signed-off-by: vchamarthi <123653452+vchamarthi@users.noreply.github.com>
|
Pushed 1 commit to
|
|
antonwolfy
left a comment
There was a problem hiding this comment.
Review at 0b5ba9a. The refactor holds: every docker run argv the package builds is the same as on the base, and the new tests pin the security flags. The merge waits for the red Static checks job on GitHub, which comes from the new test_changelog_docker_argv_fragment.py.
What I ran, on a Linux review host at 0b5ba9a:
make ci-localwith docker: 33 passed, 4 failed. 19,767 tests passed; changed-line coverage, mypy, deptry, ruff, bandit, the fidelity golden and the docker-oracle/docker-probe smoke pass. The failures are not the PR's:pre-commitfailscheck-added-large-filesondocs/reference/cli-interface.json, which this PR does not touch and which is over the limit onmaintoo; the two gitleaks steps failed on a download; two tests intest_audit_test_quality.pyhit the 60 s timeout under load and pass alone (172 passed). The PR carries theskip-changeloglabel.- 60 mutants of the new code (layout groups swapped or dropped, cap list, pids limit,
--init,--read-only,bridged, network): 59 are killed by the differential, policy, characterization, network-policy and container-agent tests. The survivor swaps the sandbox's--label/--tmpfsflags and the task-eflags, which only changes flag order and has no effect on behaviour. - Base against head: the differential test and golden fail against the base only on
sandbox/run_args, the one key changed on purpose.
Checked, no issues
- Call sites: the repo container, example runner, fidelity client and task container build the same flags in the same order as on the base, with and without a sandbox, and
bridged=network == "bridge"matches the old"bridge" in net_args. - Removed names: no reference to
TASK_CONTAINER_HARDENING,start_args,docker_cmd.PIDS_LIMITorContainerPolicy(memory_mb=...)is left in the package, docs, scripts or tests. - Commits: all 19 non-merge commits carry a
Signed-off-by.
I agree with @xaleryb's points on the missing license header in test_changelog_docker_argv_fragment.py and on its dependence on the changelog fragment. New evidence: with the fragment removed from a copy of the tree, both tests fail with FileNotFoundError.
Bot points I checked that no longer apply at this head (1)
- exai-bot's point on masking the example's
/workmount does not apply: the mount is masked only when the snippet file holds this run's code, and a test redirects the mount to a directory with a different snippet.
Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
It read the changelog fragment by name, which scriv removes at release, and it had no SPDX header. The fragment is checked by review. Thread: PRRT_kwDOVBg7g863XTgj Thread: IC_kwDOVBg7g88AAAABmY9rIg Thread: PRR_kwDOVBg7g88AAAABX-4YfQ Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
The merge of main left a noqa that ruff flags once the re-export is gone. Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
|
|
|
antonwolfy
left a comment
There was a problem hiding this comment.
LGTM. The refactor holds: every docker run argv the package builds is the same as at the base, the security flags are pinned by the tests, and the commits since my last review only drop the changelog-wording test, merge main and remove two unused noqa markers. One nit inline.
What I ran, on a Linux review host at 7b0a3e9:
make ci-localwith docker: 37 passed, 1 failed, 14 skipped. 20,447 tests passed; changed-line coverage, mypy, deptry, ruff, bandit, pre-commit, the fidelity golden, the changelog-fragment check and the docker-oracle/docker-probe smoke pass. The one FAIL istest_a_fixed_finding_leaves_the_baseline_toointest_audit_test_quality.py, which hit the 60 s timeout under load; the file does not touch this PR, and run alone it passes (172 passed).- 44 mutants of the new code (security flags, cap list, pids limit, network,
bridged, read-only, layout groups, mount flags): 40 killed by the differential and policy tests. The 4 survivors are a no-op mutant, and three lines this PR did not change (failed_to_start'snot timed_out, the value ofINFRA_EXIT, the comma check on the container path inmount_args). - The golden re-take script run against the base package: the output differs from the committed golden only in the
--networkpair undersandbox/run_args, the one key changed on purpose.
Checked, no issues
- Changelog names: every name the fragment lists was importable at the base and is not at head; a grep of
docs/,scripts/andtests/finds no stale reference. - Layouts: the task container's layout (
init cap_drop security pids cap_add network sandbox_flags env resource) matches the base order, andbridged=network == "bridge"matches the old"bridge" in net_args. - Commits: all 22 non-merge commits carry a
Signed-off-by. - Repo rules: new Python files carry the SPDX header,
docker_solver.pyandtest_container_agent.pysit at their growth baseline, and the deptry entry is needed becausescripts/imports a test module.
Signed-off-by: Anton Volkov <antonwolfy@gmail.com>
antonwolfy
left a comment
There was a problem hiding this comment.
LGTM. I pushed a commit per nit, up to f57fd1a, which fix the nit from my review:
f57fd1a:dokimi/changelog.d/20261112_180000_napetrov_docker-argv-builders.md:3: the bullet now saysContainerPolicygainscap_addbeforepids_limit, so construct it by keyword, andmemoryis a string such as"512m".
make ci-local at f57fd1a: 0 failed, 38 passed, 14 skipped.
Summary
Evidence
tests/fixtures/docker/run_argv_golden.jsoncaptured from the base commit.After:
tests/test_docker_run_argv_differential.pyreplays the input grid through the public entry points and compares argv byte for byte. Passes on head. One key changed on purpose:sandbox/run_argsno longer carries--network(the task policy writes it fromsandbox.network), so against main that key fails and every other key matches.scripts/refresh_docker_run_golden.pyre-takes the golden;tests/test_refresh_docker_run_golden.pychecks a re-take reproduces the committed file byte for byte.Merge Danger
Door: two-way (internal refactor; revert restores the old builders)
Argv is intended to be byte-identical. Removed importable names, listed for importers (checked against main, which this branch now contains):
dokimi.repos.container.ContainerPolicy,dokimi.docker_cmd.PIDS_LIMIT,dokimi.docker_cmd.TASK_CONTAINER_HARDENING,dokimi.harnesses.container_agent.TASK_CONTAINER_HARDENING,dokimi.harnesses.network_policy.start_args,ContainerPolicy(memory_mb=…). The changelog fragment carries the same list.ContainerSandbox.run_args()no longer returns--network; a caller that runs its output alone gets the default bridge, so it must go through the task policy.cap_addis a new field placed beforepids_limit, so positional construction shifts.Blast Radius: docker run argv of the repo container, example runner, fidelity capture and task container.
Follow-ups
changelog.d/20261112_180000_napetrov_docker-argv-builders.md(Removed) lists the importable names that moved.scripts/refresh_docker_run_golden.pyimports the grid fromtests/, so it needs the test dependencies (pytest) installed.🤖 Generated with Claude Code