Skip to content

Conversation

@Bubballoo3
Copy link
Contributor

@Bubballoo3 Bubballoo3 commented Nov 14, 2025

Fixes #4780 by adding a form item to edit forms allowing you to set the group owner. This has a few parts to it:

  1. We detect the possible group by taking the intersection of {groups the currentuser is a member of} and {groups that have execute access on the project root's ancestors}. We only show the form option if this intersection is nonempty
  2. We add methods to set and get the group owner
  3. We populate the form item with the current group owner ONLY IF members of the current owning group can (generically) access the project root's parent.

Eventually I would like to show the group owner in the show page, but this is a proof of concept that gets the hard part out of the way. I also think we may want to move the permissions settings to their own modal on the show page (which would more elegantly handle the fact that these can only be set after project creation), but since there is a good deal of frontend work and usage planning that would have to go into that, placing it in the form is a quicker way to get the same functionality.

The one piece this is currently missing is the ability to remove group ownership once it is given. The only way I can think to do this currently is to find a group inside the intersection mentioned above so that only the owner can access, but I don't know if that is guaranteed to exist. That being said, we are eventually going to add options to change facl permissions, so maybe "setting the group owner to 'none'" is actually best implemented by removing group access altogether, though interpreting that correctly (like in get_group_owner could get complicated.

The last special case here is that you can't use this to target intersections of groups. So if I (member of group1 and group2) create a project in a directory only accessible to group2, I can't change the project owner to group1 knowing that a certain member of group2 is also a member of group1 (effectively sharing it just with them). In a specialized permissions pane, it would be nice to have a toggle that would ignore the "who can access the parent" filter, but I don't know if this is possible inside a form without getting too complicated.

else
true
end
end
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Even though this could be condensed by combining the 'None' case and the unset case, I left them separate so that we can replace true in the ternary with the ownership removal later. Otherwise we could simplify it to just

new_group = attributes.fetch(:group_owner, 'None')
(new_group == 'None') ? true : set_group_owner(new_group)

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't see where this is being called from. Also - None value is likely dangerous if it's ever used. It should default to the users Primary group as that will always be a valid fallback.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I already removed the 'None' option from the select, as that was only necessary when we were detecting the 'possible groups', which could have been an empty set. Now that we are detecting the user's groups directly, there is no way to submit 'None'. However I see how this could create issues, maybe just sticking with nil as the default is a better idea. It should still cause set_group_owner to rescue, but ideally without any unintended effects

@directory = File.expand_path(@directory) unless @directory.blank?
@template = attributes[:template]

@group_owner = get_group_owner
Copy link
Contributor Author

@Bubballoo3 Bubballoo3 Nov 15, 2025

Choose a reason for hiding this comment

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

Although this instance variable is not explicitly used, it is responsible for setting the initial value in the form

@johrstrom
Copy link
Contributor

I don't think I'm a fan of modifying the directory after it's been created. I'd think this is needed in the project creation - but editing or changing it after the fact, I'm not so sure.

I don't think changing the group/account/charge-back code after the fact is something that'll ever need to happen. This is because funds ($) are tied to this group/account/charge-back code. A new/different group/account/charge-back code is an entirely new project.

Specifying it during project creation? Sure, I think that's needed.

@Bubballoo3
Copy link
Contributor Author

If we specify it during creation, we don't get to do the automagic detection of which groups it is 'shareable' with, since that depends on the location of the project root (unknown before initial creation). Of course this is all an alternative to specifying in the group level directory the proper default group ownership, but that moves the responsibility from the project owner to the center admin.

I don't think changing the group/account/charge-back code after the fact is something that'll ever need to happen.

Isn't that the only way we can toggle projects from private to shared and vice versa? If charge schemes prevent us from modifying group ownership then we could not allow for mistakes to be made during project creation (which seems user-error prone)

@Bubballoo3
Copy link
Contributor Author

Bubballoo3 commented Nov 24, 2025

I am also trying to account for a universal shared directory where you want to limit your project to a specific group (but multiple groups have access to the parent). Is that something we should be accounting for or not?

The use case I had in mind for this was the following interaction when working with non-primary groups
user-A: Contacts admin to create a new group for new collaboration
admin: Creates new group AB with user-A and user-B and new group directory project-AB
user-A: Creates new project in the project-AB directory, but it accidentally uses user-A's primary group
user-B: Contacts user-A that they cannot see project
user-A: Edits project to have the correct (non-primary) group

This seems like a common enough occurrence that we should find a good solution to it, or putting this responsibility on the admin who creates the project-AB directory. That would also mean we would instruct people to contact their admin instead of the project owner when things aren't right (which I was trying to avoid). Hopefully this gives a more concrete sequence to discuss further

@johrstrom
Copy link
Contributor

I am also trying to account for a universal shared directory where you want to limit your project to a specific group (but multiple groups have access to the parent). Is that something we should be accounting for or not?

I don't think there is such a thing as a "universal shared directory" outside of maybe /tmp.

user-A: Creates new project in the project-AB directory, but it accidentally uses user-A's primary group

If we're accounting for a mistake - then maybe - but project#new doesn't allow us to set the group ownership. This is what I'd want to see first, the ability to create the project with the right group ownership on the outset.

Changing the ownership after the fact I think just sets us up for a lot of edge case failures. You'd want to chown -R right? You'd want to change every child directory's group ownership. But then we'd have to account for partial success if you can change some (because you're the owner) but not others (because a collaborator could be the owner). Or we'd have to enforce a 770 permission so that you can, but everyone else could too.

This seems like a common enough occurrence that we should find a good solution to it, or putting this responsibility on the admin who creates the project-AB directory

Not sure where you're getting the admin from here. If a user creates /fs/ess/project-AB/foo the directory in question is foo which is owned by the user, not project-AB. But even so, if that same user is the PI (the person who requested the project and supplies the funds for the budget), then they likely own project-AB. I own /fs/ess/PZS0714 for example. If you look through /fs/ess you'll see most are owned by a regular user who is the principle investigator (PI) for that project.

@Bubballoo3 Bubballoo3 moved this from Awaiting Review to Changes Requested in PR Review Pipeline Nov 24, 2025
@Bubballoo3
Copy link
Contributor Author

Ok the group selection option has now been enabled for the new page only, and the group is only shown on projects outside the user's home directory (potentially shared projects). We can return to group owner modification later, when we have a way to account for edge cases or have a clearer idea of what that should look like.

end

def user_groups
CurrentUser.groups.map(&:name)
Copy link
Contributor

Choose a reason for hiding this comment

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

CurrentUser already has this api.

def group_names
@group_names ||= groups.map(&:name)
end

Comment on lines 133 to 136
if new_record?
set_group_owner(@group_owner)
return
end
Copy link
Contributor

Choose a reason for hiding this comment

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

This should likely go into the save method. I don't think we should chmod during object creation as it may never actually get saved.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah that seems like a good idea

@Bubballoo3 Bubballoo3 closed this Dec 4, 2025
@github-project-automation github-project-automation bot moved this from Changes Requested to Merged/Closed in PR Review Pipeline Dec 4, 2025
@Bubballoo3 Bubballoo3 reopened this Dec 4, 2025
@github-project-automation github-project-automation bot moved this from Merged/Closed to Awaiting Review in PR Review Pipeline Dec 4, 2025

def make_dir
project_dataroot.mkpath unless project_dataroot.exist?
set_group_owner
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we actually move this to update_permissons - I feel like it fits better there.

Copy link
Contributor

Choose a reason for hiding this comment

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

Errr.... actually it is fine here. We should maybe just pass 750 to mkpath here.

I say that it's fine here, because we'll also need to setgid bit for shared projects and we should do that before we make the other directories so that they're initialized under the correct group.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It certainly would logically, but as soon as project_dataroot has files, we end up in the chmod -r scenario that could present a lot of complex cases. By intercepting it as soon as the project directory is created (before it has any contents) we make sure that the group ownership (and eventually setbit) setting can inform the creation of those project files

Copy link
Contributor Author

@Bubballoo3 Bubballoo3 Dec 5, 2025

Choose a reason for hiding this comment

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

We should maybe just pass 750 to mkpath here

I wonder if this prompts a reorganization to the setup steps here. Maybe we have a method make_root that just creates the root directory, and then fire them in the following order: make_root && update_permissions && make_dir.... That way all the permissions changes have the chance to apply before metadata files are created

jobs_project_directory_error: Project directory path is not set for this workflow
jobs_project_directory_placeholder: Project directory absolute path
jobs_project_generic_error: 'There was an error processing your request: %{error}'
jobs_project_group_owner: Group owner
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm struggling a bit with the word owner here. While within the code base I can let it slip, but a user facing string is a bit different as it seems to collide with User (Owner) permission.

A quick google search indicates it's just group as in user (owner) - group - others (world or anonymous).

Copy link
Contributor Author

@Bubballoo3 Bubballoo3 Dec 5, 2025

Choose a reason for hiding this comment

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

So maybe a label like 'Create as group:' would be more accurate? Or maybe 'Create with group:' would be better. Or are you saying just 'group' by itself is clear enough?

Copy link
Contributor

Choose a reason for hiding this comment

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

I may be overthinking it. Maybe it's fine.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No I think it is an important thing to get right. We basically have to find a compromise between people with and without a working knowledge of linux, and be attentive to what will give the best understanding to everyone. 'Group owner' is almost bad both ways, as it is both confusing to someone who knows that groups cannot be an 'owner' of a file, and someone without that knowledge could mistakenly think they are doing just that, and voiding their personal ownership and control of the project. Especially without any auto-detection helping with the choice, it is important that people know that this is a necessary step for sharing their project.

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe a little ? icon with hover-over text can help here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah I like that. I think I'll probably go with 'Group' to be as minimal and accurate as possible, and then explain in the help text like Make sure to choose the group that includes all intended collaborators. If this is not a collaborative project, the default group is recommended

end

def set_group_owner
return true if private? || @group_owner == get_group_owner
Copy link
Contributor

Choose a reason for hiding this comment

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

Since it's an att_reader we should prefer to use it instead of referencing the instance variable directly. I.e., group_owner instead of @group_owner.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Awaiting Review

Development

Successfully merging this pull request may close these issues.

Add group ownership option to projects

4 participants