From 0cceaaf4a9905b16f61363823911cc3da317e341 Mon Sep 17 00:00:00 2001 From: MechaCat02 Date: Sat, 29 Aug 2026 16:31:53 +0200 Subject: [PATCH] containers: an expired token could never be replaced Credentials were seeded only when the container's copy was MISSING. So when a session expired, the file still existed, the copy was skipped, and restarting changed nothing -- the one recovery path a human has, re-logging in on the host, could not reach the containers at all. Now re-seeds whenever the host's copy is newer. Newer-wins rather than always-copy, because a container refreshes its own token mid-run and that copy may legitimately be the fresher of the two. Found when both sessions expired: host credentials at 16:30, containers holding 14:20 and 14:24. --- Cargo.lock | 12 ++++++++++++ docker/decoder/entrypoint.sh | 14 ++++++++++++-- docker/port/entrypoint.sh | 14 ++++++++++++-- 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 896db78b..c3d303d5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4618,6 +4618,18 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "sylpheed-export" +version = "0.1.0" +dependencies = [ + "anyhow", + "clap", + "image", + "serde", + "serde_json", + "sylpheed-formats", +] + [[package]] name = "sylpheed-formats" version = "0.1.0" diff --git a/docker/decoder/entrypoint.sh b/docker/decoder/entrypoint.sh index f14b94de..da5ce0e5 100755 --- a/docker/decoder/entrypoint.sh +++ b/docker/decoder/entrypoint.sh @@ -133,13 +133,23 @@ mkdir -p /exchange/files 2>/dev/null || true # Seeded rather than shared because credentials live in .credentials.json and a # token refresh must be able to write. Copying once means each agent refreshes # its own token and neither can corrupt the host's. -if [ -d "$HOME/.claude.seed" ] && [ ! -s "$HOME/.claude/.credentials.json" ]; then +# Re-seed whenever the HOST's credentials are newer than ours, not only when +# ours are missing. The missing-only guard meant an expired token could never be +# replaced: the file existed, so the copy was skipped, and restarting the +# container changed nothing. A human re-logging in on the host is exactly the +# recovery path, and it has to reach here. +# +# Newer-wins rather than always-copy, because the container refreshes its own +# token during a run and that copy may legitimately be the fresher one. +if [ -d "$HOME/.claude.seed" ] && \ + { [ ! -s "$HOME/.claude/.credentials.json" ] || \ + [ "$HOME/.claude.seed/.credentials.json" -nt "$HOME/.claude/.credentials.json" ]; }; then mkdir -p "$HOME/.claude" cp -a "$HOME/.claude.seed/.credentials.json" "$HOME/.claude/" 2>/dev/null || true for f in settings.json CLAUDE.md; do [ -e "$HOME/.claude.seed/$f" ] && cp -a "$HOME/.claude.seed/$f" "$HOME/.claude/" 2>/dev/null || true done - echo "[entrypoint] seeded ~/.claude from the host (credentials only)" + echo "[entrypoint] refreshed ~/.claude credentials from the host" fi # Seed ~/.claude.json from the host's read-only copy, then stamp onboarding as diff --git a/docker/port/entrypoint.sh b/docker/port/entrypoint.sh index 0cd71feb..8fa94dcc 100755 --- a/docker/port/entrypoint.sh +++ b/docker/port/entrypoint.sh @@ -30,13 +30,23 @@ echo "[entrypoint] display $DISPLAY ready ($SCREEN_GEOMETRY)" # Seeded rather than shared because credentials live in .credentials.json and a # token refresh must be able to write. Copying once means each agent refreshes # its own token and neither can corrupt the host's. -if [ -d "$HOME/.claude.seed" ] && [ ! -s "$HOME/.claude/.credentials.json" ]; then +# Re-seed whenever the HOST's credentials are newer than ours, not only when +# ours are missing. The missing-only guard meant an expired token could never be +# replaced: the file existed, so the copy was skipped, and restarting the +# container changed nothing. A human re-logging in on the host is exactly the +# recovery path, and it has to reach here. +# +# Newer-wins rather than always-copy, because the container refreshes its own +# token during a run and that copy may legitimately be the fresher one. +if [ -d "$HOME/.claude.seed" ] && \ + { [ ! -s "$HOME/.claude/.credentials.json" ] || \ + [ "$HOME/.claude.seed/.credentials.json" -nt "$HOME/.claude/.credentials.json" ]; }; then mkdir -p "$HOME/.claude" cp -a "$HOME/.claude.seed/.credentials.json" "$HOME/.claude/" 2>/dev/null || true for f in settings.json CLAUDE.md; do [ -e "$HOME/.claude.seed/$f" ] && cp -a "$HOME/.claude.seed/$f" "$HOME/.claude/" 2>/dev/null || true done - echo "[entrypoint] seeded ~/.claude from the host (credentials only)" + echo "[entrypoint] refreshed ~/.claude credentials from the host" fi # Seed ~/.claude.json from the host's read-only copy, then stamp onboarding as