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
+27
View File
@@ -149,6 +149,7 @@ const DEFAULT_PERMISSIONS = [
'actions.create',
'actions.update',
'actions.delete',
'actions.execute',
'users.manage',
'secrets.manage',
'roles.manage',
@@ -1118,6 +1119,7 @@ function ActionsConfigTab() {
const [draftDescription, setDraftDescription] = useState('')
const [draftBody, setDraftBody] = useState('')
const [draftEnv, setDraftEnv] = useState<ActionEnvVar[]>([emptyEnvRow()])
const [draftRequiresSudo, setDraftRequiresSudo] = useState(false)
const [isSaving, setIsSaving] = useState(false)
const isEditing = editingActionId !== null
@@ -1169,6 +1171,7 @@ function ActionsConfigTab() {
setDraftDescription('')
setDraftBody('')
setDraftEnv([emptyEnvRow()])
setDraftRequiresSudo(false)
setSubmitError(null)
}
@@ -1185,6 +1188,7 @@ function ActionsConfigTab() {
setDraftDescription('')
setDraftBody('')
setDraftEnv([emptyEnvRow()])
setDraftRequiresSudo(false)
setSubmitError(null)
}
@@ -1203,6 +1207,7 @@ function ActionsConfigTab() {
? action.env.map((envVar) => ({ ...envVar }))
: [emptyEnvRow()],
)
setDraftRequiresSudo(Boolean(action.requires_sudo))
setSubmitError(null)
}
@@ -1250,6 +1255,7 @@ function ActionsConfigTab() {
description: draftDescription,
body: draftBody,
env,
requires_sudo: draftRequiresSudo,
})
: await createAction({
name: draftName,
@@ -1257,6 +1263,7 @@ function ActionsConfigTab() {
kind: editorKind,
body: draftBody,
env,
requires_sudo: draftRequiresSudo,
})
setActions([...response.actions])
clearEditor()
@@ -1342,6 +1349,11 @@ function ActionsConfigTab() {
{action.builtin ? (
<span className="user-badge">built-in</span>
) : null}
{action.requires_sudo ? (
<span className="user-badge action-requires-sudo">
sudo
</span>
) : null}
</div>
<div className="groups-li-meta">
{action.description || 'No description'}
@@ -1521,8 +1533,23 @@ function ActionsConfigTab() {
onChange={(event) => setDraftBody(event.target.value)}
/>
)}
<p className="config-hint">
Do not include a leading <code>sudo</code>; check Requires Sudo
instead so ClusterCanvas runs with <code>sudo -n</code>.
</p>
</div>
<label className="checkbox-row">
<input
type="checkbox"
checked={draftRequiresSudo}
onChange={(event) =>
setDraftRequiresSudo(event.target.checked)
}
/>
Requires Sudo
</label>
<div className="config-field">
<label>Environment variables</label>
<p className="config-hint">