-
Notifications
You must be signed in to change notification settings - Fork 62
Allow silo-scoped limited-collaborators to promote / demote images from project images to silo images #9394
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
CI failures all look to be unrelated |
| } | ||
|
|
||
| #[nexus_test] | ||
| async fn test_silo_viewer_cannot_promote_demote_images( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm surprised there is not already a test for this. I guess maybe it would be testing the totally unprivileged user.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is this one, but it's more about testing silo deletion permissions.
omicron/nexus/tests/integration_tests/images.rs
Lines 474 to 576 in 2f7f807
| async fn test_image_deletion_permissions(cptestctx: &ControlPlaneTestContext) { | |
| let client = &cptestctx.external_client; | |
| DiskTest::new(&cptestctx).await; | |
| // Create a project | |
| create_project(client, PROJECT_NAME).await; | |
| // Grant the unprivileged user viewer on the silo and admin on that project | |
| let silo_url = format!("/v1/system/silos/{}", DEFAULT_SILO.id()); | |
| grant_iam( | |
| client, | |
| &silo_url, | |
| SiloRole::Viewer, | |
| USER_TEST_UNPRIVILEGED.id(), | |
| AuthnMode::PrivilegedUser, | |
| ) | |
| .await; | |
| let project_url = format!("/v1/projects/{}", PROJECT_NAME); | |
| grant_iam( | |
| client, | |
| &project_url, | |
| ProjectRole::Admin, | |
| USER_TEST_UNPRIVILEGED.id(), | |
| AuthnMode::PrivilegedUser, | |
| ) | |
| .await; | |
| // Create an image in the default silo using the privileged user | |
| let silo_images_url = "/v1/images"; | |
| let images_url = get_project_images_url(PROJECT_NAME); | |
| let image_create_params = get_image_create( | |
| params::ImageSource::YouCanBootAnythingAsLongAsItsAlpine, | |
| ); | |
| let image = | |
| NexusRequest::objects_post(client, &images_url, &image_create_params) | |
| .authn_as(AuthnMode::PrivilegedUser) | |
| .execute_and_parse_unwrap::<views::Image>() | |
| .await; | |
| let image_id = image.identity.id; | |
| // promote the image to the silo | |
| let promote_url = format!("/v1/images/{}/promote", image_id); | |
| NexusRequest::new( | |
| RequestBuilder::new(client, http::Method::POST, &promote_url) | |
| .expect_status(Some(http::StatusCode::ACCEPTED)), | |
| ) | |
| .authn_as(AuthnMode::PrivilegedUser) | |
| .execute_and_parse_unwrap::<views::Image>() | |
| .await; | |
| let silo_images = NexusRequest::object_get(client, &silo_images_url) | |
| .authn_as(AuthnMode::PrivilegedUser) | |
| .execute_and_parse_unwrap::<ResultsPage<views::Image>>() | |
| .await | |
| .items; | |
| assert_eq!(silo_images.len(), 1); | |
| assert_eq!(silo_images[0].identity.name, "alpine-edge"); | |
| // the unprivileged user should not be able to delete that image | |
| let image_url = format!("/v1/images/{}", image_id); | |
| NexusRequest::new( | |
| RequestBuilder::new(client, http::Method::DELETE, &image_url) | |
| .expect_status(Some(http::StatusCode::FORBIDDEN)), | |
| ) | |
| .authn_as(AuthnMode::UnprivilegedUser) | |
| .execute() | |
| .await | |
| .expect("should not be able to delete silo image as unpriv user!"); | |
| // Demote that image | |
| let demote_url = | |
| format!("/v1/images/{}/demote?project={}", image_id, PROJECT_NAME); | |
| NexusRequest::new( | |
| RequestBuilder::new(client, http::Method::POST, &demote_url) | |
| .expect_status(Some(http::StatusCode::ACCEPTED)), | |
| ) | |
| .authn_as(AuthnMode::PrivilegedUser) | |
| .execute_and_parse_unwrap::<views::Image>() | |
| .await; | |
| // now the unpriviledged user should be able to delete that image | |
| let image_url = format!("/v1/images/{}", image_id); | |
| NexusRequest::new( | |
| RequestBuilder::new(client, http::Method::DELETE, &image_url) | |
| .expect_status(Some(http::StatusCode::NO_CONTENT)), | |
| ) | |
| .authn_as(AuthnMode::UnprivilegedUser) | |
| .execute() | |
| .await | |
| .expect("should be able to delete project image as unpriv user!"); | |
| } |
| // This allows limited-collaborators to demote images. | ||
| let (_, authz_project) = project_lookup | ||
| .lookup_for(authz::Action::CreateChild) | ||
| .await?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! Guess this was wrong before.
|
I was curious about how we prevent you from demoting to a project in another silo, so I had Claude write a test confirming that you can't. But this is probably not necessary to add since all of our project lookup infrastructure is built around nesting under silos.
|
This PR allows silo users with the
limited-collaboratorrole to promote project images to silo images and demote silo images to project images. In PR #9299, we established thelimited-collaboratorrole at both the project and silo scope, and created Polar rules that allow them to create/modify/delete compute resources. After that PR they were not able to promote project images to be silo images, or to demote silo images to project images. This change enables silo.limited-collaborators to manage images across project and silo scopes. This is done via a syntheticSiloImageListresource (similar toVpcList) to grant image promotion, without giving them the broadercreate_childpermission on Silo (which would allow creating projects, users, groups, identity providers, etc.).What a silo.limited-collaborator can now do (beyond what they got in PR 9299):
What remains restricted (only collaborators have permissions for …):
Note on project-scoped limited-collaborators:
Only users with silo.limited-collaborator (or higher) can promote/demote images. A project.limited-collaborator can list, read, and modify Project Images within their project, but lacks the silo-level role needed to promote project images to silo scope or demote silo images.
Added tests:
test_silo_collaborator_can_promote_demote_images— Verifies silo collaborators can promote project images to silo images and demote them backtest_silo_limited_collaborator_can_promote_demote_images— Verifies silo limited-collaborators can promote project images to silo images and demote them backtest_silo_viewer_cannot_promote_demote_images— Verifies silo viewers cannot promote or demote images (403 Forbidden)test_project_collaborator_cannot_promote_demote_images— Verifies project-level collaborators without silo roles cannot promote or demote images (404 Not Found)test_project_limited_collaborator_cannot_promote_demote_images— Verifies project-level limited-collaborators without silo roles cannot promote or demote images (404 Not Found)Closes #9338