fix(init): template the polkit rule on --group too
polkit rule 50-decnet-workers.rules hardcoded isInGroup("decnet"),
so when 'decnet init --group anti' installed systemd units as
User=anti / Group=anti, the API (running as anti) could no longer
systemctl start/stop decnet-*.service — polkit fell back to
'interactive authentication required', which in a daemon context is
a hard fail:
START FAILED · COLLECTOR — Failed to start decnet-collector.service:
Access denied as the requested operation requires interactive
authentication.
Rename the rule to .j2, parameterise the group on {{ group }}, and
route _install_polkit through _render_template /
_write_rendered_if_changed. Now the polkit rule matches whatever
group was passed to 'decnet init'.
Test fixture updated to seed the .j2 variant.
This commit is contained in:
@@ -379,13 +379,23 @@ def _install_units(
|
|||||||
|
|
||||||
|
|
||||||
def _install_polkit(
|
def _install_polkit(
|
||||||
deploy: Path, rules_dir: Path, *, force: bool, dry_run: bool
|
deploy: Path, rules_dir: Path, *, group: str, force: bool, dry_run: bool
|
||||||
) -> str:
|
) -> str:
|
||||||
src = deploy / "polkit" / "50-decnet-workers.rules"
|
"""Render the group-scoped polkit rule to /etc/polkit-1/rules.d/.
|
||||||
|
|
||||||
|
The rule has to reference the same POSIX group passed via --group —
|
||||||
|
otherwise the API (running as that user) can't
|
||||||
|
systemctl start/stop decnet-*.service without an interactive auth
|
||||||
|
prompt that never gets answered in a daemon context.
|
||||||
|
"""
|
||||||
|
src = deploy / "polkit" / "50-decnet-workers.rules.j2"
|
||||||
if not src.is_file():
|
if not src.is_file():
|
||||||
raise RuntimeError(f"missing polkit rule at {src}")
|
raise RuntimeError(f"missing polkit rule template at {src}")
|
||||||
return _copy_if_changed(
|
rendered = _render_template(src, {"group": group})
|
||||||
src, rules_dir / src.name,
|
# 50-decnet-workers.rules.j2 → 50-decnet-workers.rules
|
||||||
|
dst_name = src.name[: -len(".j2")]
|
||||||
|
return _write_rendered_if_changed(
|
||||||
|
src, rules_dir / dst_name, rendered,
|
||||||
mode=0o644, force=force, dry_run=dry_run,
|
mode=0o644, force=force, dry_run=dry_run,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -755,7 +765,8 @@ def register(app: typer.Typer) -> None:
|
|||||||
_step(
|
_step(
|
||||||
"install polkit rule",
|
"install polkit rule",
|
||||||
lambda: _install_polkit(
|
lambda: _install_polkit(
|
||||||
deploy, polkit_dir, force=force, dry_run=dry_run,
|
deploy, polkit_dir, group=group,
|
||||||
|
force=force, dry_run=dry_run,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
_step(
|
_step(
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
// Allow members of the 'decnet' group to manage DECNET systemd units
|
// Allow members of the '{{ group }}' group to manage DECNET systemd units
|
||||||
// (start / stop / restart / reload) without a password prompt.
|
// (start / stop / restart / reload) without a password prompt.
|
||||||
//
|
//
|
||||||
// Scope is locked to units matching `decnet-<name>.service` or the
|
// Scope is locked to units matching `decnet-<name>.service` or the
|
||||||
// `decnet.target` grouping unit. Any other unit is unaffected by this
|
// `decnet.target` grouping unit. Any other unit is unaffected by this
|
||||||
// rule and still goes through the default polkit policy.
|
// rule and still goes through the default polkit policy.
|
||||||
//
|
//
|
||||||
|
// The group name is rendered at `decnet init` time from --group; the
|
||||||
|
// default is `decnet`, but dev boxes that pass --group $USER get a
|
||||||
|
// rule that matches the operator's own login group.
|
||||||
|
//
|
||||||
// Install: /etc/polkit-1/rules.d/50-decnet-workers.rules
|
// Install: /etc/polkit-1/rules.d/50-decnet-workers.rules
|
||||||
|
|
||||||
polkit.addRule(function(action, subject) {
|
polkit.addRule(function(action, subject) {
|
||||||
@@ -12,7 +16,7 @@ polkit.addRule(function(action, subject) {
|
|||||||
var unit = action.lookup("unit");
|
var unit = action.lookup("unit");
|
||||||
if (unit &&
|
if (unit &&
|
||||||
/^decnet-[a-z]+\.service$|^decnet\.target$/.test(unit) &&
|
/^decnet-[a-z]+\.service$|^decnet\.target$/.test(unit) &&
|
||||||
subject.isInGroup("decnet")) {
|
subject.isInGroup("{{ group }}")) {
|
||||||
return polkit.Result.YES;
|
return polkit.Result.YES;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -77,7 +77,9 @@ def _seed_deploy(monkeypatch: Any, tmp_path: Path) -> Path:
|
|||||||
"ExecStart={{ install_dir }}/venv/bin/decnet api\n"
|
"ExecStart={{ install_dir }}/venv/bin/decnet api\n"
|
||||||
)
|
)
|
||||||
(deploy / "decnet.target").write_text("# target\n")
|
(deploy / "decnet.target").write_text("# target\n")
|
||||||
(deploy / "polkit" / "50-decnet-workers.rules").write_text("// rule\n")
|
(deploy / "polkit" / "50-decnet-workers.rules.j2").write_text(
|
||||||
|
'// rule for {{ group }}\n'
|
||||||
|
)
|
||||||
(deploy / "tmpfiles.d" / "decnet.conf").write_text("d /run/decnet\n")
|
(deploy / "tmpfiles.d" / "decnet.conf").write_text("d /run/decnet\n")
|
||||||
monkeypatch.setattr(_init, "_deploy_root", lambda: deploy)
|
monkeypatch.setattr(_init, "_deploy_root", lambda: deploy)
|
||||||
return deploy
|
return deploy
|
||||||
|
|||||||
Reference in New Issue
Block a user