Skip to content

fix(harness-opencode): allow external directory access with permissionMode: "allow-all" - #21191

Merged
felixarntz merged 5 commits into
mainfrom
bugfix-21187-20260920020212054720
Sep 21, 2026
Merged

felixarntz merged 5 commits into
mainfrom
bugfix-21187-20260920020212054720

Conversation

@ai-sdk-factory

@ai-sdk-factory ai-sdk-factory Bot commented Sep 20, 2026

Copy link
Copy Markdown
Contributor

Background

The PR reordered permission evaluation and introduced canonical filesystem containment; review identified an overbroad traversal boundary.

Root Cause

Allow-all was evaluated after external rejection, lexical paths mishandled symlinks, and startsWith('..') conflated traversal with valid dot-prefixed names.

Summary

Allow-all now permits external access, canonical containment blocks symlink escapes, and separator-aware traversal detection preserves valid dot-prefixed children.

Testing

Regression coverage includes allow-all external access, symlink-backed workdirs, symlink escapes, and ..cache children. All validation passed.

End-to-end Validation

  • Original reproduction replay no longer reproduces.
  • Full harness-opencode suite passes.
  • Package build and workspace validation pass.

Related Issues

Fixes #21187

Closes #21189

ai-sdk-factory and others added 3 commits September 20, 2026 02:07
Co-authored-by: davidcolatti-eve <314377486+davidcolatti-eve@users.noreply.github.com>
Co-authored-by: davidcolatti-eve <314377486+davidcolatti-eve@users.noreply.github.com>
@ai-sdk-factory

Copy link
Copy Markdown
Contributor Author

Bugfix review

Outcome: changes-required

Reproduction replay

Status: no-longer-reproduces

The exact original reproduction completed successfully and the original bug signal did not appear.

Fixes issue

Status: fully-addresses

The permission check now honors allow-all before external-path rejection, and canonical path comparison handles symlink-backed work directories while rejecting symlink escapes in restrictive modes.

Side effects

Risk: low

The new containment predicate incorrectly rejects a narrow class of legitimate in-workdir paths under restrictive permission modes.

Concerns:

  • packages/harness-opencode/src/bridge/index.ts:1404 treats every relative path beginning with '..' as an escape, so valid children such as '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/..cache/file' or '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/.../file' are rejected as external.

Performance

Risk: low

Canonicalization adds synchronous realpath calls for restrictive permission requests, but the work is bounded by resource count and path depth and presents no material memory risk.

Backwards compatibility

Risk: none

The change does not read, migrate, or alter stored sessions, configuration files, or other persisted data.

Breaking changes

Risk: low

No public API, type, export, default, or persisted format changes, but restrictive modes gain an observable false rejection for valid paths whose first relative component starts with two dots.

Concerns:

  • Use an escape test that distinguishes '..' and '..' followed by a path separator from valid names such as '..cache'; the current startsWith('..') check narrows previously accepted path inputs.

Architecture

Risk: none

The implementation remains private to the OpenCode bridge, follows existing dependency direction, and introduces no cross-package source import, export, or misplaced shared abstraction.

Change scope

Status: minimal

The production change, focused bridge regression tests, and patch changeset are all directly related to fixing and validating the reported permission behavior.

Security

Risk: none

External access is enabled only for the documented allow-all mode, while restrictive modes now canonicalize paths and reject tested symlink escapes.

Testing

Status: needs-more

Tests cover allow-all external access, symlink-backed work directories, and symlink escapes, but miss the containment boundary that exposes the new false rejection.

Concerns:

  • Add a restrictive-mode regression test proving that an in-workdir child whose name begins with '..', such as '..cache/file', remains allowed.

Verification

Inspected the complete merge-base diff and permission flow, ran the full harness-opencode test suite successfully with 107 tests, passed package type checking and changed-file formatting checks, and used a focused path-containment probe that confirmed valid '..cache' and '...' child paths are classified as outside.

Relevant Documentation

Co-authored-by: davidcolatti-eve <314377486+davidcolatti-eve@users.noreply.github.com>
Co-authored-by: ai-sdk-factory[bot] <305873210+ai-sdk-factory[bot]@users.noreply.github.com>
Co-authored-by: Felix Arntz <3531426+felixarntz@users.noreply.github.com>
@ai-sdk-factory ai-sdk-factory Bot changed the title fix: OpenCode allow-all mode rejects external directory access fix: OpenCode permission handling rejected external paths under allow-all and could misclassify canonical or dot-prefixed in-workdir paths. Sep 21, 2026
@ai-sdk-factory

Copy link
Copy Markdown
Contributor Author

Addressed PR comment 5757559326.

Bugfix review

Outcome: changes-required

Reproduction replay

Status: no-longer-reproduces

... 73 more line(s) omitted

Addressed. The containment predicate now rejects only an exact .. segment or .. followed by the platform separator, so valid children such as ..cache/file remain inside the workdir. The restrictive-mode regression test now verifies that path is allowed while the symlink escape is still rejected. All package tests, type checks, formatting/lint checks, and the package build pass.

@ai-sdk-factory

Copy link
Copy Markdown
Contributor Author

Bugfix review

Outcome: approved

Reproduction replay

Status: no-longer-reproduces

The exact original reproduction completed successfully and the original bug signal did not appear.

Fixes issue

Status: fully-addresses

Allow-all is evaluated before external-path rejection, while canonical containment handles symlink-backed work directories and blocks symlink escapes in restrictive modes.

Side effects

Risk: low

Restrictive modes now intentionally reject paths whose canonical targets escape the work directory; separator-aware traversal detection preserves legitimate dot-prefixed children such as '..cache'.

Performance

Risk: low

Restrictive permission checks add bounded synchronous realpath resolution per resource and path ancestor, with no material memory-growth risk.

Backwards compatibility

Risk: none

The change does not read, migrate, or alter stored sessions, configuration files, or persisted data formats.

Breaking changes

Risk: none

No public APIs, types, exports, accepted configuration shapes, defaults, output formats, or persisted formats change; the observable permission change corrects allow-all and restrictive containment semantics.

Architecture

Risk: none

The implementation remains private to the OpenCode bridge, preserves package boundaries and dependency direction, and adds no cross-package source imports or misplaced shared abstractions.

Change scope

Status: minimal

The bridge permission changes, focused regression tests, and patch changeset are all directly necessary to fix and verify the reported behavior.

Security

Risk: none

External access is enabled only for allow-all, while restrictive modes canonicalize paths and reject symlink escapes, improving containment without exposing credentials or new attack surfaces.

Testing

Status: appropriate

Regression coverage verifies allow-all external access, symlink-backed work directories, symlink escapes, and valid dot-prefixed children under restrictive modes.

Verification

Inspected the complete merge-base diff and permission flow; the full harness-opencode suite passed with 107 tests, and package type checking, build, changed-file formatting, linting, and diff checks all passed.

Relevant Documentation

Comment thread .changeset/friendly-otters-approve.md Outdated
@felixarntz felixarntz changed the title fix: OpenCode permission handling rejected external paths under allow-all and could misclassify canonical or dot-prefixed in-workdir paths. fix(harness-opencode): allow external directory access with permissionMode: "allow-all" Sep 21, 2026
@felixarntz
felixarntz merged commit 01a671a into main Sep 21, 2026
53 checks passed
@felixarntz
felixarntz deleted the bugfix-21187-20260920020212054720 branch September 21, 2026 12:24
@github-actions

Copy link
Copy Markdown
Contributor

🚀 Published in:

Package Version
ai 7.0.108 github npm
@ai-sdk/amazon-bedrock 5.0.89 github npm
@ai-sdk/angular 3.0.108 github npm
@ai-sdk/azure 4.0.76 github npm
@ai-sdk/code-mode 1.0.65 github npm
@ai-sdk/deepseek 3.0.50 github npm
@ai-sdk/gateway 4.0.88 github npm
@ai-sdk/harness 1.0.118 github npm
@ai-sdk/harness-acp 1.0.56 github npm
@ai-sdk/harness-claude-code 1.0.122 github npm
@ai-sdk/harness-cline 1.0.45 github npm
@ai-sdk/harness-codex 1.0.120 github npm
@ai-sdk/harness-cursor 1.0.31 github npm
@ai-sdk/harness-deepagents 1.0.118 github npm
@ai-sdk/harness-fx 1.0.31 github npm
@ai-sdk/harness-github-copilot 1.0.13 github npm
@ai-sdk/harness-grok-build 1.0.55 github npm
@ai-sdk/harness-opencode 1.0.120 github npm
@ai-sdk/harness-pi 1.0.120 github npm
@ai-sdk/langchain 3.0.108 github npm
@ai-sdk/llamaindex 3.0.108 github npm
@ai-sdk/mcp 2.0.55 github npm
@ai-sdk/openai 4.0.72 github npm
@ai-sdk/otel 1.0.108 github npm
@ai-sdk/policy-opa 1.0.108 github npm
@ai-sdk/react 4.0.111 github npm
@ai-sdk/rsc 3.0.108 github npm
@ai-sdk/sandbox-just-bash 1.0.118 github npm
@ai-sdk/sandbox-vercel 1.0.118 github npm
@ai-sdk/svelte 5.0.108 github npm
@ai-sdk/tui 1.0.109 github npm
@ai-sdk/vue 4.0.108 github npm
@ai-sdk/workflow 2.0.39 github npm
@ai-sdk/workflow-harness 1.0.118 github npm
@ai-sdk/xai 5.0.5 github npm

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

harness-opencode: permissionMode: "allow-all" cannot allow external directory access

2 participants