Skip to content

bug(backend): the docker SDK is imported by 5 production modules and declared in no requirements file #14872

Closed

Description

@mrveiss

Found while fixing #14518.

The Docker SDK (import docker) is imported by five modules under
autobot-backend/, and appears in no requirements file anywhere in the
repository:

  • autobot-backend/secure_sandbox_executor.py:30
  • autobot-backend/services/execution/docker_backend.py:31
  • autobot-backend/services/execution/container_pool.py:20
  • autobot-backend/services/docker_task_workspace.py:115
  • autobot-backend/tests/integration/test_codeexec_docker_smoke.py

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".

Why it was not fixed in the #14518 PR

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

Related

Activity

  1. mrveiss commented on Aug 25, 2026

    @mrveiss
    OwnerAuthor

    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.

    All three criteria met. Closing.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    backendbugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions