Keep the Claude login across container runs - #48
Merged
Merged
Conversation
Claude writes credentials through a temp file and a rename, so the symlink standing in for .credentials.json was replaced by a regular file on the first write. Every refresh after that landed in the container-local config dir and died with the run, leaving the shared home holding a stale record -- an invalid login on the next start. CLAUDE_SECURESTORAGE_CONFIG_DIR names the credential store apart from CLAUDE_CONFIG_DIR, so the config dir stays container-local while the store resolves to ~/.claude on the persistent mount. Claude's token-refresh lock lives in the store, so concurrent containers rotate the shared token one at a time. - .last-update-result.json leaves the allowlist for the same reason: it is rewritten by rename, so the link never carried it - the config merge excludes .credentials.json -- the default user layer is the host's own ~/.claude, and the link that used to overwrite the merged copy is gone
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.
Claude's config dir is container-local, with the state that must outlive the run symlinked back into it from the shared home.
.credentials.jsonsat on that allowlist, but credentials are written through a temp file and a rename: the first write replaced the link with a regular file in the container-local dir, and every refresh after that was stranded there. The shared home kept whatever predated the link's removal, so the next container started from a stale record and the login was invalid.CLAUDE_SECURESTORAGE_CONFIG_DIRnames the credential store apart fromCLAUDE_CONFIG_DIR. The config dir stays container-local and keeps the isolation it was given; the store resolves to~/.claudeon the persistent mount, where the rename lands on a real file in a real directory. Claude takes its token-refresh lock in the store as well, so concurrent containers rotate the shared token one at a time instead of each holding a divergent copy of a rotating refresh token.Also here:
.last-update-result.jsonleaves the state allowlist. It is rewritten by rename too, so the link never carried it..credentials.json. The default user layer is the host's own~/.claude, and the link whose removal used to clear the merged copy is gone.The allowlist comment now states the rule an entry has to satisfy: a link holds only what claude writes in place.
tests/test_image_layout.pycovers the store being named rather than linked, the store resolving inside the shared persistent home, and the merge exclusion.