chore: move source to repo root and standardize config

Phase 1 — Structural overhaul:
- Move all source from headlamp-sealed-secrets/ subdirectory to repo root
- Delete 23 AI-generated docs, 8 pre-built tarballs, release snapshots dir
- Remove all working-directory refs from CI/release workflows
- Update install-plugin.sh and typedoc.json paths

Phase 2 — Config standardization:
- Create .eslintrc.js and .prettierrc.js (standard Headlamp configs)
- Remove inline eslintConfig/prettier from package.json (drop jsx-a11y, prettier extends)
- Rewrite tsconfig.json (package name extend, add compilerOptions.types)
- Create vitest.config.mts and vitest.setup.ts (standard from polaris)
- Replace headlamp-plugin CLI scripts with direct tool invocation
- Rewrite .gitignore with standard baseline

Phase 3 — MCP & Claude settings:
- Create .mcp.json with github/kubernetes/flux/playwright servers
- Create .claude/settings.local.json
- Remove 7 specialized agents, keep 3 meta-orchestration agents

Phase 4 — Documentation:
- Rewrite CLAUDE.md (remove subdirectory refs, standard format)
- Add ArtifactHub badge, Architecture section, standardized install methods to README.md
- Create CONTRIBUTING.md and SECURITY.md
- Fix pre-existing test bugs in validators.test.ts (isValidNamespace returns boolean,
  not ValidationResult; error message string mismatches)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
DevContainer User
2026-03-03 21:31:12 +00:00
parent 604fe06f9c
commit af95c3795c
108 changed files with 704 additions and 14041 deletions
+198
View File
@@ -0,0 +1,198 @@
/**
* SealedSecret Custom Resource Definition
*/
import { ApiProxy,K8s } from '@kinvolk/headlamp-plugin/lib';
const { apiFactoryWithNamespace } = ApiProxy;
const { KubeObject } = K8s.cluster;
import { AsyncResult, Err, Ok, tryCatchAsync } from '../types';
import {
SealedSecretInterface,
SealedSecretScope,
SealedSecretSpec,
SealedSecretStatus,
} from '../types';
/**
* SealedSecret CRD class
* Represents a Bitnami Sealed Secret resource in the cluster
*/
export class SealedSecret extends KubeObject<SealedSecretInterface> {
/**
* Default API version (fallback)
*/
static readonly DEFAULT_VERSION = 'bitnami.com/v1alpha1';
/**
* Cached detected API version
*/
private static detectedVersion: string | null = null;
/**
* API endpoint for SealedSecret resources
* bitnami.com/v1alpha1/sealedsecrets
*/
static apiEndpoint = apiFactoryWithNamespace('bitnami.com', 'v1alpha1', 'sealedsecrets');
/**
* Class name used for Headlamp registration
*/
static get className(): string {
return 'SealedSecret';
}
/**
* Get the SealedSecret spec
*/
get spec(): SealedSecretSpec {
return this.jsonData.spec;
}
/**
* Get the SealedSecret status
*/
get status(): SealedSecretStatus | undefined {
return this.jsonData.status;
}
/**
* Get the scope of this SealedSecret (strict, namespace-wide, or cluster-wide)
*/
get scope(): SealedSecretScope {
const annotations = this.metadata.annotations || {};
if (annotations['sealedsecrets.bitnami.com/cluster-wide'] === 'true') {
return 'cluster-wide';
}
if (annotations['sealedsecrets.bitnami.com/namespace-wide'] === 'true') {
return 'namespace-wide';
}
return 'strict';
}
/**
* Get the count of encrypted keys
*/
get encryptedKeysCount(): number {
return Object.keys(this.spec.encryptedData || {}).length;
}
/**
* Check if the SealedSecret is synced
*/
get isSynced(): boolean {
const syncCondition = this.status?.conditions?.find(c => c.type === 'Synced');
return syncCondition?.status === 'True';
}
/**
* Get the sync status condition
*/
get syncCondition() {
return this.status?.conditions?.find(c => c.type === 'Synced');
}
/**
* Get the sync status message
*/
get syncMessage(): string {
const condition = this.syncCondition;
if (!condition) {
return 'Unknown';
}
// Ensure we always return a string, not an object
const message = condition.message || condition.reason || condition.status;
return String(message || 'Unknown');
}
/**
* Detect the API version available in the cluster
*
* Queries the SealedSecrets CRD to determine which API version is installed
* and preferred. Returns the storage version (the version used for persisting
* objects in etcd).
*
* @returns Result containing the API version string (e.g., "bitnami.com/v1alpha1")
*/
static async detectApiVersion(): AsyncResult<string, string> {
// Return cached version if available
if (this.detectedVersion) {
return Ok(this.detectedVersion);
}
const result = await tryCatchAsync(async () => {
// Query the CRD to get available versions using Headlamp's API proxy
const crd = await ApiProxy.request(
'/apis/apiextensions.k8s.io/v1/customresourcedefinitions/sealedsecrets.bitnami.com'
);
// Find the storage version (the version used for persistence)
const storageVersion = crd.spec?.versions?.find((v: any) => v.storage === true);
if (storageVersion) {
const version = `${crd.spec.group}/${storageVersion.name}`;
this.detectedVersion = version;
return version;
}
// Fallback to first served version if no storage version found
const servedVersion = crd.spec?.versions?.find((v: any) => v.served === true);
if (servedVersion) {
const version = `${crd.spec.group}/${servedVersion.name}`;
this.detectedVersion = version;
return version;
}
// Ultimate fallback to default
return this.DEFAULT_VERSION;
});
if (result.ok === false) {
return Err(result.error.message);
}
return Ok(result.value);
}
/**
* Get API endpoint with auto-detected version
*
* Automatically detects and uses the correct API version from the cluster.
* Falls back to default version (v1alpha1) if detection fails.
*
* @returns API endpoint configured with the detected version
*/
static async getApiEndpoint() {
const versionResult = await this.detectApiVersion();
if (versionResult.ok) {
const [group, version] = versionResult.value.split('/');
return apiFactoryWithNamespace(group, version, 'sealedsecrets');
}
// Fallback to default endpoint
return this.apiEndpoint;
}
/**
* Get the detected API version
*
* Returns the cached detected version or null if not yet detected.
*
* @returns The detected API version string or null
*/
static getDetectedVersion(): string | null {
return this.detectedVersion;
}
/**
* Clear the cached API version
*
* Forces re-detection on next call to detectApiVersion().
* Useful for refreshing after CRD updates.
*/
static clearVersionCache(): void {
this.detectedVersion = null;
}
}