fix(entrypoint): start ssh-agent without writing into the bind-mounted home - #135
Merged
Merged
Conversation
…d home The ssh-agent startup added in 1cf8070 writes an env-dump file to /root/ssh_env and appends `source /root/ssh_env` to /root/.bashrc on every container start. With compose.dev.yml / the documented `docker run` bind-mounting ${HOME}:/root, those land in the host user's ~/ssh_env and ~/.bashrc, the latter accumulating a line per start. (macOS defaults to zsh so it went unnoticed there, but it still pollutes ~/.bashrc.) Only the WHEEL server process needs the agent env, and it already gets it in the current code (the `source` before `npm start`). Replace the file + .bashrc write with an agent on a fixed, container-local socket: - entrypoint.sh: `ssh-agent -a /tmp/wheel-ssh-agent.sock`, export SSH_AUTH_SOCK, then `exec npm start` (also makes npm the container's PID 1). /tmp is not bind-mounted, so nothing is written to the host home. - Dockerfile: add one line to the image's /etc/bash.bashrc that exports SSH_AUTH_SOCK when that socket exists, so `docker exec ... bash` sessions still attach to the same agent - the only thing the /root/.bashrc write was for. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01C3jKNM1qubomM8UTRdkEWu
This was referenced Sep 11, 2026
so5
added a commit
that referenced
this pull request
Sep 11, 2026
…ime (#136) (#138) Backport of PR #136 (main) to maintenance2023. This branch's Dockerfile predates the run_base/dev/versioner-friendly layout on main (it's builder -> base -> {UT, exec}, node:hydrogen-slim, no separate dev stage), so the backport is adapted rather than a literal copy: - versioner is `FROM base AS versioner` (base already has git installed) followed by `COPY . .` + `git describe`, same idea as main. - the version is baked only in the `exec` stage (there is no `dev` stage here); paths use this stage's WORKDIR (/usr/src/server, so app/db/version.json, not server/app/db/version.json). - kept "master" branch naming used in this line's run_test.yml / build_and_deploy.yml comments (unlike main, not yet renamed here). - did not add the entrypoint.sh ssh-agent block (PR #135, not backported to this branch) or the doc files that don't exist here yet (AGENTS.md, TEST_GUIDE.md, documentMD/design/{developer_guide,testing}.md). The `[skip ci] update version number` step in run_test.yml rewrote server/app/db/version.json and pushed it to every feature branch, so parallel PRs conflicted on that file and a stale `-beta` value rode onto main/maintenance at merge (issue #1014). - run_test.yml: drop the version-stamp / commit / push steps. - version.json: the committed value is a fixed placeholder ("not defined - this is a development build"). Nothing in CI edits the tracked file, so it never diverges between branches -> no more conflicts. - build_and_deploy.yml: pass the computed version through the WHEEL_VERSION build-arg instead of editing the worktree; repack source.tar.gz from a clean tree with the real version dropped in (git archive shipped the placeholder before). versionInfo.js is unchanged - it still statically imports version.json. (cherry picked from commit 931f0ae) Claude-Session: https://claude.ai/code/session_01C3jKNM1qubomM8UTRdkEWu Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
so5
added a commit
that referenced
this pull request
Sep 11, 2026
…ime (#136) (#137) Backport of PR #136 (main) to maintenance2026. Adjusted for this branch: - kept "master" branch naming used in this line's run_test.yml / build_and_deploy.yml comments (unlike main, not yet renamed here) - kept `RUN npm prune --production` in the exec stage as-is (this branch still prunes; main's "don't prune" comment doesn't apply here) - did not add the entrypoint.sh ssh-agent block (PR #135, not backported to this branch) or the doc files that don't exist here yet (AGENTS.md, TEST_GUIDE.md, documentMD/design/{developer_guide,testing}.md) The `[skip ci] update version number` step in run_test.yml rewrote server/app/db/version.json and pushed it to every feature branch, so parallel PRs conflicted on that file and a stale `-beta` value rode onto main/maintenance at merge (issue #1014). - run_test.yml: drop the version-stamp / commit / push steps and the now-unused GITHUB_TOKEN from the test job. CI no longer touches the file. - version.json: the committed value is a fixed placeholder ("not defined - this is a development build"). Nothing in CI edits the tracked file, so it never diverges between branches -> no more conflicts. - build_and_deploy.yml: pass the computed version through the WHEEL_VERSION build-arg instead of editing the worktree; repack source.tar.gz from a clean tree with the real version dropped in (git archive shipped the placeholder before). - Dockerfile: a throwaway `versioner` stage runs `git describe` on the build context, so a plain `docker build .` still bakes a commit-identifying version (`<describe>-local`). `--build-arg WHEEL_VERSION` overrides it; an un-stamped source build keeps whatever version.json ships. No --dirty: .dockerignore hides tracked paths (documentMD/) from the stage's `COPY . .`, so --dirty would always fire. versionInfo.js is unchanged - it still statically imports version.json. (cherry picked from commit 931f0ae) Claude-Session: https://claude.ai/code/session_01C3jKNM1qubomM8UTRdkEWu Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
背景
entrypoint.shの ssh-agent 起動は1cf80702(2025-08-06、HPCI-SS の E2E テスト追加と同時)で入りました。コミットメッセージは簡潔で、当時の意図が追いにくくなっています。追加されたのは次の 4 行です。compose.dev.ymlおよび README のdocker run例は、いずれも${HOME}:/rootを bind mount します。この状態でこの entrypoint は、ホストの~/ssh_envを生成し、コンテナ起動のたびにホストの~/.bashrcへsource /root/ssh_envを 1 行ずつ追記します。macOS はログインシェルが zsh のため気づきにくいものの、~/.bashrcは同様に汚染されます。調査結果(この仕組みが実際に必要としているもの)
node app/index)がSSH_AUTH_SOCK/SSH_AGENT_PIDを持つこと。WHEEL はssh-client-wrapper経由で多数のssh子プロセスを spawn し、それらがサーバの環境を継承します。~/.ssh/configにAddKeysToAgent yesがあり対象鍵がパスフレーズ付きの場合、エージェントがあればパスフレーズ入力(ブラウザのプロンプト)が 1 回で済み、ProxyJump チェーンや同一リモート間のファイル配送(-A)でもエージェント転送が効きます。source ${SSH_ENV_FILE}の後にnpm startを実行しているため、サーバプロセスへは既にエージェント環境が渡っています。>> /root/.bashrcの唯一の目的は、docker exec ... bashの対話シェルが同じエージェントを参照できるようにすることです。通常運転には不要です。ssh_env/SSH_ENV_FILEを参照する箇所は、テスト・CI を含めてこの 4 行のみでした。変更内容
entrypoint.sh該当 4 行を、固定・コンテナローカルなソケット上のエージェント起動に置き換えました。
/tmpは bind mount されないため、ホームディレクトリへは一切書き込みません。exec npm startとし、npm startをコンテナの PID 1 にしました(従来は非execで bash が PID 1)。Dockerfileイメージ内の
/etc/bash.bashrcに 1 行追加し、当該ソケットが存在すればSSH_AUTH_SOCKをエクスポートするようにしました(bind mount 外のためホスト非汚染)。docker exec -it wheel_dev bash(Debian の対話非ログイン bash)はこれを読み込み、同じエージェントに接続します。ソケットが無ければ何もしません。動作確認(Linux ホスト、
compose.dev.yml+ ローカル override でビルド・再作成)~/.bashrcの mtime・SHA256 が不変。~/ssh_envは生成されない。SSH_AUTH_SOCK=/tmp/wheel-ssh-agent.sock。docker exec -it wheel_dev bash:SSH_AUTH_SOCKが設定され、ssh-add -lが応答。npm start。補足
eslint(npm run lint)は非対象。entrypoint.shに依存するユニットテストはありません。🤖 Generated with Claude Code
https://claude.ai/code/session_01C3jKNM1qubomM8UTRdkEWu