Content-Length: 311341 | pFad | http://github.com/github/copilot-cli/issues/1643

FB Persistent permissions broken in git worktrees · Issue #1643 · github/copilot-cli · GitHub
Skip to content

Persistent permissions broken in git worktrees #1643

@Gamezar

Description

@Gamezar

Describe the bug

Permission prompts in git worktrees show the main repo path instead of the worktree path. Approving permissions enters an infinite loop — each new session or sub-agent re-prompts because the stored approval key doesn't match the actual working directory.

Affected version

0.0.410

Steps to reproduce the behavior

  1. Set "experimental": true in ~/.copilot/config.json
  2. Create a worktree: git worktree add ../my-feature feature-branch
  3. Start Copilot CLI in the worktree
  4. Trigger a permission prompt (edit, bash, etc.)
  5. Prompt says "in this repo (my-repo)" instead of my-feature
  6. Approve → reprompted again even in same session

Expected behavior

No need to approve again what was marked as safe to do in current directory

Additional context

Copilot investigation:

Bug: PERSISTED_PERMISSIONS breaks git worktree support — location key resolves to wrong path

Description

The PERSISTED_PERMISSIONS feature (introduced in v0.0.407) breaks permission handling in git worktrees. When enabled (via "experimental": true in config), the permission dialog only offers "approve permanently for this location" — but the location key is resolved via git rev-parse --git-common-dir, which returns the main repository path instead of the worktree path.

This causes:

  1. Permission prompts display the wrong directory
  2. Approvals are stored under the wrong path in permissions-config.json
  3. Subsequent sessions in the same worktree cannot find the stored approvals (they look up using the main repo key, but the file paths they're checking are under the worktree)
  4. Sub-agents (task tool) that start fresh permission contexts re-prompt for already-approved permissions

Before v0.0.407, permissions were session-scoped only and worked correctly in worktrees because they didn't rely on filesystem path matching.

Environment

  • Copilot CLI: 0.0.410
  • OS: Ubuntu 20.04 (Linux 6.0.12)
  • Node.js: v18.20.4
  • Config: "experimental": true (enables PERSISTED_PERMISSIONS feature flag)
  • Git: worktree setup with multiple parallel workspaces

Steps to Reproduce

  1. Ensure "experimental": true in ~/.copilot/config.json
  2. Have a git repository cloned at /home/user/my-repo
  3. Create a worktree:
    git worktree add /home/user/my-repo-feature feature-branch
  4. cd /home/user/my-repo-feature
  5. Start a Copilot CLI session: copilot
  6. Trigger any action that requires permission (e.g., edit a file, run bash)
  7. Notice the prompt says "in this repo (my-repo)" — wrong path
  8. Approve the permission
  9. Start a new session or trigger a sub-agent → re-prompted for the same permission

Expected Behavior

  • Permission prompt shows the worktree path: "in this repo (my-repo-feature)"
  • Approval is stored under the worktree path
  • New sessions and sub-agents in the same worktree find the stored approval

Actual Behavior

  • Prompt shows main repo: "in this repo (my-repo)"
  • Approval stored under /home/user/my-repo in permissions-config.json
  • New sessions/sub-agents resolve to the same wrong key but file paths don't match → re-prompt

Regression Timeline

Version Date Behavior
≤ 0.0.406 ≤ Feb 10 Session-scoped permissions only → worktrees worked fine
0.0.407 Feb 12 PERSISTED_PERMISSIONS added (staff-or-experimental)
0.0.410 Feb 16 First location-based permission log entries; worktrees broken

The PERSISTED_PERMISSIONS feature flag gates "staff-or-experimental", so this affects users with "experimental": true or staff accounts.

Root Cause: Source-Level Trace

The location key resolver function (qme in minified index.js):

async function qme(cwd) {
  // Step 1: Get worktree-aware path (CORRECT)
  let toplevel = exec("git", ["rev-parse", "--show-toplevel"], {cwd}).stdout.trim();
  
  // Step 2: Get common git dir (points to MAIN repo for worktrees)
  let commonDir = exec("git", ["rev-parse", "--git-common-dir"], {cwd}).stdout.trim();
  
  // Step 3: BUG — prefers dirname(commonDir) over toplevel
  return isAbsolute(commonDir)
    ? { locationKey: dirname(commonDir) }  // ← WRONG for worktrees
    : { locationKey: toplevel };            // ← correct, but only used as fallback
}

For a normal repo, --git-common-dir returns .git (relative) → falls through to toplevelworks.
For a worktree, --git-common-dir returns /home/user/my-repo/.git (absolute) → uses dirname()returns main repo path.

Why the dialog doesn't offer session-scoped approval as fallback

When PERSISTED_PERMISSIONS is enabled, the permission dialog replaces the session-scoped option:

if (featureFlags?.PERSISTED_PERMISSIONS && locationKey) {
  // ONLY option: "Yes, and don't ask again for ... in this repo (my-repo)"
  choices.push({kind: "approve-for-location", ...});
} else {
  // Fallback: "Yes, and approve ... for the rest of the session"
  choices.push({kind: "approve-for-session", ...});
}

So users with experimental: true cannot fall back to session-scoped permissions.

Suggested Fix

Replace dirname(commonDir) with toplevel in the location key resolver:

// Before (buggy for worktrees):
return isAbsolute(commonDir)
  ? { locationKey: normalize(dirname(commonDir)), locationType: "repo" }
  : { locationKey: normalize(toplevel), locationType: "repo" };

// After (worktree-aware):
return { locationKey: normalize(toplevel), locationType: "repo" };

--show-toplevel is already computed and is worktree-aware. For normal repos it returns the same value as dirname(.git). For worktrees it returns the correct worktree root.

Workaround

Manually duplicate the permission entry in ~/.copilot/permissions-config.json for each worktree path:

{
  "locations": {
    "/home/user/my-repo": { "tool_approvals": [...] },
    "/home/user/my-repo-feature": { "tool_approvals": [...] }
  }
}

Or disable the feature flag by setting "experimental": false in ~/.copilot/config.json (but this disables other experimental features too).

Impact

  • Breaks git worktree workflows for all users with experimental: true or staff accounts
  • No session-scoped fallback — the feature replaces rather than supplements the old approval flow
  • Sub-agents re-prompt — agents spawned via task tool get fresh permission contexts and can't find stored approvals
  • Blocks autonomous workflows — parallel development with multiple worktrees requires manual config editing per worktree

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions









      ApplySandwichStrip

      pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


      --- a PPN by Garber Painting Akron. With Image Size Reduction included!

      Fetched URL: http://github.com/github/copilot-cli/issues/1643

      Alternative Proxies:

      Alternative Proxy

      pFad Proxy

      pFad v3 Proxy

      pFad v4 Proxy