Skip to content

Fix #5682: add IS_OWNER for permissions added by Python mutators - #5821

Merged
denik merged 6 commits into
mainfrom
denik/permissions-5682-one-owner
Jul 6, 2026
Merged

Fix #5682: add IS_OWNER for permissions added by Python mutators#5821
denik merged 6 commits into
mainfrom
denik/permissions-5682-one-owner

Conversation

@denik

@denikdenik commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Permissions added to an existing job/pipeline by a PyDABs mutator went through NormalizeResources, which skipped FixPermissions. The deploying user was never added as IS_OWNER, so the direct engine sent an ownerless permissions PUT and the API rejected it with The <resource> must have exactly one owner (#5682). The terraform provider re-injects the owner at PUT time, which is why the same bundle worked on terraform but failed on the direct engine.

Fix: run FixPermissions in NormalizeResources so permissions added by a Python mutator get the same owner treatment as permissions declared in YAML. FixPermissions is idempotent, so it is a no-op for resources that already have an owner; ApplyBundlePermissions is intentionally not re-run (not idempotent, already applied earlier). FixPermissions also now skips when CurrentUser is unset.

Includes an acceptance test that deploys a pipeline whose only permission is added by a Python mutator; verified against real AWS on both engines.

This pull request and its description were written by Isaac.

@denik
deniktemporarily deployed to test-trigger-is July 3, 2026 11:55 — with GitHub Actions Inactive
@denik
deniktemporarily deployed to test-trigger-is July 3, 2026 11:55 — with GitHub Actions Inactive
@eng-dev-ecosystem-bot

eng-dev-ecosystem-bot commented Jul 3, 2026

Copy link
Copy Markdown
Collaborator

Integration test report

Commit: cc5aac3

Run: 28666047764

Env💚​RECOVERED🙈​SKIP✅​pass🙈​skipTime
💚​aws linux41523010464:21
💚​aws windows41523210443:37
💚​aws-ucws linux4153149646:20
💚​aws-ucws windows4153169624:09
💚​azure linux41523010454:08
💚​azure windows41523210433:39
💚​azure-ucws linux4153169615:55
💚​azure-ucws windows4153189593:59
💚​gcp linux41522910473:41
💚​gcp windows41523110453:47
19 interesting tests: 15 SKIP, 4 RECOVERED
Test Nameaws linuxaws windowsaws-ucws linuxaws-ucws windowsazure linuxazure windowsazure-ucws linuxazure-ucws windowsgcp linuxgcp 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/permissions🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S
🙈​TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/with_permissions🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S
🙈​TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/without_permissions🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S
🙈​TestAccept/bundle/resources/postgres_branches/basic🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S
🙈​TestAccept/bundle/resources/postgres_branches/recreate🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S
🙈​TestAccept/bundle/resources/postgres_branches/replace_existing🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S
🙈​TestAccept/bundle/resources/postgres_branches/update_protected🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S
🙈​TestAccept/bundle/resources/postgres_branches/without_branch_id🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S
🙈​TestAccept/bundle/resources/postgres_endpoints/basic🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S
🙈​TestAccept/bundle/resources/postgres_projects/update_display_name🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S🙈​S
🙈​TestAccept/bundle/resources/synced_database_tables/basic🙈​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
💚​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 5 slowest tests (at least 2 minutes):
durationenvtestname
3:02gcp windowsTestAccept
2:46aws windowsTestAccept
2:44azure windowsTestAccept
2:41aws-ucws windowsTestAccept
2:37azure-ucws windowsTestAccept

@denik
deniktemporarily deployed to test-trigger-is July 3, 2026 12:22 — with GitHub Actions Inactive
@denik
deniktemporarily deployed to test-trigger-is July 3, 2026 12:22 — with GitHub Actions Inactive
@denikdenik changed the title Reproduce #5682: Python-mutator permissions miss IS_OWNER on direct engineFix #5682: add IS_OWNER for permissions added by Python mutatorsJul 3, 2026
denik added a commit that referenced this pull request Jul 3, 2026
Co-authored-by: Isaac
denik added 5 commits July 3, 2026 16:02
Permissions added to an existing resource by a PyDABs job/pipeline mutator go
through NormalizeResources (UpdatedResources path), which does not run
FixPermissions. The deploying user is therefore never added as IS_OWNER, and the
direct engine PUTs an ownerless ACL that the Permissions API rejects with
"The pipeline must have exactly one owner". The terraform provider re-injects the
owner at PUT time, so it succeeds - hence the terraform-vs-direct divergence.
Model the real backend rule (jobs and pipelines require exactly one owner; zero
or two both fail) in the testserver, and add an acceptance test that deploys and
records the per-engine outcome.
Co-authored-by: Isaac
Convert the reproduction to a real deploy against a UC pipeline: notebook
library, unique names via envsubst, a real grantee group on cloud, and cleanup.
Add INVALID_PARAMETER_VALUE to the testserver's owner error to match the real
Permissions API response shown in the issue.
Co-authored-by: Isaac
Permissions added to an existing resource by a PyDABs job/pipeline mutator went
through NormalizeResources, which ran only the normalize mutators and skipped
FixPermissions. The deploying user was therefore never added as IS_OWNER, and the
direct engine PUT an ownerless ACL that the Permissions API rejects with
"must have exactly one owner". The terraform provider re-injected the owner at PUT
time, hiding the bug for that engine.
Run FixPermissions in NormalizeResources so Python-sourced permissions get the same
owner treatment as YAML ones. FixPermissions is idempotent, so re-running it on
resources that already have an owner is a no-op; ApplyBundlePermissions is not
re-run because it is not idempotent and already ran in ProcessStaticResources.
Guard FixPermissions against a nil CurrentUser, which is possible when it runs
outside the initialize phase.
Co-authored-by: Isaac
Co-authored-by: Isaac
The testserver now enforces exactly-one-owner for pipelines (like jobs), so the
pipelines.permissions CRUD fixture must set IS_OWNER instead of CAN_MANAGE.
Co-authored-by: Isaac
@denik
denikforce-pushed the denik/permissions-5682-one-owner branch from 796efdb to 1306a5dCompareJuly 3, 2026 14:07
@denik
deniktemporarily deployed to test-trigger-is July 3, 2026 14:07 — with GitHub Actions Inactive
@denik
deniktemporarily deployed to test-trigger-is July 3, 2026 14:07 — with GitHub Actions Inactive
@denik
deniktemporarily deployed to test-trigger-is July 3, 2026 14:13 — with GitHub Actions Inactive
@denik
deniktemporarily deployed to test-trigger-is July 3, 2026 14:13 — with GitHub Actions Inactive
@denik
denik added this pull request to the merge queueJul 6, 2026
Merged via the queue into main with commit de465e0Jul 6, 2026
25 checks passed
@denik
denik deleted the denik/permissions-5682-one-owner branch July 6, 2026 08:26
deco-sdk-taggingBot added a commit that referenced this pull request Jul 9, 2026
## Release v1.7.0
### CLI
* An explicitly selected profile (`--profile` or a bundle's `workspace.profile`) now takes precedence over auth environment variables (`DATABRICKS_HOST`, `DATABRICKS_TOKEN`, etc.) instead of being silently shadowed by them; env vars still fill auth fields the profile leaves empty ([#5096](#5096)).
* Fix intermittent crashes when processing pages from API calls ([#5815](#5815)).
### Bundles
* direct: add basic version of job_runs resource (experimental) ([#5603](#5603)).
* Fix permissions added to a job or pipeline by a Python (PyDABs) mutator failing to deploy with "must have exactly one owner"; the deploying identity is now set as owner, matching resources whose permissions are declared in YAML ([#5821](#5821)).
* Remove duplicate enum values for jsonschema.json ([#5839](#5839)).
* direct: volumes: support `volume_path` property ([#5550](#5550)).
* direct: Fix deploy bug when a `postgres_projects`, `postgres_branches`, or `postgres_endpoints` field is set to its zero value (e.g. `enable_pg_native_login: false`, `replace_existing: false`) ([#5782](#5782)).
* `bundle run --only` help now documents the `+` modifier syntax: prefix a task key with `+` to also run its upstream tasks, or suffix it with `+` for downstream tasks ([#5760](#5760)).
* direct: Recognize UC-managed catalog and schema property defaults to avoid unnecessary drift ([#5865](#5865) & [#5870](#5870)).
* Fix `bundle deploy --select <resource>` skipping the resource's grants and permissions; they are now applied as part of the selected resource ([#5852](#5852)).
* Support `purge_on_delete: true` on `postgres_branches` so bundles can hard-delete a Lakebase branch on destroy (skipping the soft-delete retention window) ([#5801](#5801)).
* Support `replace_existing: true` on `postgres_databases` and `postgres_roles` so bundles can take over a database or role that already exists on a Lakebase branch instead of failing with `ALREADY_EXISTS` ([#5803](#5803)).
### Dependency updates
* Bump databricks-sdk-go to v0.154.0 ([#5855](#5855)).
* Bump terraform-provider to 1.121.0 ([#5857](#5857)).
* Bump OpenTelemetry dependencies to v1.44.0 to address [CVE-2026-41178](GHSA-5wrp-cwcj-q835) ([#5873](#5873)).
Sign up for freeto 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

@denik@eng-dev-ecosystem-bot@pietern