Wire action-group variables, sudo, and command path resolution through the API and UI.

Completes run-if/set_variable and requires_sudo editing, sudoers path resolve helpers, and execute permission checks so node action groups can gate upgrades and elevate safely.
This commit is contained in:
2026-07-19 22:00:14 +02:00
parent 0e06063c1d
commit 7631591f30
22 changed files with 2685 additions and 274 deletions
@@ -51,7 +51,8 @@ func TestActionsCreatePatchDelete(t *testing.T) {
"description": "Print the target IP",
"kind": "shell",
"body": "echo {{node.ip}}",
"env": [{"name": "APP_HOME", "value": "/opt/app"}]
"env": [{"name": "APP_HOME", "value": "/opt/app"}],
"requires_sudo": true
}`)
createReq := withSession(httptest.NewRequest(http.MethodPost, "/api/v1/actions", bytes.NewReader(createBody)), cookie)
createRec := httptest.NewRecorder()
@@ -71,8 +72,11 @@ func TestActionsCreatePatchDelete(t *testing.T) {
if custom.Builtin || custom.Name != "Echo host" || custom.Kind != settings.ActionKindShell {
t.Fatalf("custom = %#v", custom)
}
if !custom.RequiresSudo {
t.Fatalf("expected requires_sudo true, got %#v", custom)
}
patchBody := []byte(`{"name":"Echo target","body":"echo {{node.host}}"}`)
patchBody := []byte(`{"name":"Echo target","body":"echo {{node.host}}","requires_sudo":false}`)
patchReq := withSession(
httptest.NewRequest(http.MethodPatch, "/api/v1/actions?id="+custom.ID, bytes.NewReader(patchBody)),
cookie,
@@ -94,6 +98,9 @@ func TestActionsCreatePatchDelete(t *testing.T) {
if action.Name != "Echo target" || action.Body != "echo {{node.host}}" {
t.Fatalf("patched = %#v", action)
}
if action.RequiresSudo {
t.Fatalf("expected requires_sudo false after patch, got %#v", action)
}
}
}
if !found {