Files
shopify-ai-backup/EXTERNAL_DIR_PERMISSION_FIX.md

3.4 KiB

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

{
  "$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