-
Notifications
You must be signed in to change notification settings - Fork 36
openai agents shell/apply_patch example #221
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
🦋 Changeset detectedLatest commit: eda06f8 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
237045a to
fff782d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Claude Code Review
Solid OpenAI Agents integration example. The SandboxShell and WorkspaceEditor implementations correctly bridge the two SDKs. However, several issues need attention:
Critical:
- Unused
@codesandbox/sandpack-reactdependency bloats the package - Auto-approval of shell commands and file operations needs prominent security warnings
- Path traversal protection should use proper path normalization
Important:
- Replace
error: anywith proper error types per CLAUDE.md standards - Investigate or remove commented
seedWorkspace()call - README needs security warnings and deployment guidance
Nice to have:
- Deduplicate CommandResult/FileOperationResult types between frontend/backend
- Remove unused
allResultsfield from API response - Add error boundary to React app
The core functionality is well-implemented with good UX. Address the critical issues before merging.
commit: |
🐳 Docker Image PublishedFROM cloudflare/sandbox:0.0.0-pr-221-a817d06Version: You can use this Docker image with the preview package from this PR. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Claude Code Review
This PR adds a well-structured example demonstrating OpenAI agents integration with the Sandbox SDK. The adapter pattern for Shell and Editor interfaces is sound, and the frontend provides good UX. However, there are critical security and correctness issues that must be fixed before merge.
Critical Issues
- Path traversal vulnerability in
resolve()- doesn't normalize..sequences before validation - Missing OpenAI API key configuration - README mentions it but code never uses it
- Invalid model name
gpt-5.1- not a valid OpenAI model - Extensive use of
anytype - violates repository standards (CLAUDE.md: "Never use theanytype") - Unused dependency
@codesandbox/sandpack-react- adds unnecessary weight
Major Issues
- Commented-out
seedWorkspace()with vague explanation should be removed or fixed - Missing
checkscript in package.json (other examples have this) - Not using centralized error classes from
@repo/shared/errors
Minor Issues
- Hardcoded
DEBUG = truein logger - Type duplication between frontend/backend
- Emoji usage violates coding standards
- localStorage parsing without error boundary
Verdict: Needs fixes before merge. The architecture is solid once security and type safety issues are addressed.
See inline comments for specific fixes.
examples/openai-agents/src/index.ts
Outdated
| throw new Error(`Operation outside workspace: ${relativePath}`); | ||
| } | ||
| // Normalize path separators | ||
| return resolved.replace(/\/+/g, '/'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CRITICAL: Path traversal vulnerability
This resolve() function doesn't normalize .. sequences before checking if path is within workspace. An attacker could use paths like foo/../../../etc/passwd which would pass the startsWith('/workspace') check but resolve outside the workspace.
Fix: Normalize the path before validation:
private resolve(relativePath: string): string {
const normalized = relativePath.replace(/^\.?\//, '');
const resolved = normalized ? `${this.root}/${normalized}` : this.root;
// Normalize to resolve .. sequences
const parts = resolved.split('/').filter(p => p !== '');
const stack: string[] = [];
for (const part of parts) {
if (part === '..') {
stack.pop();
} else if (part !== '.') {
stack.push(part);
}
}
const finalPath = '/' + stack.join('/');
if (!finalPath.startsWith(this.root)) {
throw new Error(`Operation outside workspace: ${relativePath}`);
}
return finalPath;
}
examples/openai-agents/src/logger.ts
Outdated
| @@ -0,0 +1,41 @@ | |||
| // Global flag to enable/disable logging | |||
| const DEBUG = true; | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: Hardcoded debug flag
Debug logging is always enabled in production. Consider using environment variable or the centralized logger from @repo/shared which supports SANDBOX_LOG_LEVEL.
| const saved = localStorage.getItem(STORAGE_KEY); | ||
| if (saved) { | ||
| try { | ||
| const parsed = JSON.parse(saved); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: localStorage parse error crashes app
If localStorage becomes corrupted, JSON.parse fails and user loses access to app. Add error recovery:
try {
const parsed = JSON.parse(saved);
setMessages(parsed);
} catch (error) {
console.error('Error loading history:', error);
localStorage.removeItem(STORAGE_KEY); // Clear corrupted data
}| JSON.stringify({ | ||
| error: errorMessage || 'Internal server error', | ||
| naturalResponse: 'An error occurred while processing your request.', | ||
| commandResults: [], | ||
| fileOperations: [] | ||
| }), |
Check warning
Code scanning / CodeQL
Information exposure through a stack trace Medium
stack trace information
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 1 day ago
To eliminate the possibility of exposing sensitive stack trace or other internal error information to the end user, only return a generic error message in HTTP responses. All specific information about the error (message and stack) should be logged server-side (which the code already does via console.error). To fix the issue, modify the handler to always send a fixed, generic error string (e.g., "Internal server error") in the JSON response's error field, regardless of the error.
Edit lines within the catch block of the handleRunRequest function (examples/openai-agents/src/index.ts, lines 130–151):
- Do NOT set the recipient error message to
getErrorMessage(error)(i.e., no expose the variableerrorMessage). - Instead, use a fixed error string (e.g.,
"Internal server error") for what is sent to the user. - Optionally, keep the server-side log unchanged: keep error message and stack for debugging.
- Make sure no direct or indirect exposure of error details goes to the response.
No new methods or imports are required since the console-based logging is sufficient.
-
Copy modified line R133 -
Copy modified line R140
| @@ -130,13 +130,14 @@ | ||
| } catch (error: unknown) { | ||
| const errorMessage = getErrorMessage(error); | ||
| const errorStack = getErrorStack(error); | ||
| // log full details server-side, but don't expose them to the client | ||
| console.error('[openai-example]', 'Error handling run request', { | ||
| error: errorMessage, | ||
| stack: errorStack | ||
| }); | ||
| return new Response( | ||
| JSON.stringify({ | ||
| error: errorMessage || 'Internal server error', | ||
| error: 'Internal server error', | ||
| naturalResponse: 'An error occurred while processing your request.', | ||
| commandResults: [], | ||
| fileOperations: [] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Claude Code Review
The path traversal vulnerability is still present and must be fixed. The resolve() function doesn't normalize .. sequences before validation, allowing paths like foo/../../../etc/passwd to pass the startsWith check but resolve outside /workspace when executed by the filesystem.
The README still lacks security warnings about auto-approved operations. This needs prominent documentation before anyone deploys this.
Most other issues from the previous review remain unaddressed (debug logging, localStorage recovery, emojis). These are less critical but should be cleaned up.
Verdict: Needs fixes before merge. Path traversal is the blocker.
Critical issues (must fix):
- Path traversal vulnerability in
resolve()function - Missing security warnings in README
Important issues (should fix):
- Hardcoded debug logging
- localStorage error recovery
Minor issues (nice to have):
- Remove emojis per coding standards
- Add input validation/rate limiting
- Only log stack traces in development
| @@ -0,0 +1,32 @@ | |||
| # OpenAI Agents with Cloudflare Sandbox | |||
|
|
|||
| A conversational AI assistant that executes shell commands and edits files in a Cloudflare Sandbox. | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
README needs prominent security warning before anyone deploys this. The auto-approval of all AI operations is a significant risk.
Suggest adding:
## Security Warning
**This example auto-approves all AI operations without human review.** The AI can:
- Execute ANY shell command
- Create, modify, or delete ANY file in /workspace
- No safety limits beyond the container itself
**Do not use in production without proper approval flows and rate limiting.**| const parsed = JSON.parse(saved); | ||
| setMessages(parsed); | ||
| } catch (error) { | ||
| console.error('Error loading history:', error); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If localStorage is corrupted, JSON.parse fails but the bad data isn't cleared. Add recovery:
} catch (error) {
console.error('Error loading history:', error);
localStorage.removeItem(STORAGE_KEY);
setMessages([]);
}There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still needs fixing - add localStorage.removeItem(STORAGE_KEY) in the catch block to clear corrupted data.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Claude Code Review
The OpenAI Agents integration is well-architected and follows SDK patterns correctly. However, there's a critical path traversal vulnerability that must be fixed before merge.
Critical Issues
Path traversal vulnerability remains unresolved. The resolve() method in Editor class (packages/sandbox/src/openai/index.ts:405-415) doesn't normalize .. sequences before validation. Paths like foo/../../../etc/passwd will pass the startsWith('/workspace') check but escape to parent directories when the filesystem resolves them.
This needs proper normalization that processes .. segments before checking containment. The current implementation only strips leading slashes and checks the literal string, which is insufficient.
README security warnings are missing. The example uses needsApproval: false which auto-approves all AI operations (arbitrary shell commands, file modifications) without any security warnings. Developers copying this for production will create serious vulnerabilities. Need prominent warnings about authentication, rate limiting, command whitelisting, and approval workflows before deployment.
Other Issues
Hardcoded debug logging (examples/openai-agents/src/logger.ts:2): DEBUG = true is always on, even in production. Use environment variable or the centralized logger from @repo/shared.
localStorage recovery (examples/openai-agents/src/app.tsx:57-60): Corrupted data isn't cleared, leaving app in broken state.
Stack trace exposure (flagged by GitHub Security): While logging internally is fine, add comments clarifying stack traces should never be exposed to clients.
What's Good
✓ No any types - excellent type safety
✓ Proper use of centralized logger in SDK
✓ Good package structure with separate exports
✓ Solid foundation for OpenAI integration
✓ Changeset properly created
Verdict
Needs fixes before merge - the path traversal vulnerability is a security blocker. After fixing that and adding README warnings, this will be ready to ship.
Introduces file creation, update, and deletion capabilities via a new WorkspaceEditor and applyPatchTool integration. Adds a logger utility for structured debug/info/error output throughout the backend. Refactors the UI to support persistent chat history, multi-column output, and improved message rendering. Updates dependencies to include Sandpack React for future file editing features. Improves documentation and exposes port 8080 in Dockerfile for local development.
Moved CommandResult and FileOperationResult interfaces to a new types.ts file and updated imports in app.tsx and index.ts. Removed @codesandbox/sandpack-react from dependencies and cleaned up related code. Updated env.d.ts for improved type safety and added a type-check script.
Introduces helper functions for consistent error property extraction and message formatting. Refactors error handling in SandboxShell, WorkspaceEditor, and handleRunRequest to use these helpers, improving reliability and clarity in error logging and reporting.
Introduces Shell and Editor adapters in packages/sandbox/src/openai for integrating OpenAI Agents with Cloudflare Sandbox, including structured command and file operation results. Updates examples/openai-agents to use these adapters, removes local types in favor of shared interfaces, and adds tests for the new adapters. Also updates package.json and tsdown config to export the new openai module and adjusts dependencies.
Reordered import statements for consistency in app.tsx, index.ts, and vite.config.ts. Fixed useEffect dependency array in App component to prevent unnecessary scrolling. Added explicit type to clear history button and improved key usage in list rendering.
2baf081 to
29dfb79
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Claude Code Review
This PR implements a clean OpenAI Agents integration with good adapter patterns and comprehensive result collection. However, there is one critical security vulnerability that must be fixed before merge.
Critical Issue: Path Traversal Vulnerability
The resolve() method in the Editor class doesn't properly sanitize .. segments before checking path boundaries. This allows directory traversal attacks like ../../etc/passwd to escape the workspace.
Required fix: Normalize path segments and validate containment before filesystem operations. See inline comment for implementation.
Architecture Issues
- Error handling: Should use centralized error types from
@repo/shared/errorsinstead of genericErrorinstances (or document why standard errors are required by OpenAI Agents contract) - Logger naming: Component should be
'sandbox-client'not'sandbox-do'since this code runs in the SDK layer - Test types: Remove
anytypes in tests, use proper mock interfaces per project standards
Missing Test Coverage
Critical: Add security tests for path traversal attempts (../, ../../, etc.)
Recommended: Add tests for edge cases like non-zero exit codes, stderr output, nested directories, and concurrent operations.
Positive Aspects
- Clean adapter pattern implementation
- Excellent structured result collection (CommandResult[], FileOperationResult[])
- Proper timeout handling
- Type-safe error guards
- Correct optional peer dependency pattern
- Changeset follows project rules
Verdict
Needs fixes before merge - specifically the path traversal vulnerability and security tests. The other issues are important for consistency but not blocking if you want to address them in a follow-up.
|
|
||
| const logger: Logger = createLogger({ | ||
| component: 'sandbox-do', | ||
| operation: 'openai-agent' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Logger component name should be 'sandbox-client' or 'openai-adapter', not 'sandbox-do'. This code runs in the SDK client layer, not in the Durable Object. Using 'sandbox-do' makes debugging harder since logs incorrectly indicate their source.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot fix this please
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still shows 'sandbox-do' on line 38-39. Should be 'openai-adapter' to accurately reflect this runs in the SDK client layer.
| logger.error('Cannot update missing file', undefined, { | ||
| path: operation.path | ||
| }); | ||
| throw new Error(`Cannot update missing file: ${operation.path}`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider using centralized error types from @repo/shared/errors (e.g., ErrorCode.FILE_NOT_FOUND) instead of generic Error instances. This maintains consistency with the SDK's architecture pattern documented in CLAUDE.md.
If the OpenAI Agents contract requires standard Error objects, that's fine - just ensure enough context is included for debugging.
Introduces strict path normalization and validation in the Editor class to prevent file operations outside the workspace via path traversal (e.g., '../'). Extensive tests were added to verify security against various traversal attempts. The README now includes a security warning about auto-approval and risks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Claude Code Review
Good progress on addressing previous feedback. The path traversal security is now solid - I traced through multiple attack scenarios and the stack-based normalization correctly handles all edge cases.
Still need fixes for:
-
Logger component name (line 38-39 of openai/index.ts): Still shows
'sandbox-do'but should be'openai-adapter'. This makes debugging harder since logs incorrectly indicate their source. -
Error stack exposure (lines 132-136 of example worker):
getErrorStack()function exists but stack traces shouldn't be in API responses - only server logs. Either remove the function or clarify it's internal-only. -
localStorage error recovery (app.tsx line 60): When JSON.parse fails on corrupted data, the bad data isn't cleared. Add
localStorage.removeItem(STORAGE_KEY)in the catch block.
The rest looks good - excellent test coverage, proper type safety, and clear security warnings in the README.
Verdict: Fix these three issues before merge.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Claude Code Review
The localStorage issue from my previous review is still not fixed. The catch block at line 59 needs localStorage.removeItem(STORAGE_KEY) to handle corrupted data.
New issues found:
Critical:
- Invalid model name 'gpt-5.1' in examples/openai-agents/src/index.ts:78 - this will cause runtime errors. Use 'gpt-4o' or another valid OpenAI model.
- Hardcoded platform in examples/openai-agents/Dockerfile:9 breaks on non-ARM64 systems
Code quality:
- Error handling utilities duplicated between packages/sandbox/src/openai/index.ts and examples/openai-agents/src/index.ts - should move to shared package
Positive:
- Comprehensive security testing for path traversal
- No
anytypes - proper type safety throughout - Excellent documentation with clear security warnings
- Good architectural patterns
Needs fixes before merge.
| const parsed = JSON.parse(saved); | ||
| setMessages(parsed); | ||
| } catch (error) { | ||
| console.error('Error loading history:', error); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still missing localStorage.removeItem(STORAGE_KEY) here. When JSON.parse fails due to corrupted data, the corrupted data remains in localStorage and breaks the app on every reload. Add:
catch (error) {
console.error('Error loading history:', error);
localStorage.removeItem(STORAGE_KEY);
}|
|
||
| # On a mac, you might need to actively pick up the | ||
| # arm64 build of the image. | ||
| FROM --platform=linux/arm64 cloudflare/sandbox-test:0.5.0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hardcoded --platform=linux/arm64 breaks on non-ARM64 systems (Intel Macs, Linux x64). The official images support both platforms, so remove the platform flag:
FROM cloudflare/sandbox-test:0.5.0| }); | ||
|
|
||
| // Helper functions for error handling | ||
| function isErrorWithProperties(error: unknown): error is { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These error handling utilities (lines 44-68) are duplicated in examples/openai-agents/src/index.ts (lines 8-31). Move to packages/shared/src/error-utils.ts for reusability:
import { isErrorWithProperties, getErrorMessage, toError } from '@repo/shared';
Uh oh!
There was an error while loading. Please reload this page.