[Fleet] Agent upgrade available should use latest agent version (#167410)

## Summary

Closes https://github.com/elastic/kibana/issues/167387

Replaced using kibana version when deciding if agent upgrade is
available (only in serverless, in stateful kibana version is still
returned as an available version).

To verify locally:
- [to test stateless] add this to `kibana.dev.yml`:
`xpack.fleet.internal.onlyAllowAgentUpgradeToKnownVersions: true`
- extract the `agent_versions_list.json` to local kibana folder
`~/kibana/x-pack/plugins/fleet/target`

[agent_versions_list.json.zip](12739519/agent_versions_list.json.zip)
- verify that upgrade available warnings still work if agent is < latest
agent version (8.10.2)
- when trying to upgrade agent, verify that the default version is the
latest agent version, and 8.11 is not in the list

Agent list:
<img width="1475" alt="image"
src="f06b7bc8-97e6-4ff9-b872-736ede5e969a">

Upgrade available filter - 1 agent on latest version, 9 upgradeable:
<img width="1314" alt="image"
src="4ff5ac02-903b-493b-94df-68b1b7ad6846">

Agent details:
<img width="1512" alt="image"
src="3ff6e1d5-2ccc-4814-83e5-c4760ad63722">

Agent on latest version has disable `Upgrade agent` action:
<img width="1322" alt="image"
src="f461dbf5-04e5-4bcc-8801-48c2b1a90225">

Bulk action with one agent that is not upgradeable (already on latest
version), expected error:
<img width="1597" alt="image"
src="8bfa46ae-6684-4748-9fca-e908c142b642">




### Checklist

- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
This commit is contained in:
Julia Bardi 2023-09-29 11:07:44 +02:00 committed by GitHub
parent c7bb851ded
commit 474c8eaf52
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 223 additions and 65 deletions

View file

@ -11,7 +11,11 @@ import semverGt from 'semver/functions/gt';
import type { Agent } from '../types';
export function isAgentUpgradeable(agent: Agent, kibanaVersion: string, versionToUpgrade?: string) {
export function isAgentUpgradeable(
agent: Agent,
latestAgentVersion: string,
versionToUpgrade?: string
) {
let agentVersion: string;
if (typeof agent?.local_metadata?.elastic?.agent?.version === 'string') {
agentVersion = agent.local_metadata.elastic.agent.version;
@ -31,23 +35,23 @@ export function isAgentUpgradeable(agent: Agent, kibanaVersion: string, versionT
if (versionToUpgrade !== undefined) {
return (
isNotDowngrade(agentVersion, versionToUpgrade) &&
isAgentVersionLessThanKibana(agentVersion, kibanaVersion)
isAgentVersionLessThanLatest(agentVersion, latestAgentVersion)
);
}
return isAgentVersionLessThanKibana(agentVersion, kibanaVersion);
return isAgentVersionLessThanLatest(agentVersion, latestAgentVersion);
}
export const isAgentVersionLessThanKibana = (agentVersion: string, kibanaVersion: string) => {
const isAgentVersionLessThanLatest = (agentVersion: string, latestAgentVersion: string) => {
// make sure versions are only the number before comparison
const agentVersionNumber = semverCoerce(agentVersion);
if (!agentVersionNumber) throw new Error('agent version is not valid');
const kibanaVersionNumber = semverCoerce(kibanaVersion);
if (!kibanaVersionNumber) throw new Error('kibana version is not valid');
const latestAgentVersionNumber = semverCoerce(latestAgentVersion);
if (!latestAgentVersionNumber) throw new Error('latest version is not valid');
return semverLt(agentVersionNumber, kibanaVersionNumber);
return semverLt(agentVersionNumber, latestAgentVersionNumber);
};
export const isNotDowngrade = (agentVersion: string, versionToUpgrade: string) => {
const isNotDowngrade = (agentVersion: string, versionToUpgrade: string) => {
const agentVersionNumber = semverCoerce(agentVersion);
if (!agentVersionNumber) throw new Error('agent version is not valid');
const versionToUpgradeNumber = semverCoerce(versionToUpgrade);

View file

@ -12,14 +12,17 @@ import { createFleetTestRendererMock } from '../../../../../../mock';
import type { Agent, AgentPolicy } from '../../../../types';
import { ExperimentalFeaturesService } from '../../../../services';
import { useAuthz } from '../../../../../../hooks/use_authz';
import { useAgentVersion } from '../../../../../../hooks/use_agent_version';
import { AgentDetailsActionMenu } from './actions_menu';
jest.mock('../../../../../../services/experimental_features');
jest.mock('../../../../../../hooks/use_authz');
jest.mock('../../../../../../hooks/use_agent_version');
const mockedExperimentalFeaturesService = jest.mocked(ExperimentalFeaturesService);
const mockedUseAuthz = jest.mocked(useAuthz);
const mockedUseAgentVersion = jest.mocked(useAgentVersion);
function renderActions({ agent, agentPolicy }: { agent: Agent; agentPolicy?: AgentPolicy }) {
const renderer = createFleetTestRendererMock();
@ -48,6 +51,7 @@ describe('AgentDetailsActionMenu', () => {
all: true,
},
} as any);
mockedUseAgentVersion.mockReturnValue('8.10.2');
});
describe('Request Diagnotics action', () => {
@ -162,45 +166,90 @@ describe('AgentDetailsActionMenu', () => {
expect(res).toBeEnabled();
});
});
});
describe('Restart upgrade action', () => {
function renderAndGetRestartUpgradeButton({
agent,
agentPolicy,
}: {
agent: Agent;
agentPolicy?: AgentPolicy;
}) {
const { utils } = renderActions({
describe('Restart upgrade action', () => {
function renderAndGetRestartUpgradeButton({
agent,
agentPolicy,
}: {
agent: Agent;
agentPolicy?: AgentPolicy;
}) {
const { utils } = renderActions({
agent,
agentPolicy,
});
return utils.queryByTestId('restartUpgradeBtn');
}
it('should render an active button', async () => {
const res = renderAndGetRestartUpgradeButton({
agent: {
status: 'updating',
upgrade_started_at: '2022-11-21T12:27:24Z',
} as any,
agentPolicy: {} as AgentPolicy,
});
expect(res).not.toBe(null);
expect(res).toBeEnabled();
});
return utils.queryByTestId('restartUpgradeBtn');
}
it('should render an active button', async () => {
const res = renderAndGetRestartUpgradeButton({
agent: {
status: 'updating',
upgrade_started_at: '2022-11-21T12:27:24Z',
} as any,
agentPolicy: {} as AgentPolicy,
it('should not render action if agent is not stuck in updating', async () => {
const res = renderAndGetRestartUpgradeButton({
agent: {
status: 'updating',
upgrade_started_at: new Date().toISOString(),
} as any,
agentPolicy: {} as AgentPolicy,
});
expect(res).toBe(null);
});
expect(res).not.toBe(null);
expect(res).toBeEnabled();
});
it('should not render action if agent is not stuck in updating', async () => {
const res = renderAndGetRestartUpgradeButton({
agent: {
status: 'updating',
upgrade_started_at: new Date().toISOString(),
} as any,
agentPolicy: {} as AgentPolicy,
describe('Upgrade action', () => {
function renderAndGetUpgradeButton({
agent,
agentPolicy,
}: {
agent: Agent;
agentPolicy?: AgentPolicy;
}) {
const { utils } = renderActions({
agent,
agentPolicy,
});
return utils.queryByTestId('upgradeBtn');
}
it('should render an active action button if agent version is not the latest', async () => {
const res = renderAndGetUpgradeButton({
agent: {
active: true,
status: 'online',
local_metadata: { elastic: { agent: { version: '8.8.0', upgradeable: true } } },
} as any,
agentPolicy: {} as AgentPolicy,
});
expect(res).not.toBe(null);
expect(res).toBeEnabled();
});
it('should render a disabled action button if agent version is latest', async () => {
const res = renderAndGetUpgradeButton({
agent: {
active: true,
status: 'online',
local_metadata: { elastic: { agent: { version: '8.10.2', upgradeable: true } } },
} as any,
agentPolicy: {} as AgentPolicy,
});
expect(res).not.toBe(null);
expect(res).not.toBeEnabled();
});
expect(res).toBe(null);
});
});

View file

@ -13,7 +13,7 @@ import { isAgentRequestDiagnosticsSupported } from '../../../../../../../common/
import { isStuckInUpdating } from '../../../../../../../common/services/agent_status';
import type { Agent, AgentPolicy } from '../../../../types';
import { useAuthz, useKibanaVersion } from '../../../../hooks';
import { useAgentVersion, useAuthz } from '../../../../hooks';
import { ContextMenuActions } from '../../../../components';
import {
AgentUnenrollAgentModal,
@ -34,7 +34,7 @@ export const AgentDetailsActionMenu: React.FunctionComponent<{
onCancelReassign?: () => void;
}> = memo(({ agent, assignFlyoutOpenByDefault = false, onCancelReassign, agentPolicy }) => {
const hasFleetAllPrivileges = useAuthz().fleet.all;
const kibanaVersion = useKibanaVersion();
const latestAgentVersion = useAgentVersion();
const refreshAgent = useAgentRefresh();
const [isReassignFlyoutOpen, setIsReassignFlyoutOpen] = useState(assignFlyoutOpenByDefault);
const [isUnenrollModalOpen, setIsUnenrollModalOpen] = useState(false);
@ -102,11 +102,12 @@ export const AgentDetailsActionMenu: React.FunctionComponent<{
</EuiContextMenuItem>,
<EuiContextMenuItem
icon="refresh"
disabled={!isAgentUpgradeable(agent, kibanaVersion)}
disabled={!!latestAgentVersion && !isAgentUpgradeable(agent, latestAgentVersion)}
onClick={() => {
setIsUpgradeModalOpen(true);
}}
key="upgradeAgent"
data-test-subj="upgradeBtn"
>
<FormattedMessage
id="xpack.fleet.agentList.upgradeOneButton"

View file

@ -22,7 +22,7 @@ import { i18n } from '@kbn/i18n';
import { FormattedMessage, FormattedRelative } from '@kbn/i18n-react';
import type { Agent, AgentPolicy } from '../../../../../types';
import { useKibanaVersion } from '../../../../../hooks';
import { useAgentVersion } from '../../../../../hooks';
import { ExperimentalFeaturesService, isAgentUpgradeable } from '../../../../../services';
import { AgentPolicySummaryLine } from '../../../../../components';
import { AgentHealth } from '../../../components';
@ -39,7 +39,7 @@ export const AgentDetailsOverviewSection: React.FunctionComponent<{
agent: Agent;
agentPolicy?: AgentPolicy;
}> = memo(({ agent, agentPolicy }) => {
const kibanaVersion = useKibanaVersion();
const latestAgentVersion = useAgentVersion();
const { displayAgentMetrics } = ExperimentalFeaturesService.get();
return (
@ -173,7 +173,7 @@ export const AgentDetailsOverviewSection: React.FunctionComponent<{
<EuiFlexItem grow={false} className="eui-textNoWrap">
{agent.local_metadata.elastic.agent.version}
</EuiFlexItem>
{isAgentUpgradeable(agent, kibanaVersion) ? (
{latestAgentVersion && isAgentUpgradeable(agent, latestAgentVersion) ? (
<EuiFlexItem grow={false}>
<EuiToolTip
position="right"

View file

@ -23,7 +23,8 @@ import { isAgentUpgradeable, ExperimentalFeaturesService } from '../../../../ser
import { AgentHealth } from '../../components';
import type { Pagination } from '../../../../hooks';
import { useLink, useKibanaVersion, useAuthz } from '../../../../hooks';
import { useAgentVersion } from '../../../../hooks';
import { useLink, useAuthz } from '../../../../hooks';
import { AgentPolicySummaryLine } from '../../../../components';
import { Tags } from '../../components/tags';
@ -91,7 +92,7 @@ export const AgentListTable: React.FC<Props> = (props: Props) => {
const { displayAgentMetrics } = ExperimentalFeaturesService.get();
const { getHref } = useLink();
const kibanaVersion = useKibanaVersion();
const latestAgentVersion = useAgentVersion();
const isAgentSelectable = (agent: Agent) => {
if (!agent.active) return false;
@ -284,7 +285,9 @@ export const AgentListTable: React.FC<Props> = (props: Props) => {
<EuiFlexItem grow={false} className="eui-textNoWrap">
{safeMetadata(version)}
</EuiFlexItem>
{isAgentSelectable(agent) && isAgentUpgradeable(agent, kibanaVersion) ? (
{isAgentSelectable(agent) &&
latestAgentVersion &&
isAgentUpgradeable(agent, latestAgentVersion) ? (
<EuiFlexItem grow={false}>
<EuiText color="subdued" size="xs" className="eui-textNoWrap">
<EuiIcon size="m" type="warning" color="warning" />
@ -324,7 +327,10 @@ export const AgentListTable: React.FC<Props> = (props: Props) => {
totalAgents
? showUpgradeable
? agents.filter(
(agent) => isAgentSelectable(agent) && isAgentUpgradeable(agent, kibanaVersion)
(agent) =>
isAgentSelectable(agent) &&
latestAgentVersion &&
isAgentUpgradeable(agent, latestAgentVersion)
)
: agents
: []

View file

@ -12,14 +12,17 @@ import { createFleetTestRendererMock } from '../../../../../../mock';
import type { Agent, AgentPolicy } from '../../../../types';
import { ExperimentalFeaturesService } from '../../../../services';
import { useAuthz } from '../../../../../../hooks/use_authz';
import { useAgentVersion } from '../../../../../../hooks/use_agent_version';
import { TableRowActions } from './table_row_actions';
jest.mock('../../../../../../services/experimental_features');
jest.mock('../../../../../../hooks/use_authz');
jest.mock('../../../../../../hooks/use_agent_version');
const mockedExperimentalFeaturesService = jest.mocked(ExperimentalFeaturesService);
const mockedUseAuthz = jest.mocked(useAuthz);
const mockedUseAgentVersion = jest.mocked(useAgentVersion);
function renderTableRowActions({
agent,
@ -57,6 +60,7 @@ describe('TableRowActions', () => {
all: true,
},
} as any);
mockedUseAgentVersion.mockReturnValue('8.10.2');
});
describe('Request Diagnotics action', () => {
@ -179,4 +183,53 @@ describe('TableRowActions', () => {
expect(res).toBe(null);
});
});
describe('Upgrade action', () => {
function renderAndGetUpgradeButton({
agent,
agentPolicy,
}: {
agent: Agent;
agentPolicy?: AgentPolicy;
}) {
const { utils } = renderTableRowActions({
agent,
agentPolicy,
});
return utils.queryByTestId('upgradeBtn');
}
it('should render an active action button if agent version is not the latest', async () => {
const res = renderAndGetUpgradeButton({
agent: {
active: true,
status: 'online',
local_metadata: { elastic: { agent: { version: '8.8.0', upgradeable: true } } },
} as any,
agentPolicy: {
is_managed: false,
} as AgentPolicy,
});
expect(res).not.toBe(null);
expect(res).toBeEnabled();
});
it('should render a disabled action button if agent version is latest', async () => {
const res = renderAndGetUpgradeButton({
agent: {
active: true,
status: 'online',
local_metadata: { elastic: { agent: { version: '8.10.2', upgradeable: true } } },
} as any,
agentPolicy: {
is_managed: false,
} as AgentPolicy,
});
expect(res).not.toBe(null);
expect(res).not.toBeEnabled();
});
});
});

View file

@ -14,7 +14,7 @@ import { isAgentRequestDiagnosticsSupported } from '../../../../../../../common/
import { isStuckInUpdating } from '../../../../../../../common/services/agent_status';
import type { Agent, AgentPolicy } from '../../../../types';
import { useAuthz, useLink, useKibanaVersion } from '../../../../hooks';
import { useAuthz, useLink, useAgentVersion } from '../../../../hooks';
import { ContextMenuActions } from '../../../../components';
import { isAgentUpgradeable } from '../../../../services';
import { ExperimentalFeaturesService } from '../../../../services';
@ -42,7 +42,7 @@ export const TableRowActions: React.FunctionComponent<{
const hasFleetAllPrivileges = useAuthz().fleet.all;
const isUnenrolling = agent.status === 'unenrolling';
const kibanaVersion = useKibanaVersion();
const latestAgentVersion = useAgentVersion();
const [isMenuOpen, setIsMenuOpen] = useState(false);
const { diagnosticFileUploadEnabled, agentTamperProtectionEnabled } =
ExperimentalFeaturesService.get();
@ -107,10 +107,11 @@ export const TableRowActions: React.FunctionComponent<{
<EuiContextMenuItem
key="agentUpgradeBtn"
icon="refresh"
disabled={!isAgentUpgradeable(agent, kibanaVersion)}
disabled={!!latestAgentVersion && !isAgentUpgradeable(agent, latestAgentVersion)}
onClick={() => {
onUpgradeClick();
}}
data-test-subj="upgradeBtn"
>
<FormattedMessage
id="xpack.fleet.agentList.upgradeOneButton"

View file

@ -21,13 +21,14 @@ jest.mock('../../../../hooks', () => {
...jest.requireActual('../../../../hooks'),
sendGetAgentsAvailableVersions: jest.fn().mockResolvedValue({
data: {
items: ['8.7.0'],
items: ['8.10.2', '8.7.0'],
},
}),
sendGetAgentStatus: jest.fn().mockResolvedValue({
data: { results: { updating: 2 } },
}),
sendPostBulkAgentUpgrade: jest.fn(),
useAgentVersion: jest.fn().mockReturnValue('8.10.2'),
};
});
@ -86,6 +87,18 @@ describe('AgentUpgradeAgentModal', () => {
});
});
it('should default the version combo to latest agent version', async () => {
const { utils } = renderAgentUpgradeAgentModal({
agents: [{ id: 'agent1', local_metadata: { host: 'abc' } }] as any,
agentCount: 1,
});
const el = utils.getByTestId('agentUpgradeModal.VersionCombobox');
await waitFor(() => {
expect(el.textContent).toEqual('8.10.2');
});
});
it('should restart uprade on updating agents if some agents in updating', async () => {
const { utils } = renderAgentUpgradeAgentModal({
agents: [

View file

@ -41,6 +41,7 @@ import {
useKibanaVersion,
useConfig,
sendGetAgentStatus,
useAgentVersion,
} from '../../../../hooks';
import { sendGetAgentsAvailableVersions } from '../../../../hooks';
@ -196,6 +197,20 @@ export const AgentUpgradeAgentModal: React.FunctionComponent<AgentUpgradeAgentMo
},
];
const [selectedVersion, setSelectedVersion] = useState(preselected);
// latest agent version might be earlier than kibana version
const latestAgentVersion = useAgentVersion();
useEffect(() => {
if (latestAgentVersion) {
setSelectedVersion([
{
label: latestAgentVersion,
value: latestAgentVersion,
},
]);
}
}, [latestAgentVersion]);
const [selectedMaintenanceWindow, setSelectedMaintenanceWindow] = useState([
isSmallBatch ? maintenanceOptions[0] : maintenanceOptions[1],
]);

View file

@ -24,6 +24,7 @@ import { getAgentById } from '../../services/agents';
import type { Agent } from '../../types';
import { getAllFleetServerAgents } from '../../collectors/get_all_fleet_server_agents';
import { getLatestAvailableVersion } from '../../services/agents/versions';
export const postAgentUpgradeHandler: RequestHandler<
TypeOf<typeof PostAgentUpgradeRequestSchema.params>,
@ -35,6 +36,7 @@ export const postAgentUpgradeHandler: RequestHandler<
const esClient = coreContext.elasticsearch.client.asInternalUser;
const { version, source_uri: sourceUri, force } = request.body;
const kibanaVersion = appContextService.getKibanaVersion();
const latestAgentVersion = await getLatestAvailableVersion();
try {
checkKibanaVersion(version, kibanaVersion, force);
} catch (err) {
@ -73,7 +75,7 @@ export const postAgentUpgradeHandler: RequestHandler<
},
});
}
if (!force && !isAgentUpgradeable(agent, kibanaVersion, version)) {
if (!force && !isAgentUpgradeable(agent, latestAgentVersion, version)) {
return response.customError({
statusCode: 400,
body: {

View file

@ -24,6 +24,7 @@ import { auditLoggingService } from '../audit_logging';
import { searchHitToAgent, agentSOAttributesToFleetServerAgentDoc } from './helpers';
import { buildAgentStatusRuntimeField } from './build_status_runtime_field';
import { getLatestAvailableVersion } from './versions';
const INACTIVE_AGENT_CONDITION = `status:inactive OR status:unenrolled`;
const ACTIVE_AGENT_CONDITION = `NOT (${INACTIVE_AGENT_CONDITION})`;
@ -302,6 +303,7 @@ export async function getAgentsByKuery(
// filtering for a range on the version string will not work,
// nor does filtering on a flattened field (local_metadata), so filter here
if (showUpgradeable) {
const latestAgentVersion = await getLatestAvailableVersion();
// fixing a bug where upgradeable filter was not returning right results https://github.com/elastic/kibana/issues/117329
// query all agents, then filter upgradeable, and return the requested page and correct total
// if there are more than SO_SEARCH_LIMIT agents, the logic falls back to same as before
@ -309,14 +311,12 @@ export async function getAgentsByKuery(
const response = await queryAgents(0, SO_SEARCH_LIMIT);
agents = response.hits.hits
.map(searchHitToAgent)
.filter((agent) => isAgentUpgradeable(agent, appContextService.getKibanaVersion()));
.filter((agent) => isAgentUpgradeable(agent, latestAgentVersion));
total = agents.length;
const start = (page - 1) * perPage;
agents = agents.slice(start, start + perPage);
} else {
agents = agents.filter((agent) =>
isAgentUpgradeable(agent, appContextService.getKibanaVersion())
);
agents = agents.filter((agent) => isAgentUpgradeable(agent, latestAgentVersion));
}
}

View file

@ -26,6 +26,7 @@ import { createErrorActionResults, createAgentAction } from './actions';
import { getHostedPolicies, isHostedAgent } from './hosted_agent';
import { BulkActionTaskType } from './bulk_action_types';
import { getCancelledActions } from './action_status';
import { getLatestAvailableVersion } from './versions';
export class UpgradeActionRunner extends ActionRunner {
protected async processAgents(agents: Agent[]): Promise<{ actionId: string }> {
@ -72,12 +73,12 @@ export async function upgradeBatch(
? givenAgents.filter((agent: Agent) => !isHostedAgent(hostedPolicies, agent))
: givenAgents;
const kibanaVersion = appContextService.getKibanaVersion();
const latestAgentVersion = await getLatestAvailableVersion();
const upgradeableResults = await Promise.allSettled(
agentsToCheckUpgradeable.map(async (agent) => {
// Filter out agents currently unenrolling, unenrolled, or not upgradeable b/c of version check
const isNotAllowed =
!options.force && !isAgentUpgradeable(agent, kibanaVersion, options.version);
!options.force && !isAgentUpgradeable(agent, latestAgentVersion, options.version);
if (isNotAllowed) {
throw new FleetError(`Agent ${agent.id} is not upgradeable`);
}

View file

@ -30,7 +30,7 @@ describe('getAvailableVersions', () => {
mockKibanaVersion = '300.0.0';
mockedReadFile.mockResolvedValue(`["8.1.0", "8.0.0", "7.17.0", "7.16.0"]`);
const res = await getAvailableVersions({ cached: false });
const res = await getAvailableVersions({ cached: false, includeCurrentVersion: true });
expect(res).toEqual(['300.0.0', '8.1.0', '8.0.0', '7.17.0']);
});
@ -39,11 +39,11 @@ describe('getAvailableVersions', () => {
mockKibanaVersion = '300.0.0-SNAPSHOT';
mockedReadFile.mockResolvedValue(`["8.1.0", "8.0.0", "7.17.0", "7.16.0"]`);
const res = await getAvailableVersions({ cached: false });
const res = await getAvailableVersions({ cached: false, includeCurrentVersion: true });
expect(res).toEqual(['300.0.0-SNAPSHOT', '8.1.0', '8.0.0', '7.17.0']);
});
it('should not include the current version if onlyAllowAgentUpgradeToKnownVersions = true', async () => {
it('should not include the current version if includeCurrentVersion is not set', async () => {
mockKibanaVersion = '300.0.0-SNAPSHOT';
mockConfig = {
internal: {
@ -65,4 +65,18 @@ describe('getAvailableVersions', () => {
expect(res).toEqual(['8.1.0', '8.0.0', '7.17.0']);
});
it('should return kibana version only if cannot read versions', async () => {
mockKibanaVersion = '300.0.0';
mockConfig = {
internal: {
onlyAllowAgentUpgradeToKnownVersions: false,
},
};
mockedReadFile.mockRejectedValue({ code: 'ENOENT' });
const res = await getAvailableVersions({ cached: false });
expect(res).toEqual(['300.0.0']);
});
});

View file

@ -60,8 +60,7 @@ export const getAvailableVersions = async ({
.sort((a: any, b: any) => (semverGt(a, b) ? -1 : 1));
versionsToDisplay = uniq(versions) as string[];
const appendCurrentVersion =
includeCurrentVersion ?? !config?.internal?.onlyAllowAgentUpgradeToKnownVersions;
const appendCurrentVersion = includeCurrentVersion;
if (appendCurrentVersion) {
// Add current version if not already present