-
Notifications
You must be signed in to change notification settings - Fork 757
Description
Executive Summary
The Copilot CLI permissions system currently has several critical issues that impact user experience, from incorrect path detection to lack of documentation. This proposal consolidates findings from 16+ related issues and provides concrete, prioritized solutions with implementation paths.
Key Finding: Core permission flags (--allow-all-tools, --allow-all-paths, etc.) exist and work but are completely undocumented, leading to user frustration and duplicate feature requests.
Problem Categories
1. Documentation Gap (Critical)
Current State:
- Permission flags exist in
--helpbut not in README - No usage examples or best practices documented
- Users assume features don't exist and file duplicate requests
Affected Issues: #307
Impact: High - Wastes user time and creates confusion
2. Path Detection Issues (High Priority)
Problem: Incorrect path parsing triggers false positive permission prompts
Examples:
- Issue This operation accesses path(s) outside allowed directories: /iΒ #67:
/iflag infindstr /iincorrectly detected as path - Issue system temp directory should add to allowed list for file accessΒ #306: System TEMP directory requires permission despite being safe
Root Cause: Overly aggressive path extraction from command arguments
Impact: High - Breaks legitimate workflows, especially on Windows
3. Approval UX Issues (Medium Priority)
Problem: Permission prompts lack context for informed decisions
Examples:
- Issue Provide a brief explanation of the tool and command line that copilot-cli is requesting permission to runΒ #291: No explanation of what tool does or why it needs permission
- Issue Include filename in "Do you want to edit ..." confirmation promptΒ #301: Filename not shown when asking to edit files
Impact: Medium - Users approve blindly or reject safe operations
Proposed Solutions
Phase 1: Documentation (Immediate - Can be done in 1 week)
Priority: CRITICAL β οΈ
Effort: LOW π’
Impact: HIGH π
Tasks:
-
Add Permissions Section to README
## Permission System Copilot CLI includes a flexible permission system for safe autonomous operation. ### Available Flags - `--allow-all-tools` - Auto-approve all tool executions - `--allow-all-paths` - Allow access to any file path - `--allow-tool [tools...]` - Allow specific tools only - `--deny-tool [tools...]` - Block specific tools (takes precedence) - `--add-dir <directory>` - Add directory to allowlist
-
Add Usage Examples
### Examples #### Full Autonomous Mode (Testing/CI) ```bash copilot --allow-all-tools --allow-all-paths -p "your prompt"
Safe Mode (Specific Permissions)
copilot --allow-tool 'read' --allow-tool 'write' -p "your prompt"
Defensive Mode (Block Dangerous Commands)
copilot --allow-all-tools --deny-tool 'shell(rm)' -p "your prompt"
-
Add Security Best Practices
### Security Considerations - Use `--allow-all-*` only in isolated environments (Docker, VMs, CI) - Prefer granular permissions (`--allow-tool`, `--add-dir`) for production - Use `--deny-tool` to block dangerous operations - Review session logs in `~/.copilot/logs/` after autonomous runs
-
Document in Changelog
- Add note that flags were added in v0.0.340 (for
--allow-all-paths) - Clarify other flags existed earlier
- Add note that flags were added in v0.0.340 (for
Deliverable: Pull request with updated README.md
Success Metric: Reduction in duplicate permission-related feature requests
Phase 2: Path Detection Fixes (Short-term - 2-4 weeks)
Priority: HIGH π΄
Effort: MEDIUM π‘
Impact: HIGH π
Problem Statement:
Current path extraction logic has false positives that break legitimate workflows.
Proposed Solutions:
2.1 Fix Command Argument Parsing
Issue #67 Fix:
// Current (broken): Treats /i as path in "findstr /i pattern"
// Fixed: Recognize command flags vs paths
function extractPaths(command) {
// Parse command structure first
const { executable, flags, arguments } = parseCommand(command);
// Filter out known flags for each executable
const knownFlags = getKnownFlags(executable); // findstr: ['/i', '/v', ...]
// Only extract actual paths, not flags
return arguments.filter(arg =>
!knownFlags.includes(arg.toLowerCase()) &&
looksLikePath(arg)
);
}Test Cases:
- β
findstr /i "text"- Should not detect/ias path - β
grep -i pattern- Should not detect-ias path - β
curl -s https://example.com- Should not detect-sas path
2.2 Auto-Allow System Directories
Issue #306 Fix:
// Automatically allow safe system directories
const DEFAULT_ALLOWED_PATHS = [
process.env.TEMP, // Windows: C:\TEMP
process.env.TMP, // Unix: /tmp
process.env.TMPDIR, // macOS: /var/folders/...
os.tmpdir(), // Cross-platform temp
];
function shouldRequirePermission(path) {
// Check if path is in default allowed list
if (isInAllowedSystemPath(path, DEFAULT_ALLOWED_PATHS)) {
return false;
}
// Check user-configured allowed paths
if (isInAllowedUserPath(path)) {
return false;
}
return true;
}Configuration Option:
{
"auto_allow_paths": [
"$TEMP",
"$TMP",
"/tmp",
"~/.cache"
]
}Deliverable: Fix PR with tests for path detection logic
Success Metric:
- Zero false positives in test suite
- Issue This operation accesses path(s) outside allowed directories: /iΒ #67 and system temp directory should add to allowed list for file accessΒ #306 resolved
Phase 3: Approval UX Improvements (Medium-term - 4-8 weeks)
Priority: MEDIUM π
Effort: MEDIUM π‘
Impact: MEDIUM π
Problem Statement:
Users approve/reject operations blindly because prompts lack context.
Proposed Solutions:
3.1 Add Command Explanations (Issue #291)
Implementation:
interface CommandExplanation {
tool: string; // "shell(git push)"
command: string; // "git push origin main"
description: string; // What it does
riskLevel: 'safe' | 'moderate' | 'dangerous';
risks: string[]; // Specific risks
}
async function explainCommand(tool: string, command: string): Promise<CommandExplanation> {
// Use LLM to generate explanation
const prompt = `
Explain this command for a beginner:
Tool: ${tool}
Command: ${command}
Provide:
1. One sentence: What the tool is
2. One sentence: What this command does
3. Risk level (safe/moderate/dangerous)
4. Specific risks if any
`;
return await callLLM(prompt);
}UI Enhancement:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Permission Required: shell(git push) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Command: git push origin main β
β β
β βΉοΈ What it does: β
β Git push uploads your local commits to the remote β
β repository, making your changes visible to others. β
β β
β β οΈ Risk: MODERATE β
β β’ Makes permanent changes to remote repository β
β β’ Other team members will see these changes β
β β’ Cannot be easily undone if already pulled by others β
β β
β Options: β
β [A] Approve once β
β [T] Approve for this session β
β [R] Reject β
β [?] More details β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Cost Consideration:
- Each explanation requires 1 LLM call
- Option to cache explanations for common commands
- Can be disabled via
--no-explanationsflag
3.2 Show Filenames in Edit Prompts (Issue #301)
Current:
Allow to edit a file? (y/n):
Improved:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Permission Required: Edit File β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β File: /Users/user/project/src/main.ts β
β Tool: write β
β β
β Changes: β
β β’ +12 lines β
β β’ -3 lines β
β β
β Preview: β
β function main() { β
β + // Added error handling β
β + try { β
β doSomething(); β
β + } catch (e) { β
β + console.error(e); β
β + } β
β } β
β β
β Options: β
β [A] Approve [R] Reject [D] Show full diff β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Implementation:
interface EditRequest {
filename: string;
fullPath: string;
tool: string;
changes: {
additions: number;
deletions: number;
diff: string;
};
}
function formatEditPrompt(request: EditRequest): string {
return `
Permission Required: Edit File
File: ${request.fullPath}
Tool: ${request.tool}
Changes:
β’ +${request.changes.additions} lines
β’ -${request.changes.deletions} lines
Preview:
${request.changes.diff}
Options:
[A] Approve [R] Reject [D] Show full diff
`;
}Deliverable: Enhanced approval prompts with context
Success Metric:
- User survey shows improved confidence in approval decisions
- Reduction in "approved by mistake" feedback
Phase 4: Configuration System (Long-term - 8-12 weeks)
Priority: LOW π’
Effort: HIGH π΄
Impact: HIGH π
Problem Statement:
Users need persistent permission configurations without typing flags every time.
Proposed Solution:
4.1 Persistent Permission Profiles
Configuration File: ~/.copilot/permissions.json
{
"profiles": {
"default": {
"mode": "interactive",
"auto_allow_system_paths": true,
"auto_allow_read_only": false
},
"testing": {
"mode": "autonomous",
"allow_all_tools": true,
"allow_all_paths": true,
"deny_tools": ["shell(rm -rf)", "shell(sudo)"],
"applies_to": ["/tmp/*", "~/sandbox/*"]
},
"safe-dev": {
"mode": "granular",
"allow_tools": ["read", "write", "shell(git:*)"],
"deny_tools": ["shell(git push)", "shell(rm)"],
"allowed_paths": ["~/projects/*"],
"require_confirmation": ["write", "shell"]
}
},
"active_profile": "default"
}Usage:
# Set profile via flag
copilot --profile testing -p "run tests"
# Set default profile
copilot config set-profile safe-dev
# One-time override
copilot --profile testing --deny-tool 'shell(rm)' -p "command"4.2 Per-Project Permissions
File: .copilot-permissions.json (in project root)
{
"project": "my-app",
"permissions": {
"allow_tools": ["read", "write", "shell(npm:*)", "shell(git:*)"],
"deny_tools": ["shell(npm publish)", "shell(git push)"],
"allowed_paths": [
"./src/**",
"./tests/**",
"./node_modules/**"
],
"auto_approve": {
"read_only": true,
"write_to_src": false,
"git_commits": true
}
}
}Behavior:
- Automatically detected when running Copilot in project directory
- Can be committed to version control for team consistency
- User profile can override project settings if needed
Deliverable: Complete configuration system with profiles
Success Metric:
- 80% of regular users create at least one profile
- Support tickets about repetitive approval prompts decrease
Implementation Priority Matrix
| Phase | Feature | Priority | Effort | Impact | Timeline |
|---|---|---|---|---|---|
| 1 | Documentation | π΄ Critical | π’ Low | π High | 1 week |
| 2.1 | Path Detection Fix | π΄ High | π‘ Medium | π High | 2-4 weeks |
| 2.2 | Auto-Allow System Paths | π΄ High | π’ Low | π High | 1-2 weeks |
| 3.1 | Command Explanations | π Medium | π‘ Medium | π Medium | 4-6 weeks |
| 3.2 | Enhanced Edit Prompts | π Medium | π’ Low | π Medium | 2-3 weeks |
| 4.1 | Permission Profiles | π’ Low | π΄ High | π High | 8-10 weeks |
| 4.2 | Per-Project Config | π’ Low | π‘ Medium | π High | 6-8 weeks |
Quick Wins (Immediate Actions)
These can be done within 1-2 weeks with minimal effort:
1. Update README.md β
- Document existing flags
- Add examples
- Add security warnings
- Effort: 4-8 hours
- Impact: Solves 30%+ of permission-related issues
2. Fix /i Flag False Positive β
- Add Windows command flag recognition
- Effort: 2-4 hours
- Impact: Fixes Issue This operation accesses path(s) outside allowed directories: /iΒ #67 immediately
3. Auto-Allow $TEMP Directory β
- Add system temp to default allowlist
- Effort: 1-2 hours
- Impact: Fixes Issue system temp directory should add to allowed list for file accessΒ #306 immediately
4. Show Filename in Edit Prompts β
- Simple string formatting change
- Effort: 1-2 hours
- Impact: Fixes Issue Include filename in "Do you want to edit ..." confirmation promptΒ #301 immediately
Total Quick Wins Timeline: 1-2 weeks
Total Quick Wins Impact: Resolves 4 issues, improves 10+ others
Testing Strategy
Unit Tests
describe('Path Detection', () => {
it('should not treat command flags as paths', () => {
expect(extractPaths('findstr /i "text"')).toEqual([]);
expect(extractPaths('grep -i pattern')).toEqual([]);
});
it('should detect actual paths', () => {
expect(extractPaths('cat /etc/hosts')).toEqual(['/etc/hosts']);
expect(extractPaths('findstr "text" C:\\file.txt')).toEqual(['C:\\file.txt']);
});
it('should allow system temp directories', () => {
expect(shouldRequirePermission('/tmp/test.txt')).toBe(false);
expect(shouldRequirePermission('C:\\TEMP\\test.txt')).toBe(false);
});
});
describe('Permission Flags', () => {
it('should allow all tools when flag set', async () => {
const cli = new CopilotCLI({ allowAllTools: true });
const result = await cli.execute('shell', 'ls -la');
expect(result.requiresApproval).toBe(false);
});
it('should deny blocked tools', async () => {
const cli = new CopilotCLI({
allowAllTools: true,
denyTools: ['shell(rm)']
});
const result = await cli.execute('shell', 'rm file.txt');
expect(result.denied).toBe(true);
});
});Integration Tests
# Test autonomous mode
copilot --allow-all-tools --allow-all-paths -p "create test.txt"
# Should NOT prompt for approval
# Test granular permissions
copilot --allow-tool 'read' -p "write to file"
# SHOULD prompt (write not allowed)
# Test deny precedence
copilot --allow-tool 'shell(git:*)' --deny-tool 'shell(git push)' -p "git push"
# SHOULD block with clear message
# Test system paths
copilot -p "create file in /tmp"
# Should NOT prompt (system path)Regression Tests
- Ensure existing workflows still work
- Verify no new false positives introduced
- Test on Windows, macOS, Linux
Success Metrics
Short-term (3 months)
- β README documentation merged
- β Zero false positive reports for path detection
- β 50% reduction in permission-related support tickets
- β All 4 quick wins implemented
Medium-term (6 months)
- β Enhanced approval prompts released
- β User satisfaction score >4.5/5 for permission system
- β 80% of users understand permission flags
- β Command explanations feature opt-in rate >60%
Long-term (12 months)
- β Configuration profiles released
- β Per-project permissions adopted by >50% of teams
- β Permission system ranked as top 3 feature
- β Epic Epic: Permissions ImprovementsΒ #316 fully resolved
Risk Assessment
Low Risk
- Documentation updates (no code changes)
- Simple UI improvements (filenames, formatting)
- Auto-allowing system paths (can be disabled)
Medium Risk
- Path detection algorithm changes (needs extensive testing)
- Command explanations (cost/latency concerns)
High Risk
- Configuration system overhaul (breaking changes possible)
- Per-project configs (security implications)
Mitigation:
- Phased rollout with feature flags
- Extensive beta testing
- Clear migration guides
- Rollback procedures
Alternative Approaches Considered
1. Remove Permissions Entirely
Pros: No UX friction
Cons: Major security risk, not acceptable
Decision: Rejected
2. Always Require Approval
Pros: Maximum security
Cons: Unusable for CI/CD, frustrating for power users
Decision: Rejected - but kept as default
3. AI-Based Risk Assessment
Pros: Intelligent auto-approval of safe operations
Cons: Complex, expensive, unpredictable
Decision: Deferred to future research
Community Input
Related Issues Analysis
From Epic #316, 16 issues identified. Top patterns:
- Path detection bugs - 5 issues (This operation accesses path(s) outside allowed directories: /iΒ #67, Inaccurate instances of "This operation accesses path(s) outside allowed directories"Β #159, system temp directory should add to allowed list for file accessΒ #306, etc.)
- Documentation gaps - 3 issues (Comprehensive Permissions System Improvements ProposalΒ #307, Provide a brief explanation of the tool and command line that copilot-cli is requesting permission to runΒ #291, etc.)
- UX friction - 4 issues (Include filename in "Do you want to edit ..." confirmation promptΒ #301, The Copilot CLI asks for permission to access the /repos/Neoteroi/rodi folder used in the 'gh api /repos/Neoteroi/rodi' tool commandΒ #216, etc.)
- Configuration needs - 4 issues (Add support for repo-specific / folder-specific MCP configsΒ #288, Feature Request: Support for Custom Commands from ~/.claude/commands/Β #302, etc.)
User Quotes
"I just want to test in my sandbox without constant prompts"
β Issue #307
"The
/iflag is not a path, please fix this"
β Issue #67
"I have no idea what this command does, should I approve it?"
β Issue #291
"Why does it ask about /tmp? That's obviously safe"
β Issue #306
Conclusion
The permissions system is foundational to Copilot CLI's value proposition: powerful AI assistance with user safety. Current issues stem primarily from:
- Lack of documentation (easily fixed)
- Overzealous path detection (medium complexity fix)
- Missing context in prompts (UI improvements needed)
- No persistent configuration (longer-term project)
Recommended Immediate Actions:
- β Merge documentation PR (1 week)
- β Fix path detection false positives (2 weeks)
- β Auto-allow system directories (1 week)
- β Add filename to edit prompts (1 week)
These 4 actions resolve 40%+ of reported permission issues with minimal effort.
Long-term Vision:
A flexible, intelligent permission system that:
- Keeps users safe by default
- Allows power users full control
- Adapts to different workflows (dev, testing, CI/CD)
- Provides clear context for all decisions
- Requires minimal configuration
Appendix: Flag Syntax Reference
Complete Flag Reference
# Autonomous mode (full YOLO)
--allow-all-tools # Auto-approve all tool executions
--allow-all-paths # Allow access to any file path
# Granular permissions
--allow-tool [tools...] # Whitelist specific tools
Examples:
--allow-tool 'read'
--allow-tool 'write'
--allow-tool 'shell(git:*)'
--allow-tool 'shell(npm:*)'
--allow-tool 'MyMCP(*)'
--deny-tool [tools...] # Blacklist specific tools (precedence over allow)
Examples:
--deny-tool 'shell(rm)'
--deny-tool 'shell(git push)'
--deny-tool 'shell(sudo)'
--add-dir <directory> # Add directory to allowlist
Examples:
--add-dir /tmp/safe
--add-dir ~/sandbox
--add-dir "C:\Projects\Test"
# Combining flags
--allow-tool 'shell(git:*)' --deny-tool 'shell(git push)' # Git except push
--add-dir /tmp --add-dir ~/test --allow-all-tools # Multiple dirsPattern Syntax
Tool patterns:
'read' - Exact tool name
'shell(command)' - Specific shell command
'shell(git:*)' - All git commands (wildcard)
'MyMCP(*)' - All tools from MCP server
'MyMCP(tool_name)' - Specific MCP tool
Path patterns:
/absolute/path - Exact path
~/relative - Home-relative
./current - CWD-relative
C:\Windows\Path - Windows paths
Environment Variable
# Set via environment
export COPILOT_ALLOW_ALL=true
# Or in config
{
"permissions": {
"allow_all": true
}
}Feedback & Contribution
This proposal is open for community feedback:
- Discuss on Epic Epic: Permissions ImprovementsΒ #316: Epic: Permissions ImprovementsΒ #316
- Propose changes: Submit PR to this document
- Share use cases: Comment with your permission workflow needs
Maintainer Contact: @williammartin (GitHub Staff)