# 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
```
