Skip to content

Restate a worktree's registration in the container - #89

Merged
CrypticSwarm merged 1 commit into
masterfrom
gitguard-worktree-gitdir
Sep 25, 2026
Merged

CrypticSwarm merged 1 commit into
masterfrom
gitguard-worktree-gitdir

Conversation

@CrypticSwarm

Copy link
Copy Markdown
Owner

A linked worktree's git dir records its checkout in gitdir by the checkout's host path. The guard mounts every git dir at its host path but never the checkout there, so inside the container that record names a directory that does not exist. Git still finds the root by walking up from the cwd, but git worktree list calls the worktree prunable, and a harness that resolves its project root from the record gets nothing back. Grok Build keys folder trust on that root, so it treats the tree it was started in as untrusted and gates off project instructions, skills, MCP and hooks.

git-guard takes --worktree-at, the container path the session starts in: /workspace, or /repos/<slug> in repo-slug mode. The Makefile recipe passes it. The guard writes a replacement record naming <path>/.git and mounts it read-only over the workspace's own record. The host's file is untouched, because the host's git worktree list and prune read it.

The replacement goes under the system temp dir, in a per-user directory that only that user can write. Its name is derived from the pair of paths, so a rerun overwrites its own file rather than adding another. The guard refuses when:

  • that directory is not the user's alone
  • a symlink sits at the file's name
  • the temp dir falls inside the workspace or its git dirs
  • the record is a symlink or missing
  • worktrees/ is a symlink
  • --worktree-at is not one of the --targets
  • a path cannot be spelled as a docker -v value

Every refusal comes before the write.

Tongs keep the host's record. Only the workspace's own registration is restated, so sibling worktrees still read prunable inside the container.

Docs: docs/git-guard.md, docs/harnesses/grok.md, docs/tongs/definitions.md.

A linked worktree's git dir records the checkout it belongs to by the
path that checkout has on the host, and the guard mounts every git dir
at its host path but never a checkout there. Git still finds the root by
walking up from the cwd, so ordinary work is unaffected, but everything
that reads the record answers with a directory the container does not
have: `git worktree list` calls the worktree `prunable`, and a harness
that resolves its project root from it -- Grok Build keys folder trust
on that root -- finds the tree it was started in untrusted and gates off
project instructions, skills, MCP and hooks.

`--worktree-at` names the container path the session starts in, and the
guard mounts a replacement record read-only over the workspace's own.
The host's file is untouched: its own `git worktree list` and
`git worktree prune` read it, where a container path would read as a
worktree that has gone away. The replacement lives under the system temp
dir at a name derived from the pair of paths it stands for, since the
guard exits before the container starts and a fresh name each run would
leave a file nothing is left to remove.

Only the workspace's own record is restated; the repository's other
linked worktrees still read `prunable` inside the container.
@CrypticSwarm
CrypticSwarm merged commit 0aaca34 into master Sep 25, 2026
4 checks passed
@CrypticSwarm
CrypticSwarm deleted the gitguard-worktree-gitdir branch September 25, 2026 04:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant