mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-25 21:20:00 +00:00
agents: name command access plainly and ask for it before the mint
The only way to give an agent the command access that Docker and Podman container updates need was a checkbox called "Enable legacy combined command profile", behind "Show advanced connection and install options", which only appeared after the install token was minted. The name told the users who want updates not to use it, and #1728 shows a user missing it entirely and hand-editing token scopes instead. It is not being retired for container updates yet. Updates dispatch through the agent command session; the separate action runner's container actions are unqualified, and rootful Docker under the safe collector profile has no update checks or actions. So the option stays, with the same security posture: off by default, an explicit choice mints an execution-scoped token and records command-capable, and a monitoring-only install still cannot be promoted remotely. The checkbox now reads "Allow Pulse to run commands on this host" and sits in the token step, so the choice is made before the credential is minted. Its description says what it enables, that Pulse can then run commands as root, and that it cannot be switched on later from Pulse. The token summary no longer claims commands can be enabled per host from Settings. One shared label feeds the installer, the locked Docker update pill and the Proxmox setup guide, and the docs name the option the same way.
This commit is contained in:
@@ -54,8 +54,8 @@ contents. Local `--disk-exclude` rules still take precedence.
|
||||
|
||||
Fresh installs use a local `monitoring-only` command-authority ceiling and a
|
||||
credential without `agent:exec`. Remote configuration cannot promote that
|
||||
service. Selecting the advanced legacy combined command profile at install time
|
||||
adds `--enable-commands`, records `command-capable`, and issues an execution-
|
||||
service. Selecting **Allow Pulse to run commands on this host** at install time (the combined
|
||||
command profile) adds `--enable-commands`, records `command-capable`, and issues an execution-
|
||||
scoped credential. The root monitoring process can then also accept server
|
||||
command requests through the existing policy and approval surfaces. Existing
|
||||
unmarked services upgrade as `legacy` during the migration window so upgrades
|
||||
|
||||
+3
-2
@@ -364,7 +364,7 @@ Docker or Podman administration tool, after checking the workload's existing
|
||||
image/state and recovery path. Deliberately opting into Pulse-managed changes
|
||||
is a separate trust decision: the
|
||||
[agent privilege model](AGENT_SECURITY.md#agent-privilege-model) explains the
|
||||
legacy combined command profile, and the
|
||||
combined command profile behind **Allow Pulse to run commands on this host**, and the
|
||||
[least-privilege profile](AGENT_SECURITY.md#least-privilege-agent-profile)
|
||||
describes the supported separate runner. Neither is a diagnostic prerequisite;
|
||||
do not change a working profile just to obtain evidence.
|
||||
@@ -485,7 +485,8 @@ Pulse can start, stop, and restart Docker / Podman containers directly from the
|
||||
- **Pulse Agent** installed on the container host (see [Unified Agent](UNIFIED_AGENT.md)) and currently connected
|
||||
- **Command execution enabled** on the agent — it is disabled by default. Either:
|
||||
- start the agent with `--enable-commands` (or `PULSE_ENABLE_COMMANDS=true`), or
|
||||
- tick **Enable legacy combined command profile** in **Settings → Infrastructure** before copying the install command, which adds the flag and grants the token the command execution permission (this is the transitional combined profile, not a least-privilege setting)
|
||||
- tick **Allow Pulse to run commands on this host** in the token step of **Settings → Infrastructure** before copying the install command, which adds the flag and grants the token the command execution permission. Pulse can then run commands as root on that host: this is the full-trust combined profile, not a least-privilege setting
|
||||
- an agent installed without it cannot be switched on from Pulse; run the new install command on the host
|
||||
- **Admin approval**: every lifecycle action requires confirmation by an admin in the UI before it runs. The agent then verifies the container's state before the change and confirms it actually reached the requested state afterwards.
|
||||
|
||||
### Limitations
|
||||
|
||||
@@ -58,7 +58,8 @@ The fresh-install posture limits that boundary:
|
||||
- Proxmox guest Docker inventory through `pct exec` is disabled by default and
|
||||
requires an explicit server setting.
|
||||
|
||||
The advanced **legacy combined command profile** is a separate trust decision.
|
||||
The **Allow Pulse to run commands on this host** install option (the combined command
|
||||
profile) is a separate trust decision.
|
||||
It marks the root collector command-capable and gives its credential execution
|
||||
scope so the same process can accept governed server requests. Existing
|
||||
unmarked installations remain in a visible `legacy` compatibility state during
|
||||
|
||||
@@ -15,6 +15,25 @@
|
||||
|
||||
## Purpose
|
||||
|
||||
### Command access is a named token-step choice, not a legacy option (21 October 2026)
|
||||
|
||||
The installer's command-access checkbox reads **Allow Pulse to run commands on
|
||||
this host** and sits in the token step, before the credential is minted,
|
||||
instead of behind the advanced connection options as "Enable legacy combined
|
||||
command profile". The behaviour behind it is unchanged: default off, an
|
||||
explicit choice adds `--enable-commands`, records `command-capable`, and mints
|
||||
an execution-scoped token; toggling after a mint still regenerates and revokes
|
||||
the superseded token, and a `monitoring-only` install still cannot be promoted
|
||||
remotely. The old name told the users who need Docker/Podman updates not to
|
||||
use the only working route: Docker updates dispatch through the agent command
|
||||
session, the separate action runner's container actions are unqualified, and
|
||||
rootful Docker under the safe collector profile carries no update checks or
|
||||
actions. The label is owned by `getUnifiedAgentCommandAccessOptionLabel`, which
|
||||
the locked Docker update pill and the Proxmox setup guide also read, so copy
|
||||
that sends users to it cannot drift from the checkbox.
|
||||
`InfrastructureInstallerSection.test.tsx` pins the checkbox in the token step
|
||||
with its root-access description.
|
||||
|
||||
### Manual update checks skip images with no registry tag (21 October 2026)
|
||||
|
||||
A manual container update check counts a `local image` status as skipped,
|
||||
|
||||
@@ -21,6 +21,15 @@
|
||||
|
||||
## Purpose
|
||||
|
||||
### Proxmox setup guide names the command-access option by its shared label (21 October 2026)
|
||||
|
||||
The Proxmox node setup guide's Docker-in-LXC note now points to the Pulse
|
||||
Agent installer option through `getUnifiedAgentCommandAccessOptionLabel`
|
||||
("Allow Pulse to run commands on this host") instead of the "combined command
|
||||
profile" wording. The node setup client still sends `enableCommands: false`
|
||||
and mints monitoring-only credentials; no request or scope changes.
|
||||
`settingsArchitecture.test.ts` pins the shared label.
|
||||
|
||||
### Reporting telemetry observes canonical generation and delivery boundaries
|
||||
|
||||
`internal/api/reporting_activity.go` records best-effort content-free events to
|
||||
|
||||
@@ -20,6 +20,14 @@
|
||||
|
||||
## Purpose
|
||||
|
||||
### Locked update pill names the command-access option by its shared label (21 October 2026)
|
||||
|
||||
For a host whose agent was installed without command access, the locked pill
|
||||
names the installer option through `getUnifiedAgentCommandAccessOptionLabel`
|
||||
("Allow Pulse to run commands on this host") and the host to run the new
|
||||
install command on, instead of the retired "legacy combined command profile"
|
||||
wording and its advanced-options path.
|
||||
|
||||
### Container update control offers only what the server advertises (21 October 2026)
|
||||
|
||||
`UpdateButton` is live only when the server advertises the `update` capability
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"version": 1,
|
||||
"base_sha": "68a59805c99f78f1f69ce1853f5d507a6dfe5e8f",
|
||||
"verified_at": "2026-10-21T14:41:00Z",
|
||||
"result": "passed",
|
||||
"changed_paths": [
|
||||
"frontend-modern/src/components/Settings/InfrastructureInstallerSection.tsx",
|
||||
"frontend-modern/src/components/Settings/NodeModalSetupGuideSection.tsx",
|
||||
"frontend-modern/src/components/shared/containerUpdateBadgeModel.ts",
|
||||
"frontend-modern/src/utils/unifiedAgentInventoryPresentation.ts"
|
||||
],
|
||||
"content_sha256": {
|
||||
"frontend-modern/src/components/Settings/InfrastructureInstallerSection.tsx": "60ada62ddc528bee9c5a394350a59c4b440f95a40e33ebd1b33805e07359a879",
|
||||
"frontend-modern/src/components/Settings/NodeModalSetupGuideSection.tsx": "208d237386ae98e3c9b502213150c757bdba7c9eb0936fff00a2fad94f5be041",
|
||||
"frontend-modern/src/components/shared/containerUpdateBadgeModel.ts": "9b855b0ed510168c73c768beb756afbb6bd0f0dcdbcf9132231420564ddc70ce",
|
||||
"frontend-modern/src/utils/unifiedAgentInventoryPresentation.ts": "2ba26a0b11445fc1483fcf825c30cd2b4245f9a0a097612f0cfe2d437b78943c"
|
||||
},
|
||||
"routes": [
|
||||
"/docker",
|
||||
"/settings/infrastructure?add=linux-host",
|
||||
"/settings/infrastructure?add=docker",
|
||||
"/settings/infrastructure?add=pve"
|
||||
],
|
||||
"viewports": [
|
||||
{
|
||||
"width": 1400,
|
||||
"height": 900
|
||||
},
|
||||
{
|
||||
"width": 375,
|
||||
"height": 812
|
||||
}
|
||||
],
|
||||
"states": [
|
||||
"Install Pulse Agent (Linux, macOS, Windows host): 'Allow Pulse to run commands on this host' checkbox visible in step 1 under the token summary, before any token exists, unchecked by default, with its root-access description",
|
||||
"Token summary bullet reads 'Monitoring only. Pulse cannot run commands or change containers on this host.' when unchecked and 'Pulse can run commands as root on this host, including container updates and Patrol actions.' when checked",
|
||||
"Advanced connection and install options now hold only the Agent URL, CA, TLS and profile controls; the only other checkbox there is Skip TLS certificate verification",
|
||||
"Docker installer: the Docker inside Proxmox LXCs note names the new option and the Proxmox VE node profile; no horizontal overflow at 375 px",
|
||||
"Proxmox VE Host Telemetry Agent guide: the Docker-in-LXC note names 'Allow Pulse to run commands on this host'",
|
||||
"No console errors",
|
||||
"The 'installed without command access' pill variant cannot render on mock data (no mock docker-host carries an agent facet); its copy is covered by containerUpdateBadgeModel and ContainerUpdateBadge tests"
|
||||
],
|
||||
"interactions": [
|
||||
"Opened Settings, Infrastructure, Add infrastructure, Install Pulse Agent",
|
||||
"Ticked the option before generating a token, then generated one: toast confirmed command execution permission and every install command carried --enable-commands or PULSE_ENABLE_COMMANDS",
|
||||
"Unticked it afterwards: token regenerated without command execution, toast told the user to copy the command again, no install command carried the flag",
|
||||
"Opened the advanced options and listed their checkboxes",
|
||||
"Opened the Docker installer at the mobile viewport and scrolled to the option",
|
||||
"Opened the Proxmox VE flow and chose Host Telemetry Agent"
|
||||
]
|
||||
}
|
||||
@@ -54,8 +54,8 @@ contents. Local `--disk-exclude` rules still take precedence.
|
||||
|
||||
Fresh installs use a local `monitoring-only` command-authority ceiling and a
|
||||
credential without `agent:exec`. Remote configuration cannot promote that
|
||||
service. Selecting the advanced legacy combined command profile at install time
|
||||
adds `--enable-commands`, records `command-capable`, and issues an execution-
|
||||
service. Selecting **Allow Pulse to run commands on this host** at install time (the combined
|
||||
command profile) adds `--enable-commands`, records `command-capable`, and issues an execution-
|
||||
scoped credential. The root monitoring process can then also accept server
|
||||
command requests through the existing policy and approval surfaces. Existing
|
||||
unmarked services upgrade as `legacy` during the migration window so upgrades
|
||||
|
||||
@@ -364,7 +364,7 @@ Docker or Podman administration tool, after checking the workload's existing
|
||||
image/state and recovery path. Deliberately opting into Pulse-managed changes
|
||||
is a separate trust decision: the
|
||||
[agent privilege model](AGENT_SECURITY.md#agent-privilege-model) explains the
|
||||
legacy combined command profile, and the
|
||||
combined command profile behind **Allow Pulse to run commands on this host**, and the
|
||||
[least-privilege profile](AGENT_SECURITY.md#least-privilege-agent-profile)
|
||||
describes the supported separate runner. Neither is a diagnostic prerequisite;
|
||||
do not change a working profile just to obtain evidence.
|
||||
@@ -485,7 +485,8 @@ Pulse can start, stop, and restart Docker / Podman containers directly from the
|
||||
- **Pulse Agent** installed on the container host (see [Unified Agent](UNIFIED_AGENT.md)) and currently connected
|
||||
- **Command execution enabled** on the agent — it is disabled by default. Either:
|
||||
- start the agent with `--enable-commands` (or `PULSE_ENABLE_COMMANDS=true`), or
|
||||
- tick **Enable legacy combined command profile** in **Settings → Infrastructure** before copying the install command, which adds the flag and grants the token the command execution permission (this is the transitional combined profile, not a least-privilege setting)
|
||||
- tick **Allow Pulse to run commands on this host** in the token step of **Settings → Infrastructure** before copying the install command, which adds the flag and grants the token the command execution permission. Pulse can then run commands as root on that host: this is the full-trust combined profile, not a least-privilege setting
|
||||
- an agent installed without it cannot be switched on from Pulse; run the new install command on the host
|
||||
- **Admin approval**: every lifecycle action requires confirmation by an admin in the UI before it runs. The agent then verifies the container's state before the change and confirms it actually reached the requested state afterwards.
|
||||
|
||||
### Limitations
|
||||
|
||||
@@ -58,7 +58,8 @@ The fresh-install posture limits that boundary:
|
||||
- Proxmox guest Docker inventory through `pct exec` is disabled by default and
|
||||
requires an explicit server setting.
|
||||
|
||||
The advanced **legacy combined command profile** is a separate trust decision.
|
||||
The **Allow Pulse to run commands on this host** install option (the combined command
|
||||
profile) is a separate trust decision.
|
||||
It marks the root collector command-capable and gives its credential execution
|
||||
scope so the same process can accept governed server requests. Existing
|
||||
unmarked installations remain in a visible `legacy` compatibility state during
|
||||
|
||||
@@ -11,6 +11,7 @@ import { getUnifiedAgentLookupStatusPresentation } from '@/utils/unifiedAgentSta
|
||||
import {
|
||||
getUnifiedAgentClipboardCopyErrorMessage,
|
||||
getUnifiedAgentClipboardCopySuccessMessage,
|
||||
getUnifiedAgentCommandAccessOptionLabel,
|
||||
} from '@/utils/unifiedAgentInventoryPresentation';
|
||||
import {
|
||||
INSTALL_PROFILE_OPTIONS,
|
||||
@@ -41,6 +42,8 @@ type InfrastructureInstallerFocusPresentation = {
|
||||
platforms: readonly AgentPlatform[];
|
||||
};
|
||||
|
||||
const COMMAND_ACCESS_OPTION_LABEL = getUnifiedAgentCommandAccessOptionLabel();
|
||||
|
||||
const ALL_AGENT_PLATFORMS: readonly AgentPlatform[] = ['linux', 'macos', 'freebsd', 'windows'];
|
||||
|
||||
const INSTALLER_FOCUS_PRESENTATION: Record<
|
||||
@@ -119,7 +122,7 @@ const getCommandSectionDescription = (
|
||||
return 'Use the Linux installer from Unraid terminal or SSH. The agent stores its local uninstall helper under the Unraid plugin path.';
|
||||
}
|
||||
if (focus === 'docker') {
|
||||
return 'Use the Linux installer on a standalone Docker or Podman host. Docker discovery inside Proxmox LXCs currently requires the advanced, command-capable Proxmox install profile.';
|
||||
return 'Use the Linux installer on a standalone Docker or Podman host. Docker discovery inside Proxmox LXCs needs the Proxmox VE node profile with command access allowed.';
|
||||
}
|
||||
if (focus === 'kubernetes') {
|
||||
return 'Use the Linux installer on a Kubernetes node. Commands in this flow include the Kubernetes profile.';
|
||||
@@ -289,12 +292,12 @@ export const InfrastructureInstallerSection: Component<InfrastructureInstallerSe
|
||||
<div class="rounded-md border border-blue-200 bg-blue-50 px-4 py-3 text-sm text-blue-950 dark:border-blue-700 dark:bg-blue-900/25 dark:text-blue-50">
|
||||
<p class="font-semibold">Docker inside Proxmox LXCs</p>
|
||||
<p class="mt-1 text-xs text-blue-800 dark:text-blue-200">
|
||||
Install the agent on the Proxmox node, not inside every LXC. In advanced options,
|
||||
select <span class="font-medium">Proxmox VE node</span> and enable{' '}
|
||||
<span class="font-medium">the legacy combined command profile</span>. This is a
|
||||
temporary full command-capable runtime, not a least-privilege monitoring install. Then
|
||||
turn on <span class="font-medium">Discover Docker in LXC guests</span> in Settings →
|
||||
System → General (admin only), or set{' '}
|
||||
Install the agent on the Proxmox node, not inside every LXC. Turn on{' '}
|
||||
<span class="font-medium">{COMMAND_ACCESS_OPTION_LABEL}</span> below, and in advanced
|
||||
options select <span class="font-medium">Proxmox VE node</span>. This gives Pulse
|
||||
command access to the node; it is not a monitoring-only install. Then turn on{' '}
|
||||
<span class="font-medium">Discover Docker in LXC guests</span> in Settings → System →
|
||||
General (admin only), or set{' '}
|
||||
<code>PULSE_ENABLE_PROXMOX_GUEST_DOCKER_INVENTORY=true</code> in the server
|
||||
environment to lock it on. Optionally restrict it with{' '}
|
||||
<code>PULSE_PROXMOX_GUEST_DOCKER_INVENTORY_VMIDS=101,102</code>. Pulse uses bounded{' '}
|
||||
@@ -340,8 +343,9 @@ export const InfrastructureInstallerSection: Component<InfrastructureInstallerSe
|
||||
<li class="flex items-start">
|
||||
<span class="mr-2 mt-0.5 text-emerald-500">✓</span>
|
||||
<span>
|
||||
Read-only by default. Assistant chat actions and host shell stay off until you opt
|
||||
in per host from <span class="font-medium">Settings → Infrastructure</span>.
|
||||
{state.enableCommands()
|
||||
? 'Pulse can run commands as root on this host, including container updates and Patrol actions.'
|
||||
: 'Monitoring only. Pulse cannot run commands or change containers on this host.'}
|
||||
</span>
|
||||
</li>
|
||||
<li class="flex items-start">
|
||||
@@ -355,6 +359,28 @@ export const InfrastructureInstallerSection: Component<InfrastructureInstallerSe
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="ml-6 rounded-md border border-border bg-surface-hover px-4 py-3">
|
||||
<label
|
||||
class={`flex items-start gap-2 text-sm font-medium text-base-content ${state.isGeneratingToken() ? 'cursor-wait opacity-70' : 'cursor-pointer'}`}
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={state.enableCommands()}
|
||||
disabled={state.isGeneratingToken()}
|
||||
onChange={(event) => void state.setEnableCommands(event.currentTarget.checked)}
|
||||
aria-describedby="install-command-access-description"
|
||||
class="mt-0.5 rounded-sm text-blue-600 focus:ring-blue-500"
|
||||
/>
|
||||
{COMMAND_ACCESS_OPTION_LABEL}
|
||||
</label>
|
||||
<p id="install-command-access-description" class="ml-6 mt-1 text-xs text-muted">
|
||||
Needed to update, start, stop or restart Docker and Podman containers from Pulse, and
|
||||
for Patrol actions. Pulse can then run commands as root on this host, so leave it off
|
||||
if you only want monitoring. It cannot be switched on later from Pulse: rerun the
|
||||
install command with this selected.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-2">
|
||||
<input
|
||||
type="text"
|
||||
@@ -514,8 +540,8 @@ export const InfrastructureInstallerSection: Component<InfrastructureInstallerSe
|
||||
</p>
|
||||
<p class="text-xs text-muted">
|
||||
Default commands use the auto-detected Pulse URL. Open this only if the target
|
||||
host needs a different URL, custom CA trust, TLS override, command execution,
|
||||
or a specific install profile.
|
||||
host needs a different URL, custom CA trust, TLS override, or a specific
|
||||
install profile.
|
||||
</p>
|
||||
</div>
|
||||
<Button
|
||||
@@ -610,31 +636,6 @@ export const InfrastructureInstallerSection: Component<InfrastructureInstallerSe
|
||||
Skip TLS certificate verification (self-signed certs, not recommended)
|
||||
</label>
|
||||
|
||||
<label
|
||||
class="flex cursor-pointer items-center gap-2 text-sm text-base-content"
|
||||
title="Install the transitional combined runtime that can accept server command requests"
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={state.enableCommands()}
|
||||
disabled={state.isGeneratingToken()}
|
||||
onChange={(event) =>
|
||||
void state.setEnableCommands(event.currentTarget.checked)
|
||||
}
|
||||
class="rounded-sm text-blue-600 focus:ring-blue-500"
|
||||
/>
|
||||
Enable legacy combined command profile
|
||||
</label>
|
||||
|
||||
<Show when={state.enableCommands()}>
|
||||
<div class="rounded-md border border-blue-200 bg-blue-50 px-4 py-2 text-sm text-blue-800 dark:border-blue-700 dark:bg-blue-900/25 dark:text-blue-200">
|
||||
<span class="font-medium">Legacy combined trust enabled</span>: The root
|
||||
monitoring service will also accept server command requests. On Proxmox nodes,
|
||||
this remains necessary for opted-in Docker-in-LXC inventory until the scoped
|
||||
local helper replaces the current <code>pct exec</code> path.
|
||||
</div>
|
||||
</Show>
|
||||
|
||||
<div class="rounded-md border border-emerald-200 bg-emerald-50 px-4 py-2 text-sm text-emerald-900 dark:border-emerald-700 dark:bg-emerald-900/25 dark:text-emerald-100">
|
||||
<span class="font-medium">Config signing (optional)</span> — Require signed
|
||||
remote config payloads with{' '}
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
} from '@/components/Settings/nodeModalModel';
|
||||
import type { NodeModalState } from '@/components/Settings/useNodeModalState';
|
||||
import type { NodeModalNodeType, NodeModalSetupMode } from '@/utils/nodeModalPresentation';
|
||||
import { getUnifiedAgentCommandAccessOptionLabel } from '@/utils/unifiedAgentInventoryPresentation';
|
||||
|
||||
interface NodeModalSetupGuideSectionProps {
|
||||
modalProps: NodeModalProps;
|
||||
@@ -145,9 +146,10 @@ export const NodeModalSetupGuideSection: Component<NodeModalSetupGuideSectionPro
|
||||
<div class="rounded-md border border-blue-200 bg-blue-50 px-3 py-2 dark:border-blue-800 dark:bg-blue-950/30">
|
||||
<p class="text-xs text-blue-800 dark:text-blue-200">
|
||||
<strong>Docker inside Proxmox LXCs:</strong> this monitoring-only setup does
|
||||
not grant the command authority currently required for guest Docker discovery.
|
||||
Until the typed local helper replaces that path, use the advanced Pulse Agent
|
||||
installer only if you explicitly accept the combined command profile. The
|
||||
not grant the command access guest Docker discovery needs. For that, install
|
||||
Pulse Agent on the node from Settings → Infrastructure with{' '}
|
||||
<span class="font-medium">{getUnifiedAgentCommandAccessOptionLabel()}</span>{' '}
|
||||
selected, only if you accept giving Pulse command access to the node. The
|
||||
Pulse server must also be opted in: turn on{' '}
|
||||
<span class="font-medium">Discover Docker in LXC guests</span> in Settings →
|
||||
System → General (admin only), or set{' '}
|
||||
|
||||
+29
-1
@@ -1,4 +1,4 @@
|
||||
import { render, screen } from '@solidjs/testing-library';
|
||||
import { fireEvent, render, screen } from '@solidjs/testing-library';
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
import type { AgentLookupResponse } from '@/types/api';
|
||||
import { InfrastructureInstallerSection } from '../InfrastructureInstallerSection';
|
||||
@@ -24,6 +24,9 @@ const stateOverrides: Record<string, unknown> = {
|
||||
commandSections: () => [],
|
||||
getInstallProfileFlags: () => [],
|
||||
lookupResult: () => lookupResult,
|
||||
enableCommands: () => false,
|
||||
setEnableCommands: vi.fn(),
|
||||
isGeneratingToken: () => false,
|
||||
};
|
||||
|
||||
vi.mock('../useInfrastructureOperationsState', () => ({
|
||||
@@ -50,4 +53,29 @@ describe('InfrastructureInstallerSection', () => {
|
||||
expect(label).toHaveTextContent('Last seen 2 hours ago');
|
||||
view.unmount();
|
||||
});
|
||||
|
||||
// #1728: the only way to grant the command access container updates need sat
|
||||
// behind "Show advanced connection and install options" under a "legacy"
|
||||
// name, so users who wanted updates either missed it or were told not to use
|
||||
// it. It is a token-scope choice, so it belongs in the token step.
|
||||
it('offers command access in the token step, outside the advanced options', () => {
|
||||
const view = render(() => <InfrastructureInstallerSection />);
|
||||
const checkbox = screen.getByRole('checkbox', {
|
||||
name: 'Allow Pulse to run commands on this host',
|
||||
});
|
||||
expect(checkbox).not.toBeChecked();
|
||||
expect(checkbox).toHaveAccessibleDescription(
|
||||
/update, start, stop or restart Docker and Podman containers.*run commands as root/,
|
||||
);
|
||||
expect(
|
||||
screen.getByText(
|
||||
'Monitoring only. Pulse cannot run commands or change containers on this host.',
|
||||
),
|
||||
).toBeInTheDocument();
|
||||
expect(screen.queryByText(/legacy combined/i)).not.toBeInTheDocument();
|
||||
|
||||
fireEvent.click(checkbox);
|
||||
expect(stateOverrides.setEnableCommands).toHaveBeenCalledWith(true);
|
||||
view.unmount();
|
||||
});
|
||||
});
|
||||
|
||||
+3
-2
@@ -330,11 +330,12 @@ describe('infrastructure operations model', () => {
|
||||
'commands keep it separate: copy the command first, then use Show token only.',
|
||||
);
|
||||
expect(infrastructureInstallerSectionSource).toContain(
|
||||
'Install the transitional combined runtime that can accept server command requests',
|
||||
'getUnifiedAgentCommandAccessOptionLabel',
|
||||
);
|
||||
expect(infrastructureInstallerSectionSource).toContain(
|
||||
'Enable legacy combined command profile',
|
||||
'Pulse can then run commands as root on this host',
|
||||
);
|
||||
expect(infrastructureInstallerSectionSource).not.toContain('legacy combined');
|
||||
expect(infrastructureInstallerSectionSource).not.toContain('Patrol auto-fix');
|
||||
expect(infrastructureInstallerSectionSource).not.toContain('auto-fix requires Pulse Pro');
|
||||
expect(infrastructureInstallerSectionSource).not.toContain('<api-token>');
|
||||
|
||||
@@ -150,6 +150,11 @@ describe('settings architecture guardrails', () => {
|
||||
expect(auditLogPanelSource).not.toContain('SavedViews');
|
||||
});
|
||||
|
||||
it('sends Proxmox Docker-in-LXC users to the shared command-access option', () => {
|
||||
expect(nodeModalSetupGuideSectionSource).toContain('getUnifiedAgentCommandAccessOptionLabel()');
|
||||
expect(nodeModalSetupGuideSectionSource).not.toContain('combined command profile');
|
||||
});
|
||||
|
||||
it('keeps the Proxmox installer TLS override explicit and request-bound', () => {
|
||||
expect(nodeModalSetupGuideSectionSource).toContain(
|
||||
'Skip TLS certificate verification when downloading the installer and',
|
||||
|
||||
@@ -248,6 +248,9 @@ describe('ContainerUpdateBadge', () => {
|
||||
const status = screen.getByLabelText(/installed without command access/);
|
||||
expect(status.getAttribute('aria-label')).toContain('the Pulse agent on Tower');
|
||||
expect(status.getAttribute('aria-label')).toContain('Settings → Infrastructure');
|
||||
expect(status.getAttribute('aria-label')).toContain(
|
||||
'"Allow Pulse to run commands on this host" selected and run it on Tower',
|
||||
);
|
||||
});
|
||||
|
||||
it('keeps the button enabled when the update readiness entry is available', () => {
|
||||
|
||||
+5
-2
@@ -17,14 +17,17 @@ describe('locked update explanation', () => {
|
||||
const text = getUpdateUnavailableExplanation({ ...disconnected, hostCommandsEnabled: false });
|
||||
expect(text).toContain('the Pulse agent on Tower was installed without command access');
|
||||
expect(text).toContain('Settings → Infrastructure');
|
||||
expect(text).toContain('"Enable legacy combined command profile"');
|
||||
expect(text).toContain(
|
||||
'"Allow Pulse to run commands on this host" selected and run it on Tower',
|
||||
);
|
||||
expect(text).not.toContain('advanced');
|
||||
expect(text).not.toContain('not connected');
|
||||
});
|
||||
|
||||
it('tells a lost command channel apart from missing access', () => {
|
||||
const text = getUpdateUnavailableExplanation({ ...disconnected, hostCommandsEnabled: true });
|
||||
expect(text).toContain('the command channel to the Pulse agent on Tower is not connected');
|
||||
expect(text).not.toContain('reinstall');
|
||||
expect(text).not.toContain('Allow Pulse to run commands');
|
||||
});
|
||||
|
||||
it("falls back to the server's reason when command access is unknown", () => {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { DockerContainerUpdateStatus } from '@/types/api';
|
||||
import type { ResourceActionReadiness } from '@/types/resource';
|
||||
import { getUnifiedAgentCommandAccessOptionLabel } from '@/utils/unifiedAgentInventoryPresentation';
|
||||
|
||||
export interface ContainerUpdateBadgeProps {
|
||||
updateStatus?: DockerContainerUpdateStatus;
|
||||
@@ -139,8 +140,8 @@ export function getUpdateUnavailableExplanation(input: {
|
||||
if (input.hostCommandsEnabled === false) {
|
||||
return (
|
||||
`Update available. Pulse cannot apply it because the Pulse agent on ${host} was installed without command access.\n` +
|
||||
`To allow updates from Pulse, reinstall the agent from Settings → Infrastructure with ` +
|
||||
'"Enable legacy combined command profile" selected in the advanced install options. ' +
|
||||
`To allow updates from Pulse, copy the install command from Settings → Infrastructure with ` +
|
||||
`"${getUnifiedAgentCommandAccessOptionLabel()}" selected and run it on ${host}. ` +
|
||||
'Otherwise, apply the update with your container manager.'
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
getUnifiedAgentAllowReconnectSuccessMessage,
|
||||
getUnifiedAgentClipboardCopyErrorMessage,
|
||||
getUnifiedAgentClipboardCopySuccessMessage,
|
||||
getUnifiedAgentCommandAccessOptionLabel,
|
||||
getUnifiedAgentCommandsUnavailableMessage,
|
||||
getUnifiedAgentConfigUpdateErrorMessage,
|
||||
getUnifiedAgentConfigUpdateSuccessMessage,
|
||||
@@ -59,6 +60,9 @@ describe('unifiedAgentInventoryPresentation', () => {
|
||||
expect(getUnifiedAgentCommandsUnavailableMessage()).toBe(
|
||||
'Agent ID unavailable for command configuration',
|
||||
);
|
||||
expect(getUnifiedAgentCommandAccessOptionLabel()).toBe(
|
||||
'Allow Pulse to run commands on this host',
|
||||
);
|
||||
expect(getUnifiedAgentConfigUpdateSuccessMessage(true)).toBe(
|
||||
'Pulse command execution enabled. Syncing with agent...',
|
||||
);
|
||||
|
||||
@@ -63,6 +63,13 @@ export function getUnifiedAgentCommandsUnavailableMessage(): string {
|
||||
return 'Agent ID unavailable for command configuration';
|
||||
}
|
||||
|
||||
// The one install-time choice that gives an agent command access. Copy that
|
||||
// sends users to it (the installer, locked Docker update pills) must name it
|
||||
// exactly, so it lives here rather than in each surface.
|
||||
export function getUnifiedAgentCommandAccessOptionLabel(): string {
|
||||
return 'Allow Pulse to run commands on this host';
|
||||
}
|
||||
|
||||
export function getUnifiedAgentConfigUpdateSuccessMessage(enabled: boolean): string {
|
||||
return `Pulse command execution ${enabled ? 'enabled' : 'disabled'}. Syncing with agent...`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user