Skip to content

fix(server): reject unusable session location directories with 400 - #59162

Open
LeizhenZhang wants to merge 1 commit into
anomalyco:devfrom
LeizhenZhang:location-input-400
Open

LeizhenZhang wants to merge 1 commit into
anomalyco:devfrom
LeizhenZhang:location-input-400

Conversation

@LeizhenZhang

@LeizhenZhang LeizhenZhang commented Oct 26, 2026 •

Copy link
Copy Markdown

Issue for this PR

Part of #59164

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

POST /api/session and session import accepted any string as location.directory. A relative path or one with a NUL byte reached the database and filesystem layers, and the client got an empty HTTP 500. The two payloads now use Location.Input, whose directory must be a POSIX, drive or UNC absolute path without NUL bytes, so a bad body location is a 400 InvalidRequestError.

Location hints in the query string and the x-opencode-directory header are left as they are. #59414 covers those entry points (middleware, forms, debug, PTY, MCP client) and keeps relative hints such as ?location[directory]=. working, so this PR stays out of its way.

How did you verify your code works?

Rebased onto dev at 986221af on 2026-10-30. The generated client type now follows the experimental import namespace introduced on dev.

  • New packages/server/test/location-input.test.ts: a NUL byte and a relative directory in the POST /api/session body. Both return 500 on dev and fail, both return 400 with the fix.
  • session-create and session-import tests pass (9 tests together with the new file).
  • bun run generate in packages/client: only SessionCreateInput.location and ExperimentalSessionImportInput.location change, from Location.PublicRef to Location.Input.
  • Before the rebase, bun run typecheck in schema, protocol, server and client, prettier on the touched files, and the root bun run check (35/35) passed. On rebased head b1bfbe6, the two new server tests pass, check:generated passes, and schema, protocol, client and server typechecks pass. The full root check has not been rerun on this head.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

Added by the opencode bot (AI-generated).

Part of #59164

Public API: session create/import location.directory must be an absolute path without NUL bytes (new Location.Input / Location.Directory); bad values get a 400 instead of a 500

@github-actions github-actions Bot added needs:compliance This means the issue will auto-close after 2 hours. and removed needs:compliance This means the issue will auto-close after 2 hours. labels Oct 26, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Thanks for updating your PR! It now meets our contributing guidelines. 👍

@opencode-agent opencode-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fix works. With the requests from #59164, the base returns an empty 500 for both the NUL-byte query directory and the relative POST /api/session location. With this PR, both return a 400 InvalidRequestError. Absolute directories and requests with no directory still return 200. The new test fails on the base and passes here, and the existing session create/import/form/instances tests pass.

Public API:

  • Session create and import payloads: location changes from Location.PublicRef to the new Location.Input, which requires an absolute POSIX, drive or UNC path without NUL bytes. In the generated client, SessionCreateInput.location and SessionImportInput.location change type the same way.
  • Schema exports: @opencode/schema/location adds Directory and Input.
  • Location query and header: location[directory] and x-opencode-directory now return 400 for relative or NUL-containing directories.
  • Compatibility: compatible for callers that send absolute paths, which as far as I can see includes the CLI and client. However, ?location[directory]=. returned 200 on dev and now returns 400, and a relative x-opencode-directory header changes from 404 to 400. Please confirm this change is intended.

Concerns:

  • Routes without the check: pty.connect (handlers/pty.ts) and mcp.client (handlers/mcp.ts) still read the directory with requestRef directly, so the new check never runs there. handlers/debug.ts does the same. Routing those through requestLocation would cover every location entry point.
  • Overlap with #54619: that open PR validates the same entry points but keeps relative paths working, so the two approaches should be reconciled.

Fixes #59164

@LeizhenZhang LeizhenZhang changed the title fix(server): reject unusable location directories with 400 fix(server): reject unusable session location directories with 400 Oct 27, 2026
@LeizhenZhang

Copy link
Copy Markdown
Author

Thanks for the review. I narrowed this PR to the request body (head 07e72fafb0):

@opencode-agent opencode-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new commits narrow the PR to the session create and import payloads, and that part works. With the #59164 script, a relative or NUL-byte location.directory in POST /api/session returns an empty 500 on dev and a 400 InvalidRequestError with this PR, while an absolute directory still returns 200. The new test and the session create/import tests pass, and bun run generate leaves the committed client files unchanged.

The earlier points are addressed by keeping the query and header middleware as they are and leaving that to #59414. Relative hints like ?location[directory]=. keep working, and the overlap with #59414 is gone.

Public API:

  • Session create and import payloads: the location field changes from Location.PublicRef to the new Location.Input. The directory must now be an absolute POSIX, drive or UNC path without NUL bytes, and other values get a 400 where they used to get a 500. The generated client's SessionCreateInput.location and SessionImportInput.location change type the same way.
  • Schema exports: @opencode/schema/location adds Directory and Input.
  • Compatibility: compatible for callers that send absolute paths, which the CLI and client do.

Concern: the description now says Closes #59164, but the issue's first case (GET /api/agent?location[directory]=%00) still returns an empty 500 with this PR. That case is left to #59414. Merging this would close the issue while half of it is still open. Please use "Part of #59164" until #59414 lands.

Session create and import accepted any string as location.directory. A relative path or one with a NUL byte reached the database and filesystem layers and the client got an empty HTTP 500. The two payloads now use Location.Input, whose directory must be a POSIX, drive or UNC absolute path without NUL bytes, so a bad body location is a 400 InvalidRequestError. Location hints in the query and header are left as they are.
@LeizhenZhang

Copy link
Copy Markdown
Author

Rebased onto current dev (986221af); new head b1bfbe6, mergeable. I regenerated the client API from the current protocol: the generated import type is now ExperimentalSessionImportInput, matching dev. check:generated passes, the two location-input server tests pass, and schema, protocol, client, and server typechecks pass. The full root check has not been rerun on this head.

@LeizhenZhang

Copy link
Copy Markdown
Author

On b1bfbe6, check, check-test, check-bot-scope and check-nix remain action_required; the inspected check and check-test runs have zero jobs. Local validation on this head passed check:generated, both location-input server tests, and schema/protocol/client/server typechecks. The full root check has not been rerun. Could a maintainer approve or trigger CI when appropriate?

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant