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:
@@ -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">
|
||||
|
||||
Reference in New Issue
Block a user