Keep the deployment's secrets out of a Bot's shell - #70
Conversation
|
Closing this in favour of #68, which got here first and is the better change. It does three things mine did not. It strips userinfo out of the proxy URLs, so a proxy password does not survive the scrub. It copies every It also found the thing I walked straight past: Nothing here is worth keeping over that. #66 has the reasoning and #68 has the fix. One thing to carry forward rather than lose: #66's second half is not addressed by either branch, and should not be closed silently along with the issue. |
What this changes
A command spawned by
computer_run_commandwas given the computer process's own environment (agent-computer/src/shell.ts:81). Underdocker-compose.ymlthat is one variable,COMPUTER_TOKEN. Under the one-container image it is the container's environment, whichdocker/s6/s6-rc.d/computer/run:1hands over deliberately and whichdocs/deployment.mdfills from--env-file .env: the key that decrypts stored credentials, the database URL, the model key.envreturned all of them, and the default policy permits the tool.Now a command gets what a command needs.
PATH, the locale and terminal names, and the proxy variables, because anapt-getbehind a corporate proxy reaches nothing without them.HOMEis the workspace, set last so nothing can move it.COMPUTER_SHELL_ENVnames anything else a deployment wants passed through, comma separated and read literally, so naming a secret there is an operator's decision rather than the default it was.An allow list rather than a deny list, because a deny list is the secrets that existed on the day it was written, and the next variable somebody adds to a deployment is not on it.
Closes #66.
What this does not do
This is a floor, not the boundary, and the image already says why:
Dockerfile:134-137notes that a Bot can become root, that per-Bot computers and gVisor are what make that sane, and that "in a container shared between Bots, or one holding a database, a Bot with sudo can reach all of it." Root in a shared container can read another process's environment whatever this function returns. What this removes is the one-word version of it. The larger question, whether a shell belongs in a container that also holds the database and is shared between every Bot, is in the issue rather than in this branch, because it is a product decision and not a bug fix.Where it runs
commandEnvironmentis a pure function of the environment it is handed and the workspace path.COMPUTER_SHELL_ENV, read at spawn time.Boundary and audit
COMPUTER_SHELL_ENVis deployment configuration, read from the computer's own environment, never from a request.Proof
commandEnvironmentis exported and pure, taking the environment as an argument the wayegressFordoes, so the cases can be read without a container.agent-computer/tests/shell.test.tscovers seven: the eight secrets a one-container deployment holds are absent;PATHand the locale survive;HOMEis the workspace whatever the deployment'sHOMEwas; a proxied deployment keepsHTTPS_PROXYandno_proxy;COMPUTER_SHELL_ENVpasses two named variables with surrounding spaces tolerated and brings nothing else with them; naming a variable that is not set does not invent an empty one, becausetest -z "$X"andtest -v Xare different questions; and namingHOMEin that list cannot move a command's home out of its workspace.bun test tests/shell.test.tsfromagent-computerreports 7 pass, 0 fail, 18expect()calls.The remaining gates I could not run here, and would rather say so than imply otherwise.
bunx biomeexits with an access violation on this machine andbun run typecheckcannot resolveyaml,zodand others; both reproduce on a clean checkout ofmainwith no changes, so they are this Windows setup rather than this branch, and I could not run the container either. I have kept every line inside 80 columns and followed the formatting of the file beside it, but CI is the real check on that, and I will fix whatever it reports.Reviewed by reading rather than running: no
ENVin theDockerfilethat a command plausibly needs is dropped, there is noDEBIAN_FRONTENDto lose, andsudoresets the environment by default in any case, sosudo apt-get installbehaves exactly as before.