feat: implement API version detection and compatibility (Phase 2.4)
Add automatic detection of SealedSecrets CRD API version from cluster. The plugin now adapts to installed versions (v1alpha1, v1, etc.) and provides warnings when CRD is missing or non-default versions are used. Changes: - Add detectApiVersion() to SealedSecretCRD class - Queries CRD definition from Kubernetes API - Uses storage version (canonical version for etcd) - Caches result to avoid repeated API calls - Falls back to v1alpha1 if detection fails - Create VersionWarning component - Auto-detects version on mount - Shows error alert for missing CRD (with install instructions) - Shows info alert for non-default versions - Provides retry button for failed detections - Configurable detail level (showDetails prop) - Integrate version warnings into UI - SealedSecretList: minimal warnings (errors only) - SettingsPage: detailed version info always shown - Add version management methods - getApiEndpoint(): auto-versioned endpoint - getDetectedVersion(): get cached version - clearVersionCache(): force re-detection Benefits: - Future-proof: automatically supports new API versions - Better UX: clear error messages with installation help - Performance: version detected once and cached - Version awareness: users see which API version is active Build: 351.34 kB (96.75 kB gzipped), +2.88 kB (+0.8%) Phase 2.4 complete. 7 of 14 phases done (50% milestone). Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
This commit is contained in:
@@ -17,6 +17,7 @@ import { usePermission } from '../hooks/usePermissions';
|
||||
import { SealedSecret } from '../lib/SealedSecretCRD';
|
||||
import { SealedSecretScope } from '../types';
|
||||
import { EncryptDialog } from './EncryptDialog';
|
||||
import { VersionWarning } from './VersionWarning';
|
||||
|
||||
/**
|
||||
* Format scope for display
|
||||
@@ -75,6 +76,7 @@ export function SealedSecretList() {
|
||||
<SectionBox
|
||||
title="Sealed Secrets"
|
||||
>
|
||||
<VersionWarning autoDetect showDetails={false} />
|
||||
<SectionFilterHeader
|
||||
title=""
|
||||
noNamespaceFilter={false}
|
||||
|
||||
@@ -11,6 +11,7 @@ import React from 'react';
|
||||
import { getPluginConfig, savePluginConfig } from '../lib/controller';
|
||||
import { PluginConfig } from '../types';
|
||||
import { ControllerStatus } from './ControllerStatus';
|
||||
import { VersionWarning } from './VersionWarning';
|
||||
|
||||
/**
|
||||
* Settings page component
|
||||
@@ -43,6 +44,9 @@ export function SettingsPage() {
|
||||
your browser's local storage.
|
||||
</Typography>
|
||||
|
||||
{/* API Version Detection */}
|
||||
<VersionWarning autoDetect showDetails />
|
||||
|
||||
{/* Controller Health Status */}
|
||||
<Box mb={3} p={2} bgcolor="background.paper" borderRadius={1} border={1} borderColor="divider">
|
||||
<Typography variant="subtitle2" gutterBottom>
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
/**
|
||||
* Version Warning Component
|
||||
*
|
||||
* Displays warnings about API version compatibility and issues.
|
||||
*/
|
||||
|
||||
import { Alert, Box, Button, Link } from '@mui/material';
|
||||
import React from 'react';
|
||||
import { SealedSecret } from '../lib/SealedSecretCRD';
|
||||
|
||||
export interface VersionWarningProps {
|
||||
/** Whether to auto-detect version on mount */
|
||||
autoDetect?: boolean;
|
||||
/** Whether to show detailed version information */
|
||||
showDetails?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Component that detects and displays API version information
|
||||
*
|
||||
* Shows warnings if:
|
||||
* - CRD is not installed
|
||||
* - Version detection fails
|
||||
* - Using non-default version (informational)
|
||||
*/
|
||||
export function VersionWarning({ autoDetect = true, showDetails = false }: VersionWarningProps) {
|
||||
const [loading, setLoading] = React.useState(true);
|
||||
const [detectedVersion, setDetectedVersion] = React.useState<string | null>(null);
|
||||
const [error, setError] = React.useState<string | null>(null);
|
||||
|
||||
const detectVersion = React.useCallback(async () => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
const result = await SealedSecret.detectApiVersion();
|
||||
|
||||
if (result.ok) {
|
||||
setDetectedVersion(result.value);
|
||||
setError(null);
|
||||
} else if (result.ok === false) {
|
||||
setDetectedVersion(null);
|
||||
setError(result.error);
|
||||
}
|
||||
|
||||
setLoading(false);
|
||||
}, []);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (autoDetect) {
|
||||
detectVersion();
|
||||
}
|
||||
}, [autoDetect, detectVersion]);
|
||||
|
||||
// Don't show anything while loading
|
||||
if (loading) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Show error if detection failed
|
||||
if (error) {
|
||||
return (
|
||||
<Box mb={2}>
|
||||
<Alert severity="error" action={
|
||||
<Button color="inherit" size="small" onClick={detectVersion}>
|
||||
Retry
|
||||
</Button>
|
||||
}>
|
||||
<strong>API Version Detection Failed</strong>
|
||||
<br />
|
||||
{error}
|
||||
{error.includes('not found') && (
|
||||
<>
|
||||
<br />
|
||||
<br />
|
||||
Install Sealed Secrets with:{' '}
|
||||
<code style={{ fontSize: '0.875em' }}>
|
||||
kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.24.0/controller.yaml
|
||||
</code>
|
||||
<br />
|
||||
Or visit:{' '}
|
||||
<Link
|
||||
href="https://github.com/bitnami-labs/sealed-secrets"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
color="inherit"
|
||||
>
|
||||
github.com/bitnami-labs/sealed-secrets
|
||||
</Link>
|
||||
</>
|
||||
)}
|
||||
</Alert>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
// Show informational message if using non-default version
|
||||
if (detectedVersion && detectedVersion !== SealedSecret.DEFAULT_VERSION) {
|
||||
return (
|
||||
<Box mb={2}>
|
||||
<Alert severity="info">
|
||||
<strong>API Version Detected</strong>
|
||||
<br />
|
||||
Using API version: <code>{detectedVersion}</code>
|
||||
{showDetails && (
|
||||
<>
|
||||
<br />
|
||||
Default version: <code>{SealedSecret.DEFAULT_VERSION}</code>
|
||||
</>
|
||||
)}
|
||||
</Alert>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
// Show success if explicitly showing details
|
||||
if (showDetails && detectedVersion) {
|
||||
return (
|
||||
<Box mb={2}>
|
||||
<Alert severity="success">
|
||||
<strong>API Version Detected</strong>
|
||||
<br />
|
||||
Using API version: <code>{detectedVersion}</code>
|
||||
</Alert>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
// Default: show nothing (version detected successfully)
|
||||
return null;
|
||||
}
|
||||
Reference in New Issue
Block a user