Clone workspaces from the repository and name containers per checkout - #852
Merged
Conversation
The pipeline container was welded to one checkout. Its mounts are relative
paths resolved at creation, and both the container and Compose project names
were hardcoded, so a second checkout running the pipeline reached the first
one's container: findings written under a repository nobody was looking at,
and workspaces cloned from a history nobody was reviewing.
Workspaces now clone from CRYPTER_REPO_URL rather than from a read-only mount
of the host's .git. A run sees the branch as the repository holds it, so the
launching checkout no longer decides what gets built or reviewed, and a stale
or unfetched host is no longer a way to start a run on the wrong base. Pull
request heads come from refs/pull/{n}/head directly, which removes the
host-side fetch that staged them. The origin/* fixup in workspace.sh goes with
it: it existed only because cloning a checkout maps that checkout's local
branches into origin/*, which cloning the real remote does not.
Dropping the mount also makes a git worktree a usable checkout for the
pipeline. Its .git is a file rather than a directory, so mounting it gave
git clone something it could not read.
Containers are now named crypter-pipeline-{slug}-{hash}, derived by
pipeline.sh from the checkout it sits in. A checkout resolves only to its own
name, so which container an orchestrator reaches is settled by where it runs
rather than by probing mounts, and recreating one leaves the others alone.
The three volumes stay shared machine-wide, so Claude Code is still
authenticated once and the caches warmed once; they are external because a
Compose-owned volume refuses to mount into a second project.
Compose requires the container name rather than defaulting it, so invoking
docker compose against the file directly now fails instead of quietly
creating a container whose identity says nothing about its mounts.
The container needs outbound network for source as well as for the API, so
the pipeline no longer works offline. It clones anonymously over https and
holds no GitHub credential; branches still leave over the ext:: transport and
are pushed from the host.
Co-Authored-By: Claude Opus 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.
Workspaces now clone from
CRYPTER_REPO_URLinstead of a read-only mount of the host's.git, so a run builds and reviews what the repository holds rather than what the launching checkout happens to have fetched. Pull request heads come fromrefs/pull/{n}/headdirectly, which removes the host-sidegit fetchthat used to stage them.Containers are named
crypter-pipeline-{slug}-{hash}, derived by the new.devcontainer/pipeline.shfrom the checkout it sits in. Each checkout gets its own container, so two can run at once without one reaching the other's/plansand/runs. This is not what makes runs parallel — several runs already share a container, separated by their per-run workspaces.Notes for review:
ext::transport and are pushed from the host..gitis a file rather than a directory, so mounting it gavegit clonesomething it could not read. Verified by running a second instance from one.docker compose -f .devcontainer/docker-compose.yml upnow fails rather than creating a container. The container name is a required variable, so the old command cannot make one whose identity says nothing about its mounts. Use.devcontainer/pipeline.sh up.externalbecause a Compose-owned volume refuses to mount into a second project;pipeline.sh upcreates them.docker volume rmis now machine-wide rather than per-checkout.pipeline.sh listshows every instance and its checkout.origin/*fixup inworkspace.shis deleted. It existed only because cloning a checkout maps that checkout's local branches intoorigin/*; cloning the real remote does not. One consequence:origin/HEADnow resolves tomain, the repository's actual default, rather than being pointed at the run's base. Nothing resolves a bareoriginas a revision — every reference is an explicitorigin/stable,origin/mainororigin/{base}.crypter-pipelinecontainers are orphaned by the rename and can be removed by hand.🤖 Generated with Claude Code