Files
Sylpheed/docker/bin/push-work
MechaCat02 11eac797a0 port: push-work must not configure the repository it runs in
It set `git config --local credential.helper "store --file=$HOME/..."`, which
PERSISTS in the repository. The repo is a bind mount the host also uses, so the
host's git inherited `store --file=/sylph-home/port/.git-credentials` -- a path
that exists only inside the container -- and every host push then failed with
`unable to get credential storage lock: No such file or directory`.

Same root as the EBUSY credential error, from the other side: a tool that
configures a shared repository to suit itself breaks every other user of that
repository. Now applied with `-c` to the single push invocation.

Cleared the leaked setting from both checkouts by hand. Syplheed-Reborn had it
too, from the RE container's copy of this script.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-28 21:15:24 +02:00

77 lines
2.9 KiB
Bash
Executable File

#!/usr/bin/env bash
# Push the current topic branch to origin — the ONLY sanctioned way out of the
# container.
#
# Why a wrapper instead of plain `git push`:
#
# * **`main` and shared branches are refused.** The agent commits to
# `auto/<topic>`; a human merges. A token that can push anywhere is one
# confused iteration away from rewriting the consolidated line.
# * **Force-push is refused**, always. Nothing here needs it, and history
# rewriting is the one mistake that cannot be undone by merging.
# * It pushes the CURRENT branch only, by name, so a stray `--all` cannot
# publish another agent's worktree branch mid-experiment.
#
# Credentials come from a file mounted read-only at ~/.git-credentials (see
# `sylph-agent`). They are never printed, never logged, and never passed on a
# command line.
#
# push-work push the current branch
# push-work --dry-run say what it would do
set -euo pipefail
DRY=0
[ "${1:-}" = "--dry-run" ] && DRY=1
repo_root=$(git rev-parse --show-toplevel 2>/dev/null) || {
echo "push-work: not inside a git repository" >&2; exit 1; }
cd "$repo_root"
branch=$(git rev-parse --abbrev-ref HEAD)
if [ "$branch" = "HEAD" ]; then
echo "push-work: detached HEAD — check out a branch first" >&2; exit 1
fi
case "$branch" in
auto/*) ;;
*)
echo "push-work: refusing to push '$branch'." >&2
echo " Only auto/* topic branches may leave the container; a human merges" >&2
echo " them into main. Move your work: git switch -c auto/<topic>" >&2
exit 1 ;;
esac
if [ ! -s "$HOME/.git-credentials" ]; then
echo "push-work: no credentials mounted at ~/.git-credentials." >&2
echo " The host must start the container with SYLPH_GIT_CREDENTIALS pointing" >&2
echo " at a file containing one line:" >&2
echo " https://<user>:<token>@git.mc02.dev" >&2
exit 1
fi
# Applied to THIS COMMAND ONLY, via `-c`, never `git config --local`.
#
# Writing it to --local config persists it in the repository, and this repo is a
# bind mount the host also uses -- so the host's git inherited
# `store --file=/sylph-home/port/.git-credentials`, a path that exists only
# inside the container, and every host push then failed with
# `unable to get credential storage lock: No such file or directory`.
#
# A tool that configures a shared repository to suit itself breaks every other
# user of that repository. Keep it to the invocation.
CRED_HELPER="store --file=$HOME/.git-credentials"
ahead=$(git rev-list --count "origin/$branch..$branch" 2>/dev/null || git rev-list --count HEAD)
echo "push-work: $branch$ahead commit(s) to publish"
if [ "$DRY" = 1 ]; then
echo "push-work: --dry-run, stopping here"
exit 0
fi
# --force-with-lease is deliberately NOT offered. If this is rejected as
# non-fast-forward, someone else moved the branch: fetch and merge, do not
# overwrite.
git -c "credential.helper=$CRED_HELPER" push --set-upstream origin "$branch"
echo "push-work: pushed $branch"