Skip to content

fix(execd): skip chmod/chown for pre-existing dirs in MakeDir#1044

Closed
ashishpatel26 wants to merge 2 commits into
opensandbox-group:mainfrom
ashishpatel26:fix/issue-1024-v2
Closed

fix(execd): skip chmod/chown for pre-existing dirs in MakeDir#1044
ashishpatel26 wants to merge 2 commits into
opensandbox-group:mainfrom
ashishpatel26:fix/issue-1024-v2

Conversation

@ashishpatel26

Copy link
Copy Markdown

Summary

  • MakeDir called os.MkdirAll then unconditionally called ChmodFile on the target path
  • For pre-existing directories (e.g. /tmp, /workspace) owned by a different user, the chmod/chown syscall fails with "operation not permitted", breaking subsequent writeFile calls
  • Fix: os.Stat before MkdirAll — if the path already exists, skip permission changes entirely; only newly-created directories get chmod/chown applied

Test plan

  • go test ./pkg/web/controller/... — 3 new unit tests: new dir created, pre-existing dir mode unchanged, nested create doesn't chmod parents

Fixes #1024

When createDirectories is called on a path whose parent components
already exist (e.g. /tmp), MakeDir was unconditionally calling
ChmodFile on the target after os.MkdirAll, even if the directory
was not newly created. For system directories the process does not
own this causes 'chmod: operation not permitted'.

Fix: stat the target before MkdirAll; if it already exists, skip
ChmodFile entirely. Only newly-created directories receive the
requested permission. This matches POSIX mkdir -p --mode semantics.

Fixes opensandbox-group#1024
Copilot AI review requested due to automatic review settings June 12, 2026 17:38
@github-actions

Copy link
Copy Markdown
Contributor

⚠️ This PR has no labels. Please add one based on the changes.

Changed directories: components.

📋 Recommended labels (based on changed files):

  • component/execd ⬅️

Other available labels:

  • bug - Something isn't working
  • dependencies - Pull requests that update a dependency file
  • documentation - Improvements or additions to documentation
  • feature - New feature or request
  • packages - Changes for package, image and configuration

💡 Tip: Use feature for new functionality or improvements, bug for fixes.

cc @ashishpatel26

Copilot AI 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.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Updates MakeDir to avoid applying chmod/chown on directories that already exist, preventing failures when the process lacks ownership/permissions, and adds regression tests to validate idempotent behavior.

Changes:

  • Detect whether the target directory exists before os.MkdirAll, and skip ChmodFile if it does.
  • Add tests covering new directory creation, idempotency on existing dirs, and nested directory creation with pre-existing parents.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.

File Description
components/execd/pkg/web/controller/utils_windows.go Skip chmod/chown for pre-existing directories in MakeDir (Windows variant).
components/execd/pkg/web/controller/utils.go Skip chmod/chown for pre-existing directories in MakeDir (non-Windows/shared variant).
components/execd/pkg/web/controller/utils_test.go Add tests validating MakeDir behavior for new/existing/nested directories.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +162 to +163
_, statErr := os.Stat(abs)
alreadyExisted := statErr == nil
Comment on lines +169 to +171
if alreadyExisted {
return nil
}
Comment on lines +126 to +127
_, statErr := os.Stat(abs)
alreadyExisted := statErr == nil
require.Equal(t, before.Mode(), after.Mode(), "MakeDir must not chmod a pre-existing directory")
}

func TestMakeDirCreatesNestedDirectoriesWithoutChmodingParents(t *testing.T) {
Comment on lines +73 to +82
func TestMakeDirCreatesNewDirectory(t *testing.T) {
tmp := t.TempDir()
newDir := filepath.Join(tmp, "newdir")

require.NoError(t, MakeDir(newDir, model.Permission{Mode: 755}))

info, err := os.Stat(newDir)
require.NoError(t, err)
require.True(t, info.IsDir())
}
@ashishpatel26

Copy link
Copy Markdown
Author

Thanks for the reviews. Addressing feedback:

Copilot – Use errors.Is(statErr, os.ErrNotExist) instead of statErr == nil: Valid. The current alreadyExisted := statErr == nil conflates permission errors and IO errors with "does not exist". A permission-denied error on os.Stat would incorrectly set alreadyExisted = false and proceed to MkdirAll. Will change to errors.Is(statErr, os.ErrNotExist) and return non-ErrNotExist errors early. Same fix will be applied to utils_windows.go.

Copilot – Undocumented semantics change: Valid. The updated behavior (skip chmod on pre-existing dirs) is intentional to avoid "operation not permitted" when callers pass system directories like /tmp. Will add a function-level comment documenting this.

Copilot – Test doesn't assert applied permissions: Will add an assertion on the resulting permission bits on non-Windows platforms.

Copilot – Typo in test identifier Chmoding: Will fix to ChmodingNewDir or similar.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ec49e55b8c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +172 to +173
if alreadyExisted {
return nil

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Apply requested permissions for explicitly listed parents

When a single /directories request includes both a parent and a nested child (for example /workspace/project with mode 700 and /workspace/project/logs with mode 755), MakeDirs iterates the request map in unspecified order; if the child is handled first, os.MkdirAll creates the parent with default permissions, and the later explicit parent entry now returns here without applying its requested mode/owner. That regresses multi-directory requests from the public API's “map of directory paths to permission objects” behavior, leaving explicitly requested directories with default permissions depending on map iteration order.

Useful? React with 👍 / 👎.

@Pangjiping

Copy link
Copy Markdown
Collaborator

Duplicate of #1025

@Pangjiping Pangjiping marked this as a duplicate of #1025 Jun 13, 2026
@Pangjiping Pangjiping closed this Jun 13, 2026
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.

createDirectories chmods pre-existing directories, breaking writeFile under /tmp and other system dirs

3 participants