You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
bug(backend): the docker SDK is imported by 5 production modules and declared in no requirements file #14872
Every one of them guards the import and degrades on failure. That is correct
handling in isolation, but taken together it means sandboxed code execution
silently downgrades in any environment that does not happen to have the SDK
installed — and no environment is guaranteed to, because nothing declares it.
The user-visible result is a code-execution feature that appears configured and
simply never uses a container.
This is the same shape as #14041: a dependency that is absent by default, whose
absence is handled so gracefully that nobody can tell the difference between
"running sandboxed" and "not running sandboxed".
That PR's scope is autobot-infrastructure/shared/scripts/. Declaring docker
touches autobot-backend/requirements.txt, a core-runtime file, and every
production declaration must be mirrored into requirements-ci/*.txt or tools/lint/check_requirements_ci_drift.py fails the build. That is a
deliberate, reviewable change of its own, not a side effect of a scripts fix.
Acceptance criteria
docker is declared in the requirements file that governs the backend,
and mirrored into requirements-ci/ so the drift check passes
Whether the sandbox is actually containerised is observable at runtime —
a degraded sandbox must be visible, not inferred
A guard asserts that a first-party module's hard dependency is declared
Closing audit — every criterion verified against merged Dev_new_gui (85561eb95, PR #15041)
Read from the merged base. Closes keywords do not fire on Dev_new_gui, so
this is a manual closure with per-criterion evidence.
#
Acceptance criterion
Verdict
Evidence in merged code
1
docker is declared in the requirements file that governs the backend, and mirrored into requirements-ci/ so the drift check passes
MET
autobot-backend/requirements.txt:141 — docker>=7.1.0, with the reason recorded at :137-140. Mirrored at requirements-ci/utilities.txt:11, which requirements-ci.txt:22 pulls in via -r; that is the entry point tools/lint/check_requirements_ci_drift.py:69 reads, and the file is inside its GUARD_INPUT_PATHS glob (:79), so the drift audit sees the mirror rather than reporting the package as unmirrored.
2
Whether the sandbox is actually containerised is observable at runtime — a degraded sandbox must be visible, not inferred
MET
Three separate surfaces, all wired: (a) a health probe — autobot-backend/api/sandbox_health.py:119-120 registers probe_sandbox under KnownProbes.SANDBOX (api/system_health.py:56), reporting docker_sdk, daemon_reachable and containerised as measured values rather than assertions; the registration is reached because api/sandbox.py:15 imports the module and api.sandbox is a live registry entry at autobot-backend/initialization/router_registry/feature_routers.py:274. (b) the stats endpoint — api/sandbox.py:320-341 replaces the unconditional "status": "operational" with "degraded_uncontainerised" and derives network_isolation / resource_limits from the same measurement instead of the hardcoded literal True. (c) per-execution — services/execution/execution_manager.py:106-116 logs an explicit warning when a task routed to the containerised backend runs anywhere else, which previously read as routine failover. Unit coverage at api/sandbox_health_test.py:27,:41 asserts the probe name and the UNSANDBOXED detail. Note this is code-level observability: the change had not yet reached a deployed host at the time of this audit.
3
A guard asserts that a first-party module's hard dependency is declared
MET
repo_tests/hard_optional_dependency_declared_test.py:316 test_every_hard_dependency_is_declared — it distinguishes a genuinely optional guard-import from one whose module later raises on the absence flag, discovering sites by AST over git ls-files "*.py" rather than a hand-listed set (:101-105). :294 test_the_sandbox_modules_are_still_discovered names the three sandbox modules by hand so a regression says which dependency stopped being watched. Its exemption dict _KNOWN_UNDECLARED (:90-96) contains five entries, all tracked under #15035 and none of them docker; :335 test_each_exemption_is_still_undeclared fails any exemption that has gone obsolete. The tree-coverage floors at :251 and :271 exist so a blinded tree cannot pass on the aggregate count.
Activity
fix(infrastructure): repair 39 of the 44 imports under shared/scripts…
fix(infrastructure): make a missing script dependency fail loudly, an…
fix(guards): floor the hard-dependency sweep per tree, not on the agg…
fix(deps): declare the docker SDK and the operator-scripts packages n…
feat(sandbox): report whether code execution is actually containerised (
style(sandbox): wrap the probe detail line within the 120-column limit (
fix(guards): floor the hard-dependency sweep per tree, not on the agg…
fix(deps): declare the docker SDK and the operator-scripts packages n…
feat(sandbox): report whether code execution is actually containerised (
style(sandbox): wrap the probe detail line within the 120-column limit (
fix(guards): floor the hard-dependency sweep per tree, not on the agg…
fix(deps): declare the docker SDK and the operator-scripts packages n…
feat(sandbox): report whether code execution is actually containerised (
style(sandbox): wrap the probe detail line within the 120-column limit (
fix(guards): floor the hard-dependency sweep per tree, not on the agg…
mrveiss commentedon Aug 25, 2026
Closing audit — every criterion verified against merged
Dev_new_gui(85561eb95, PR #15041)Read from the merged base.
Closeskeywords do not fire onDev_new_gui, sothis is a manual closure with per-criterion evidence.
dockeris declared in the requirements file that governs the backend, and mirrored intorequirements-ci/so the drift check passesautobot-backend/requirements.txt:141—docker>=7.1.0, with the reason recorded at:137-140. Mirrored atrequirements-ci/utilities.txt:11, whichrequirements-ci.txt:22pulls in via-r; that is the entry pointtools/lint/check_requirements_ci_drift.py:69reads, and the file is inside itsGUARD_INPUT_PATHSglob (:79), so the drift audit sees the mirror rather than reporting the package as unmirrored.autobot-backend/api/sandbox_health.py:119-120registersprobe_sandboxunderKnownProbes.SANDBOX(api/system_health.py:56), reportingdocker_sdk,daemon_reachableandcontainerisedas measured values rather than assertions; the registration is reached becauseapi/sandbox.py:15imports the module andapi.sandboxis a live registry entry atautobot-backend/initialization/router_registry/feature_routers.py:274. (b) the stats endpoint —api/sandbox.py:320-341replaces the unconditional"status": "operational"with"degraded_uncontainerised"and derivesnetwork_isolation/resource_limitsfrom the same measurement instead of the hardcoded literalTrue. (c) per-execution —services/execution/execution_manager.py:106-116logs an explicit warning when a task routed to the containerised backend runs anywhere else, which previously read as routine failover. Unit coverage atapi/sandbox_health_test.py:27,:41asserts the probe name and theUNSANDBOXEDdetail. Note this is code-level observability: the change had not yet reached a deployed host at the time of this audit.repo_tests/hard_optional_dependency_declared_test.py:316 test_every_hard_dependency_is_declared— it distinguishes a genuinely optional guard-import from one whose module later raises on the absence flag, discovering sites by AST overgit ls-files "*.py"rather than a hand-listed set (:101-105).:294 test_the_sandbox_modules_are_still_discoverednames the three sandbox modules by hand so a regression says which dependency stopped being watched. Its exemption dict_KNOWN_UNDECLARED(:90-96) contains five entries, all tracked under #15035 and none of themdocker;:335 test_each_exemption_is_still_undeclaredfails any exemption that has gone obsolete. The tree-coverage floors at:251and:271exist so a blinded tree cannot pass on the aggregate count.All three criteria met. Closing.