mirror of
https://github.com/hashicorp/vault.git
synced 2026-02-18 18:38:08 -05:00
* [VAULT-33083] support mount external engine * add "Plugin type" and "Plugin version" fields to the enable mount page * add changelog * address copilot review comments * address PR comments, code cleanup * fix test failures * Add support for external plugins registered without a plugin version * external plugin should be enabled for enterprise only, plugin version should be mandatory for external plugins * fix tests * address copilot feedback * fix failing tests, add unit test coverage * address PR comments * address PR comments * remove dead code * move no external versions alert * Only show un-versioned plugin message if there are un-versioned plugins in the catalog. * address PR comments * use ApiService instead of custom PluginPinsService; fix failing tests * revert changes to forms/mount.ts and forms/auth/method.ts Co-authored-by: Shannon Roberts (Beagin) <beagins@users.noreply.github.com>
130 lines
4 KiB
TypeScript
130 lines
4 KiB
TypeScript
/**
|
|
* Copyright IBM Corp. 2016, 2025
|
|
* SPDX-License-Identifier: BUSL-1.1
|
|
*/
|
|
|
|
import { isKnownExternalPlugin } from 'vault/utils/external-plugin-helpers';
|
|
|
|
/**
|
|
* Utility functions for semantic version handling
|
|
*/
|
|
|
|
/**
|
|
* Clean a version string by removing prefixes and suffixes
|
|
* @param version - The version string to clean (e.g., "v1.2.3+ent")
|
|
* @returns The cleaned version string (e.g., "1.2.3")
|
|
*/
|
|
export function cleanVersion(version: string): string {
|
|
return version.replace(/^v/, '').split(/[+-]/)[0] || '';
|
|
}
|
|
|
|
/**
|
|
* Parse a version string into numeric parts
|
|
* @param version - The version string to parse
|
|
* @returns Array of numeric version parts
|
|
*/
|
|
export function parseVersion(version: string): number[] {
|
|
const cleanVer = cleanVersion(version);
|
|
return cleanVer.split('.').map((n) => parseInt(n) || 0);
|
|
}
|
|
|
|
/**
|
|
* Compare two version strings using semantic version rules
|
|
* @param a - First version to compare
|
|
* @param b - Second version to compare
|
|
* @returns Negative if a < b, positive if a > b, 0 if equal
|
|
*/
|
|
export function compareVersions(a: string, b: string): number {
|
|
const aParts = parseVersion(a);
|
|
const bParts = parseVersion(b);
|
|
|
|
const maxLength = Math.max(aParts.length, bParts.length);
|
|
for (let i = 0; i < maxLength; i++) {
|
|
const aPart = aParts[i] || 0;
|
|
const bPart = bParts[i] || 0;
|
|
|
|
if (aPart !== bPart) {
|
|
return aPart - bPart;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Sort an array of version strings in semantic version order
|
|
* @param versions - Array of version strings to sort
|
|
* @param descending - If true, sort highest version first (default: false)
|
|
* @returns New sorted array (does not mutate original)
|
|
*/
|
|
export function sortVersions(versions: string[], descending = false): string[] {
|
|
const sorted = versions.slice().sort((a, b) => compareVersions(a, b));
|
|
return descending ? sorted.reverse() : sorted;
|
|
}
|
|
|
|
/**
|
|
* Find the highest version from an array of version strings
|
|
* @param versions - Array of version strings
|
|
* @returns The highest version string, or null if array is empty
|
|
*/
|
|
export function getHighestVersion(versions: string[]): string | null {
|
|
if (versions.length === 0) return null;
|
|
|
|
const sorted = sortVersions(versions, true);
|
|
return sorted[0] || null;
|
|
}
|
|
|
|
/**
|
|
* Check if version A is greater than version B
|
|
* @param a - First version
|
|
* @param b - Second version
|
|
* @returns True if a > b
|
|
*/
|
|
export function isVersionGreater(a: string, b: string): boolean {
|
|
return compareVersions(a, b) > 0;
|
|
}
|
|
|
|
/**
|
|
* Check if two versions are equal
|
|
* @param a - First version
|
|
* @param b - Second version
|
|
* @returns True if versions are equal
|
|
*/
|
|
export function areVersionsEqual(a: string, b: string): boolean {
|
|
return compareVersions(a, b) === 0;
|
|
}
|
|
|
|
/**
|
|
* Check if a version string is valid and non-empty
|
|
* @param version - The version string to validate
|
|
* @returns True if the version is valid
|
|
*/
|
|
export function isValidVersion(version: string): boolean {
|
|
if (!version || typeof version !== 'string') return false;
|
|
|
|
const trimmed = version.trim();
|
|
if (trimmed === '' || trimmed === 'null') return false;
|
|
|
|
// Basic semantic version pattern check (allows prefixes like 'v' and suffixes like '+ent')
|
|
const semverPattern = /^v?\d+(\.\d+)*([+-].+)?$/;
|
|
const cleanVer = cleanVersion(trimmed);
|
|
|
|
return semverPattern.test(`v${cleanVer}`);
|
|
}
|
|
|
|
/**
|
|
* Check if a plugin version is required for external plugins
|
|
* @param pluginType - The plugin type (e.g., 'keymgmt' or 'vault-plugin-secrets-keymgmt')
|
|
* @param pluginVersion - The plugin version string
|
|
* @returns True if the plugin version requirement is satisfied
|
|
*/
|
|
export function isPluginVersionValidForType(pluginType: string, pluginVersion?: string): boolean {
|
|
if (!pluginType) return false;
|
|
|
|
if (isKnownExternalPlugin(pluginType)) {
|
|
// External plugins require a valid version
|
|
return isValidVersion(pluginVersion || '');
|
|
} else {
|
|
// Builtin plugins should not have a version specified
|
|
return !pluginVersion || pluginVersion.trim() === '' || pluginVersion.trim() === 'null';
|
|
}
|
|
}
|