Give back only the groups the mesh added, and say when a new login is needed (hq ADR 0251, issue 247)
mesh/delivery-group group feat/module-groups checking: 0 of 2 member(s) ready
mesh/delivery superseded: a newer head of the same pull request
mesh/merge-gate pass: builds mesh-host → ace, g14, novox, shanks; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery-group group feat/module-groups checking: 0 of 2 member(s) ready
mesh/delivery superseded: a newer head of the same pull request
mesh/merge-gate pass: builds mesh-host → ace, g14, novox, shanks; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed
A module puts the operator's account in a group by declaring the account with that group alone. The node-engine now records each group it added, takes back only those when nothing declared still asks for them, refuses a group the machine lacks before usermod runs, and states each such account as its module's resource of kind account: relogin needed while the running session lacks the group.
This commit is contained in:
@@ -173,3 +173,12 @@ func (alpine) AddUserToGroup(ctx context.Context, run Runner, name, group string
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveUserFromGroup uses busybox delgroup, which given an account and a group takes the account out of
|
||||
// that group only (novox/hq ADR 0251).
|
||||
func (alpine) RemoveUserFromGroup(ctx context.Context, run Runner, name, group string) error {
|
||||
if _, err := run(ctx, "delgroup", name, group); err != nil {
|
||||
return fmt.Errorf("cannot take %q out of the group %q: %w", name, group, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -341,6 +341,15 @@ func (arch) AddUserToGroup(ctx context.Context, run Runner, name, group string)
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveUserFromGroup takes an account out of one group with gpasswd, which changes that group's entry
|
||||
// and no other (novox/hq ADR 0251). Never usermod --groups, which replaces the whole set.
|
||||
func (arch) RemoveUserFromGroup(ctx context.Context, run Runner, name, group string) error {
|
||||
if _, err := run(ctx, "gpasswd", "--delete", name, group); err != nil {
|
||||
return fmt.Errorf("cannot take %q out of the group %q: %w", name, group, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ServiceUnitFile says where the service manager loads a unit from — systemd's FragmentPath. It
|
||||
// is how the host tells a unit an administrator installed, under /etc or /run, from one a package
|
||||
// ships under /usr (novox/hq ADR 0103). Empty, with no error, for a unit that loads from nowhere.
|
||||
|
||||
@@ -76,7 +76,8 @@ type System interface {
|
||||
// declared state rather than a command the link may not carry.
|
||||
SetUserShell(ctx context.Context, run Runner, name, shell string) error
|
||||
// AddUserToGroup is additive and never removes. A machine's own groups are not the mesh's to
|
||||
// know about, and a declaration that pruned them would take away what somebody set by hand.
|
||||
// know about, and a declaration that pruned them would take away what somebody set by hand. The
|
||||
// one group the mesh takes an account out of is one it put it in (GroupLeaver, ADR 0251).
|
||||
AddUserToGroup(ctx context.Context, run Runner, name, group string) error
|
||||
}
|
||||
|
||||
@@ -130,6 +131,28 @@ func GroupsOf(ctx context.Context, run Runner, name string) ([]string, error) {
|
||||
return strings.Fields(out), nil
|
||||
}
|
||||
|
||||
// GroupExists is whether the machine's group database has a group (novox/hq ADR 0251). Absent is an
|
||||
// answer, an error is not, on LookUpUser's rule: `getent` exits 2 for a key it does not have.
|
||||
//
|
||||
// Asked before an account is put in a group, so that a group whose package has not made it yet is said
|
||||
// as that, rather than in usermod's words.
|
||||
func GroupExists(ctx context.Context, run Runner, group string) (bool, error) {
|
||||
if _, err := run(ctx, "getent", "group", group); err != nil {
|
||||
if code, ok := ExitCode(err); ok && code == 2 {
|
||||
return false, nil
|
||||
}
|
||||
return false, fmt.Errorf("the group database did not answer about %q: %w", group, err)
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// GroupLeaver is a system that can take an account out of one group, and out of no other (novox/hq ADR
|
||||
// 0251): what gives back a group the mesh put an account in, when the module that wanted it goes.
|
||||
// Optional, as lingering is: a system without it keeps every group, and the removal says so.
|
||||
type GroupLeaver interface {
|
||||
RemoveUserFromGroup(ctx context.Context, run Runner, name, group string) error
|
||||
}
|
||||
|
||||
// shells is where the machine lists the shells a login may have (shells(5)). A variable so a test
|
||||
// can point it at a list of its own; ShellsIn is how.
|
||||
var shells = "/etc/shells"
|
||||
|
||||
Reference in New Issue
Block a user