Skip to content

Consolidate workspace folder ACL logic and add a writability check#5948

Open
pietern wants to merge 2 commits into
mainfrom
validate-writable-file-path
Open

Consolidate workspace folder ACL logic and add a writability check#5948
pietern wants to merge 2 commits into
mainfrom
validate-writable-file-path

Conversation

@pietern

@pietern pietern commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Why

Reading bundle validate's remote-path handling (#5528) surfaced that we have no read-only way to tell a user, early, that they likely can't write to their workspace.file_path. Today that only fails at deploy. Reasoning about folder permissions was also split: folder_permissions.go owned the ancestor-walk traversal while bundle/permissions owned the ACL model. This lands one place for it and the reusable core for a follow-up writability warning.

What

  • Consolidate the traversal and ACL model into bundle/permissions as FolderACL (walks up to the closest existing ancestor for a not-yet-created folder).
  • CanWrite(user): CAN_EDIT+ directly or via a known group; conservative for admins and unknown group membership.
  • CheckWritable(...): three-valued (writable / not-writable / unknown), since reading a folder ACL itself requires manage access, so "cannot write" usually surfaces as a 403 on the read.

Groundwork only: no validator is wired up yet (the consuming validator is a follow-up, alongside #5528), and existing behavior is unchanged. ValidateFolderPermissions now calls ResolveFolderACL but produces the same diagnostics. Confined to bundle/permissions.

This pull request and its description were written by Isaac.

pietern added 2 commits July 16, 2026 15:47
The logic for reasoning about a workspace folder's access control was
split across two places: folder_permissions.go owned the traversal that
walks up to the closest existing ancestor, while bundle/permissions owned
the ACL model (WorkspacePathPermissions, ObjectAclToResourcePermissions).
Bring them together in bundle/permissions as FolderACL, so there is one
place that resolves and reasons about folder permissions.

Add a writability check with two entry points:

  - FolderACL.CanWrite inspects a readable ACL: does the user hold CAN_EDIT
    or higher, directly or via a known group. It is conservative, assuming
    write access for workspace admins (who bypass the folder ACL) and when
    group membership is not known here.

  - CheckWritable resolves the ACL and returns a three-valued result. This
    is necessary because reading a folder ACL itself requires manage access:
    verified against a live workspace, GET permissions returns 403 for
    folders the caller cannot manage, so the common "cannot write" case
    surfaces as a permission error on the read, not as a readable ACL that
    omits the user. CheckWritable maps that 403 to WritabilityNotWritable, a
    readable ACL to writable/not-writable, and anything else to unknown.

Tests use ACLs that mirror the shape of real workspace folder permissions
(a home dir with direct CAN_MANAGE; a shared dir with CAN_MANAGE via a
group the user belongs to) to confirm CanWrite agrees with those grants.

This is the reusable core for a future read-only "remote file path may not
be writable" validation. No validator is wired up yet and existing behavior
is unchanged: folder_permissions now calls ResolveFolderACL but produces the
same diagnostics.

Co-authored-by: Isaac
Cite the workspace ACL model (managing permissions is exclusive to
CAN_MANAGE) so the next reader can trace why CheckWritable treats a
permission-denied error on the permissions GET as a definite "not
writable" without re-probing the API.

Co-authored-by: Isaac
@eng-dev-ecosystem-bot

Copy link
Copy Markdown
Collaborator

Integration test report

Commit: f1c3824

Run: 29514807918

Env 🔄​flaky 💚​RECOVERED 🙈​SKIP ✅​pass 🙈​skip Time
🔄​ aws linux 2 4 4 225 1119 4:58
💚​ aws windows 4 4 229 1117 8:37
💚​ aws-ucws linux 4 4 316 1035 5:59
💚​ aws-ucws windows 4 4 318 1033 7:35
💚​ azure linux 4 4 227 1118 4:46
💚​ azure windows 4 4 229 1116 6:36
💚​ azure-ucws linux 4 4 318 1032 6:19
💚​ azure-ucws windows 4 4 320 1030 8:53
💚​ gcp linux 4 4 226 1120 4:38
💚​ gcp windows 4 4 228 1118 6:45
10 interesting tests: 4 RECOVERED, 4 SKIP, 2 flaky
Test Name aws linux aws windows aws-ucws linux aws-ucws windows azure linux azure windows azure-ucws linux azure-ucws windows gcp linux gcp windows
💚​ TestAccept 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R
🙈​ TestAccept/bundle/invariant/no_drift 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/vector_search_endpoints/drift/recreated_same_name 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/vector_search_indexes/recreate/embedding_dimension 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/ssh/connection 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🔄​ TestFilerWorkspaceNotebook 🔄​f ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p
🔄​ TestFilerWorkspaceNotebook/scalaNb.scala 🔄​f ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p ✅​p
💚​ TestFetchRepositoryInfoAPI_FromRepo 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R
💚​ TestFetchRepositoryInfoAPI_FromRepo/root 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R
💚​ TestFetchRepositoryInfoAPI_FromRepo/subdir 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R
Top 10 slowest tests (at least 2 minutes):
duration env testname
8:12 aws windows TestAccept
7:20 azure-ucws windows TestAccept
6:34 aws-ucws windows TestAccept
6:21 gcp windows TestAccept
6:12 azure windows TestAccept
2:55 azure linux TestAccept
2:53 azure-ucws linux TestAccept
2:51 aws linux TestAccept
2:50 gcp linux TestAccept
2:44 aws-ucws linux TestAccept

// "does not have Manage permissions" otherwise), so a 403 means the user cannot
// manage, and therefore cannot write to, the folder.
// See https://docs.databricks.com/aws/en/security/auth/access-control/
func CheckWritable(ctx context.Context, w workspace.WorkspaceInterface, folderPath string, user *iam.User) Writability {

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.

It's not called right now, is it expected for it to be called somewhere else later?

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.

3 participants