Files
shopify-ai-backup/EXTERNAL_DIR_PERMISSION_FIX.md

107 lines
3.4 KiB
Markdown

# External Directory Permission Auto-Deny Implementation
## Summary
Automatically denies OpenCode `external_directory` permission requests when they don't match the current app's ID, preventing permission prompts from appearing in the builder UI.
## Storage Impact
- **Config file size**: ~208 bytes per app
- **Location**: `{workspaceDir}/opencode.json` (in each app's workspace directory)
- **Overhead**: Negligible (< 0.3 KB per app)
## Implementation Details
### Files Modified
1. **chat/server.js**:
- Added `ENABLE_EXTERNAL_DIR_RESTRICTION` environment variable (line 102)
- Added `ensureOpencodeConfig(session)` function (lines 1960-2001)
- Modified `ensureSessionPaths(session)` to call the new function (line 1956)
2. **.env.example**:
- Added `ENABLE_EXTERNAL_DIR_RESTRICTION` documentation (line 35)
### How It Works
1. When a session is created, `ensureSessionPaths()` is called
2. This function calls `ensureOpencodeConfig()` which:
- Extracts the app ID and user ID from the session
- Creates an `opencode.json` config file in the workspace directory
- Configures `external_directory` permission rules:
- Deny all external directory access (`*`: "deny")
- Allow access only to current app's paths:
- `*/{appId}/*` - Any path containing the app ID
- `apps/{userId}/{appId}/*` - The full workspace path pattern
3. OpenCode automatically loads this config when running in the workspace directory
4. Permission requests for paths matching the current app ID are auto-allowed
5. Permission requests for other apps are auto-denied (no user prompt)
### Example Config File
```json
{
"$schema": "https://opencode.ai/config.json",
"permission": {
"external_directory": {
"*": "deny",
"*/c7f9e5c6-e7c2-4258-a583-ccffcf9791c8/*": "allow",
"apps/user123/c7f9e5c6-e7c2-4258-a583-ccffcf9791c8/*": "allow"
}
}
}
```
## Configuration
### Environment Variable
```
ENABLE_EXTERNAL_DIR_RESTRICTION=1 # Default: enabled
```
To disable the feature:
```
ENABLE_EXTERNAL_DIR_RESTRICTION=false
```
### Usage
1. **New sessions**: Config is automatically created when session starts
2. **Existing sessions**: Config is created next time `ensureSessionPaths()` runs
3. **Failed writes**: Logged but doesn't block session creation
## Security Benefits
1. **App isolation**: Prevents one app from accessing another app's files
2. **No user prompts**: Permission requests are handled automatically
3. **Minimal exposure**: Only allows access to current app's workspace directory
4. **Fail-safe**: If config creation fails, session continues (logs error)
## Testing Checklist
- [ ] Verify config file created in workspace directory
- [ ] Confirm OpenCode loads config (no permission prompts for same app)
- [ ] Test access to different app ID → auto-denied
- [ ] Verify no permission dialogs appear in builder UI
- [ ] Test with both UUID and slug app IDs
- [ ] Test with anonymous users
- [ ] Verify `ENABLE_EXTERNAL_DIR_RESTRICTION=false` disables feature
- [ ] Check that config file is ~200-300 bytes (minimal storage)
## Logs
On successful creation:
```
Created opencode config for session
sessionId: c7f9e5c6-e7c2-4258-a583-ccffcf9791c8
appId: my-shopify-app
userId: user123
```
On failure (non-blocking):
```
Failed to create opencode config
sessionId: c7f9e5c6-e7c2-4258-a583-ccffcf9791c8
error: EACCES: permission denied
```