Skip to content

Add per-resource permissions support to cluster_policies - #6304

Merged
Sankalp-Mittal merged 12 commits into
mainfrom
sankalp-mittal/cluster-policy-permissions
Aug 25, 2026
Merged

Add per-resource permissions support to cluster_policies#6304
Sankalp-Mittal merged 12 commits into
mainfrom
sankalp-mittal/cluster-policy-permissions

Conversation

@Sankalp-Mittal

@Sankalp-Mittal Sankalp-Mittal commented Aug 18, 2026

Copy link
Copy Markdown
Collaborator

Summary

Stacked on #6225 (cluster policy resource). Adds the per-resource permissions field to cluster_policies so a policy can grant access via the direct engine's generic permissions applier.

Cluster policies support a single ACL level — CAN_USE (SDK compute.ClusterPolicyPermissionLevel), meaning "may create clusters governed by this policy." There is no CAN_MANAGE/CAN_VIEW/CAN_RUN; policy administration is an admin-only function.

resources:
  cluster_policies:
    my_policy:
      name: my-policy
      permissions:
        - level: CAN_USE
          group_name: users

Changes

  • Resource wiring: declare ClusterPolicyPermission, add the Permissions field, register cluster_policies.permissions in the direct engine, and map the permissions-API object type to /cluster-policies/.
  • FixPermissions: add cluster_policies to ignoredResources so the deploying user is not auto-injected as CAN_MANAGE/IS_OWNER — cluster policies can't accept it, and the real backend would reject the deploy (same treatment as secret_scopes).
  • Testserver: model the real API — a non-CAN_USE level on a cluster policy returns 400, so local and cloud runs agree.
  • Generated files: regenerated schema, refschema field list, and validation (level enum = CAN_USE only, level required).

Design note

cluster_policies is intentionally not added to the top-level levelsMap; it stays in unsupportedResources. The bundle-wide permissions: block is expressed in CAN_MANAGE/CAN_VIEW/CAN_RUN (and auto-grants the deployer CAN_MANAGE), none of which a cluster policy can accept. Supporting only the explicit per-resource form avoids silently dropping those grants. Two current-user injection paths had to be handled for this: the top-level levelsMap and the FixPermissions mutator.

Testing

Acceptance tests under acceptance/bundle/resources/cluster_policies/permissions/:

  • basic/ — deploy applies the CAN_USE grants, redeploy updates the ACL; requests asserted with print_requests.py.
  • out_of_band_change/ — an out-of-band ACL change is detected by bundle plan and reconciled on redeploy.
  • levels/ (Cloud=true) — CAN_USE deploys successfully; a direct CAN_MANAGE set-permissions call is rejected (asserted with musterr; the backend error differs between the fake and cloud, so it is routed to a LOG file rather than pinned).

Plus the cluster_policies.permissions CRUD roundtrip fixture in dresources/all_test.go. Unit + acceptance suites pass locally.

This pull request and its description were written by Isaac.

@eng-dev-ecosystem-bot

eng-dev-ecosystem-bot commented Aug 18, 2026

Copy link
Copy Markdown
Collaborator

Integration test report

Commit: 366aa22

Run: 32789691264

Env 💚​RECOVERED 🙈​SKIP ✅​pass 🙈​skip Time
💚​ aws linux 2 3 286 1467 4:03
💚​ aws windows 2 3 288 1465 4:09
💚​ azure linux 2 3 285 1467 4:34
💚​ azure windows 2 3 287 1465 4:07
💚​ gcp linux 2 3 286 1467 4:41
💚​ gcp windows 2 3 288 1465 5:20
Test Name aws linux aws windows azure linux azure windows gcp linux gcp windows
💚​ TestAccept 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R
💚​ TestAccept/bundle/invariant/no_drift 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R
🙈​ TestAccept/bundle/resources/vector_search_endpoints/drift/recreated_same_name 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/vector_search_indexes/recreate/embedding_dimension 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/ssh/connection 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
Top 3 slowest tests (at least 2 minutes):
duration env testname
4:19 gcp windows TestAccept
3:18 aws windows TestAccept
3:10 azure windows TestAccept

@Sankalp-Mittal
Sankalp-Mittal marked this pull request as ready for review August 18, 2026 13:45
Comment thread acceptance/bundle/resources/cluster_policies/permissions/levels/script Outdated
@@ -0,0 +1,22 @@
cleanup() {

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 basic test isn't really interesting (should be covered by invariant test already).

maybe add a test for out-of-band recreate & eventual consistency of the resource (remember we discussed v1 vs v2 permissions API), since that's not covered by tests

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This resource like genie_spaces also uses v1 permissions, so there can be drift on out_of_band changes. Should this be left as is, or something be fixed.

I have removed basic/ and added 2 out_of_band* tests

@Sankalp-Mittal
Sankalp-Mittal force-pushed the sankalp-mittal/cluster-policy-permissions branch from ebd6fbf to 1c3b7c2 Compare August 24, 2026 15:38
Base automatically changed from sankalp-mittal/cluster-policy-resource to main August 24, 2026 22:39
Cluster policies support a single ACL level, CAN_USE (SDK
compute.ClusterPolicyPermissionLevel). Wire up the per-resource
`permissions` field so a policy can grant CAN_USE to users, groups, and
service principals via the direct engine's generic permissions applier:

- Declare the ClusterPolicyPermission type and add the Permissions field.
- Register cluster_policies.permissions in the direct engine and map the
  permissions-API object type to /cluster-policies/.
- Regenerate the bundle JSON schema and fill in the field descriptions.

cluster_policies is intentionally left out of the top-level levelsMap
(it stays in unsupportedResources): the bundle-wide permissions block is
expressed in CAN_MANAGE/CAN_VIEW/CAN_RUN, none of which a cluster policy
can accept, so only the explicit per-resource form is supported.

Co-authored-by: Isaac
Add basic and out_of_band_change acceptance tests for the cluster_policies
`permissions` field, filtering permission requests with print_requests.py.

The basic test surfaced that FixPermissions injects the current user as
CAN_MANAGE onto every resource with a permissions field. Cluster policies
only accept CAN_USE, so the real backend would reject that. Add
cluster_policies to fix_permissions.go's ignoredResources (like
secret_scopes) so only the user-specified CAN_USE grants are sent.

Co-authored-by: Isaac
Add a Cloud=true test that deploys a policy with CAN_USE (accepted) and
then asserts a direct CAN_MANAGE set-permissions call is rejected.

Model the rejection in the testserver: the permissions API only accepts
CAN_USE for cluster policies, so a non-CAN_USE level returns 400. This
keeps the local run and the cloud run in agreement. The backend error
text differs between the fake and a real workspace, so it is routed to a
LOG file and musterr asserts only that the request fails.

Co-authored-by: Isaac
Runs generate-check output: the refschema field list, the level enum
(CAN_USE only), and the required-field entry for the new cluster_policies
permissions block.

Co-authored-by: Isaac
TestInvariantConfigsCoverage requires every resource with a permissions
field to have an invariant config exercising it. Attach a CAN_USE grant
to the cluster_policies invariant config.

Co-authored-by: Isaac
Address review feedback: instead of a raw set-permissions CLI call, flip
the grant to CAN_MANAGE with update_file.py and assert the bundle deploy
fails.

Sync the testserver's rejection message to the real permissions API
("Unknown Cluster Policy Permission Level: <level>", captured from a
cloud run) so the fake and cloud agree, and assert it verbatim in the
golden. Verified against a real workspace via deco env run.

Co-authored-by: Isaac
The failing redeploy's upload count differs between the fake and cloud, so
its output cannot live in the golden. Follow the repo convention: capture
the deploy to LOG and assert the backend's error message with contains.py.

Verified against a real workspace via deco env run.

Co-authored-by: Isaac
The base branch now sets Cloud=true for cluster_policies tests. The basic
and out_of_band_change permission tests use a fixed policy name and are
not cloud-safe for concurrent runs, so pin them Cloud=false. The levels
test remains the cloud-run coverage (it uses UNIQUE_NAME).

Co-authored-by: Isaac
More precise than out_of_band_change (which, at the resource level, means a
definition change): this test grants an extra principal out of band and
checks the bundle reconciles it. Parallels the out_of_band_deletion naming
from the genie_spaces precedent.

Co-authored-by: Isaac
Add v1 out-of-band deletion coverage for cluster_policies permissions:
the policy is deleted out of band, its ACL lingers (no 404, unlike a v2
cascade delete), and plan recreates it. Modeled on the genie_spaces
out_of_band_deletion precedent.

Remove the basic test: its create/deploy path is already covered by the
invariant config, per review feedback.

Co-authored-by: Isaac
@Sankalp-Mittal
Sankalp-Mittal force-pushed the sankalp-mittal/cluster-policy-permissions branch from 84d6c30 to 4c3cd95 Compare August 24, 2026 22:45
The test passes a leading-slash path to `api get`; on Windows, Git Bash
rewrites /api/... to a Windows path before the CLI sees it, so the request
misses the testserver stub. Set Env.MSYS_NO_PATHCONV, matching the
genie_spaces out_of_band_deletion precedent.

Co-authored-by: Isaac
With MSYS_NO_PATHCONV set (needed for the api get leading-slash path),
Git Bash on Windows no longer converts the PATH-resolved location of the
read_id.py helper, so python3 cannot open it. Fetch the policy id via
bundle summary + add_repl (a shell function), matching the genie_spaces
precedent. Golden output is unchanged.

Co-authored-by: Isaac
@Sankalp-Mittal
Sankalp-Mittal added this pull request to the merge queue Aug 24, 2026
Merged via the queue into main with commit df7a376 Aug 25, 2026
23 checks passed
@Sankalp-Mittal
Sankalp-Mittal deleted the sankalp-mittal/cluster-policy-permissions branch August 25, 2026 00:09
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