-
Notifications
You must be signed in to change notification settings - Fork 37
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
Add ownership options for "Create directory" #478
Conversation
This is a pretty annoying issue. This comes from cockpit repo, and it's written in js. js assumes that some of these fields might be missing (and deals with them if they're undefined). It would be nice if we could figure out a way to work around issues like this with something better than "port the cockpit component to typescript" every time... |
} | ||
|
||
const id = Number(match[1]); | ||
const name = match[2] === "unbound" ? null : match[2]; |
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.
When is match[2]
ever unbound? Is that something id
prints?
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 tested running id
as a user without a /etc/passwd
entry and it printed "unbound" for the username.
I also noticed that ls -l
does this now as well, instead of printing the numeric ID, which is a bit annoying.
I wonder if it's some nss module responsible for that, or a recent change in coreutils. I tried to look into it a bit but I didn't get too far.
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.
Ok, unbound
is also a fairly popular daemon so that's "interesting"
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.
Sounds like it might be nss
https://github.com/search?q=repo%3Acoreutils%2Fcoreutils%20unbound&type=code
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.
This unbound check still feels a bit suspect to me.
src/dialogs/mkdir.tsx
Outdated
key={owner} | ||
value={owner} | ||
/* Translators: the $0 is a string like root:root or admin:staff */ | ||
label={cockpit.format(_("Create directory owned by '$0'"), owner)} |
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 don't think the Select should include this very verbose information but only root:root
.
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.
Agreed, but I didn't know how to do the thing with the Label :)
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.
Okay. I did something here. I don't know if it's good enough.
3c77a94
to
579964d
Compare
test/check-application
Outdated
b.wait_visible("[data-item='newdir']") | ||
self.assert_owner('/root/newdir', 'root:root') | ||
finally: | ||
m.execute(['rm', '-rf', '/root/newdir']) |
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.
This should be `self.addCleanup(m.execute, "rm -rf /root/newdir")
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.
True.
I first tried to do .restore_dir('/root')
but this had problems since it would need to unmount the overlayed root homedir while running a command executed over ssh... as root. So I did this. But you're right — addCleanup
is definitely more idiomatic.
test/check-application
Outdated
b.wait_visible("[data-item='newdir']") | ||
self.assert_owner('/tmp/newdir', 'root:root') | ||
finally: | ||
m.execute(['rm', '-rf', '/tmp/newdir']) |
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.
Same as above.
The rawhide issue is a straight-up race. The tests are fast enough to go through the process of creating the directory before sudo gets done with what it's doing. We do |
This stats a file on the VM with the given format string.
src/dialogs/mkdir.tsx
Outdated
<Button | ||
variant="primary" | ||
onClick={createDirectory} | ||
isDisabled={errorMessage !== undefined || nameError !== undefined} |
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.
This needs to be disabled when superuser.allowed && !id && !cwdInfo
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.
- isDisabled={errorMessage !== undefined || nameError !== undefined}
+ isDisabled={errorMessage !== undefined || nameError !== undefined || (superuser.allowed && (!id && !cwdInfo))}
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 think you meant (!id || !cwdInfo)
or !(id && cwdInfo)
, yes?
} | ||
|
||
export function useId(): IdInfo | null { | ||
/* XXX This should be part of the cockpit UserInfo */ |
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.
And it is, so linking cockpit-project/cockpit#20517 would be nice
|
||
const [id, setId] = React.useState<IdInfo | null>(null); | ||
|
||
React.useEffect(() => { |
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.
useInit is like useEffect(, [])
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.
If we add isDisabled
then the change is fine to me
Done. |
Two trivial lint issues left. |
If we have superuser capabilities, then add a drop-down list to the "Create directory" dialog with possible ownerships for the create directory. By default we try to create the new directory with the same owner as the parent, but also have options for root:root or the user:group of the logged in user (if it is different from the parent directory). The logic for determining the potential owners of newly created items is generic and might also be applied to things like upload, so keep it in its own file. Also, move the dialog into a new file: src/dialogs/mkdirt.tsx. fileActions has become a bit too much of a catch-all. Add some test cases to make sure that we create files with "reasonable default" ownership in various different locations.
download tests can be flaky, retrying. |
await cockpit.spawn(["mkdir", path], opts); | ||
await cockpit.spawn(["chown", owner, path], opts); | ||
} else { | ||
await cockpit.spawn(["mkdir", path], { err: "message" }); |
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.
This added line is not executed by any test.
isHorizontal onSubmit={e => { | ||
createDirectory(); | ||
e.preventDefault(); | ||
return false; |
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.
These 4 added lines are not executed by any test.
<FormSelect | ||
id='create-directory-owner' | ||
value={owner} | ||
onChange={(_ev, val) => setOwner(val)} |
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.
This added line is not executed by any test.
if (!match) { | ||
throw new Error(`invalid id ${content}`); |
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.
These 2 added lines are not executed by any test.
} | ||
|
||
const id = Number(match[1]); | ||
const name = match[2] === "unbound" ? null : match[2]; |
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.
This added line is not executed by any test.
try { | ||
const uid = parse_id(fields.uid); | ||
const gid = parse_id(fields.gid); | ||
const groups = fields.groups?.split(',')?.map(parse_id) || []; |
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.
This added line is not executed by any test.
} catch (exc) { | ||
console.log(`Failed to parse output of "id" command: ${stdout}: ${exc}`); |
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.
These 2 added lines are not executed by any test.
// create as, mirroring the usual POSIX behaviour. There are other cases | ||
// where the "BSD group semantics" come into play (like mount options) but | ||
// we don't currently support those. We might in the future, though... | ||
const setgid = (info.group !== undefined && (info.mode || 0) & 0o2000) ? `${info.group}` : null; |
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.
This added line is not executed by any test.
// The last option is always available: create as the normal user. In case | ||
// of something inside of the user's home directory, this was probably the | ||
// first option as well... | ||
candidates.add(`${id.uid.name || id.uid.id}:${setgid || id.gid.name || id.gid.id}`); |
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.
This added line is not executed by any test.
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.
Merging with the promise that we kill useId
with Cockpit 318 :)
If we have superuser capabilities, then add a drop-down list to the "Create directory" dialog with possible ownerships for the create directory.
By default we try to create the new directory with the same owner as the parent, but also have options for root:root or the user:group of the logged in user (if it is different from the parent directory).
The logic for determining the potential owners of newly created items is generic and might also be applied to things like upload, so keep it in its own file.
Also, move the dialog into a new file: src/dialogs/mkdirt.tsx. fileActions has become a bit too much of a catch-all.
Todo: