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:
+285
@@ -0,0 +1,285 @@
|
||||
/**
|
||||
* TypeScript interfaces for Bitnami Sealed Secrets plugin
|
||||
*/
|
||||
|
||||
import { K8s } from '@kinvolk/headlamp-plugin/lib';
|
||||
|
||||
type KubeObjectInterface = K8s.cluster.KubeObjectInterface;
|
||||
|
||||
/**
|
||||
* Result type for operations that can fail
|
||||
* Replaces throw/catch with explicit error handling
|
||||
*
|
||||
* @example
|
||||
* function divide(a: number, b: number): Result<number, string> {
|
||||
* if (b === 0) return Err('Division by zero');
|
||||
* return Ok(a / b);
|
||||
* }
|
||||
*/
|
||||
export type Result<T, E = Error> =
|
||||
| { ok: true; value: T }
|
||||
| { ok: false; error: E };
|
||||
|
||||
/**
|
||||
* Async result type for promises that can fail
|
||||
*/
|
||||
export type AsyncResult<T, E = Error> = Promise<Result<T, E>>;
|
||||
|
||||
/**
|
||||
* Branded types for type-level security
|
||||
* These prevent mixing sensitive/non-sensitive values at compile time
|
||||
*/
|
||||
|
||||
/** Unique symbol for branding plaintext values */
|
||||
declare const PlaintextBrand: unique symbol;
|
||||
|
||||
/** Unique symbol for branding encrypted values */
|
||||
declare const EncryptedBrand: unique symbol;
|
||||
|
||||
/** Unique symbol for branding base64-encoded values */
|
||||
declare const Base64Brand: unique symbol;
|
||||
|
||||
/** Unique symbol for branding PEM certificates */
|
||||
declare const PEMCertBrand: unique symbol;
|
||||
|
||||
/**
|
||||
* Plaintext sensitive value (not yet encrypted)
|
||||
* Must be explicitly created via PlaintextValue()
|
||||
*/
|
||||
export type PlaintextValue = string & { readonly [PlaintextBrand]: typeof PlaintextBrand };
|
||||
|
||||
/**
|
||||
* Encrypted value (already encrypted)
|
||||
* Created by encryption functions
|
||||
*/
|
||||
export type EncryptedValue = string & { readonly [EncryptedBrand]: typeof EncryptedBrand };
|
||||
|
||||
/**
|
||||
* Base64-encoded string
|
||||
* Created by base64 encoding functions
|
||||
*/
|
||||
export type Base64String = string & { readonly [Base64Brand]: typeof Base64Brand };
|
||||
|
||||
/**
|
||||
* PEM-encoded certificate
|
||||
* Created by certificate parsing functions
|
||||
*/
|
||||
export type PEMCertificate = string & { readonly [PEMCertBrand]: typeof PEMCertBrand };
|
||||
|
||||
/**
|
||||
* Create a branded plaintext value
|
||||
* Use this to mark user input as plaintext before encryption
|
||||
*
|
||||
* @example
|
||||
* const secret = PlaintextValue('my-password');
|
||||
*/
|
||||
export function PlaintextValue(value: string): PlaintextValue {
|
||||
return value as PlaintextValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a branded encrypted value
|
||||
* This is typically used by encryption functions
|
||||
*
|
||||
* @example
|
||||
* return Ok(EncryptedValue(encryptedString));
|
||||
*/
|
||||
export function EncryptedValue(value: string): EncryptedValue {
|
||||
return value as EncryptedValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a branded base64 string
|
||||
*
|
||||
* @example
|
||||
* return Ok(Base64String(encoded));
|
||||
*/
|
||||
export function Base64String(value: string): Base64String {
|
||||
return value as Base64String;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a branded PEM certificate
|
||||
*
|
||||
* @example
|
||||
* return Ok(PEMCertificate(certPem));
|
||||
*/
|
||||
export function PEMCertificate(value: string): PEMCertificate {
|
||||
return value as PEMCertificate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unwrap a branded type to get the raw string
|
||||
* Use sparingly - only when you need the raw value
|
||||
*
|
||||
* @example
|
||||
* const rawValue = unwrap(plaintextValue);
|
||||
*/
|
||||
export function unwrap<T extends string>(value: T): string {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to create a success result
|
||||
*
|
||||
* @example
|
||||
* return Ok(42);
|
||||
*/
|
||||
export function Ok<T>(value: T): Result<T, never> {
|
||||
return { ok: true, value };
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to create an error result
|
||||
*
|
||||
* @example
|
||||
* return Err('Something went wrong');
|
||||
* return Err(new Error('Something went wrong'));
|
||||
*/
|
||||
export function Err<E>(error: E): Result<never, E> {
|
||||
return { ok: false, error };
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a throwing function to a Result-returning function
|
||||
*
|
||||
* @example
|
||||
* const safeParseJSON = tryCatch(JSON.parse);
|
||||
* const result = safeParseJSON('{"key": "value"}');
|
||||
* if (result.ok) {
|
||||
* console.log(result.value);
|
||||
* }
|
||||
*/
|
||||
export function tryCatch<T>(fn: () => T): Result<T, Error> {
|
||||
try {
|
||||
return Ok(fn());
|
||||
} catch (error) {
|
||||
return Err(error instanceof Error ? error : new Error(String(error)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an async throwing function to an AsyncResult
|
||||
*
|
||||
* @example
|
||||
* const safeFetch = tryCatchAsync(() => fetch('/api/data'));
|
||||
* const result = await safeFetch();
|
||||
*/
|
||||
export async function tryCatchAsync<T>(fn: () => Promise<T>): AsyncResult<T, Error> {
|
||||
try {
|
||||
const value = await fn();
|
||||
return Ok(value);
|
||||
} catch (error) {
|
||||
return Err(error instanceof Error ? error : new Error(String(error)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sealed Secret scope types
|
||||
*/
|
||||
export type SealedSecretScope = 'strict' | 'namespace-wide' | 'cluster-wide';
|
||||
|
||||
/**
|
||||
* SealedSecret CRD spec
|
||||
*/
|
||||
export interface SealedSecretSpec {
|
||||
/** Map of key names to encrypted (base64-encoded) values */
|
||||
encryptedData: Record<string, string>;
|
||||
/** Metadata template for the resulting Secret */
|
||||
template?: {
|
||||
metadata?: {
|
||||
labels?: Record<string, string>;
|
||||
annotations?: Record<string, string>;
|
||||
};
|
||||
type?: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* SealedSecret status condition
|
||||
*/
|
||||
export interface SealedSecretCondition {
|
||||
type: string;
|
||||
status: 'True' | 'False' | 'Unknown';
|
||||
lastTransitionTime?: string;
|
||||
lastUpdateTime?: string;
|
||||
reason?: string;
|
||||
message?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* SealedSecret CRD status
|
||||
*/
|
||||
export interface SealedSecretStatus {
|
||||
conditions?: SealedSecretCondition[];
|
||||
observedGeneration?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete SealedSecret CRD interface
|
||||
*/
|
||||
export interface SealedSecretInterface extends KubeObjectInterface {
|
||||
spec: SealedSecretSpec;
|
||||
status?: SealedSecretStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Plugin configuration stored in localStorage
|
||||
*/
|
||||
export interface PluginConfig {
|
||||
/** Controller deployment name */
|
||||
controllerName: string;
|
||||
/** Controller namespace */
|
||||
controllerNamespace: string;
|
||||
/** Controller service port */
|
||||
controllerPort: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default plugin configuration
|
||||
*/
|
||||
export const DEFAULT_CONFIG: PluginConfig = {
|
||||
controllerName: 'sealed-secrets-controller',
|
||||
controllerNamespace: 'kube-system',
|
||||
controllerPort: 8080,
|
||||
};
|
||||
|
||||
/**
|
||||
* Key-value pair for encryption dialog
|
||||
*/
|
||||
export interface SecretKeyValue {
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encryption request parameters
|
||||
*/
|
||||
export interface EncryptionRequest {
|
||||
name: string;
|
||||
namespace: string;
|
||||
scope: SealedSecretScope;
|
||||
keyValues: SecretKeyValue[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Certificate information extracted from PEM certificate
|
||||
*/
|
||||
export interface CertificateInfo {
|
||||
/** Validity period start date */
|
||||
validFrom: Date;
|
||||
/** Validity period end date */
|
||||
validTo: Date;
|
||||
/** Whether certificate is currently expired */
|
||||
isExpired: boolean;
|
||||
/** Days until expiry (negative if expired) */
|
||||
daysUntilExpiry: number;
|
||||
/** Certificate issuer (formatted as DN string) */
|
||||
issuer: string;
|
||||
/** Certificate subject (formatted as DN string) */
|
||||
subject: string;
|
||||
/** SHA-256 fingerprint of certificate */
|
||||
fingerprint: string;
|
||||
/** Serial number of certificate */
|
||||
serialNumber: string;
|
||||
}
|
||||
Reference in New Issue
Block a user