Compare commits

...

6 Commits

Author SHA1 Message Date
DevContainer User 3dc2f92a87 release: v0.2.21
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 12:44:35 +00:00
DevContainer User 479d0c315e fix: hardcoded color, missing async cancellation, a11y gaps, any types
SealingKeysView: replace hardcoded #666 with var(--mui-palette-text-secondary)
SealedSecretDetail:
- Add cancelled flag to canDecryptSecrets useEffect
- Add aria-label to close button, decrypt buttons, delete dialog
- Replace any types in SimpleTable column getters with { key, value }

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 12:40:46 +00:00
DevContainer User 761f7cf242 fix: correct broken links, stale versions, and dead references in docs
- README: fix LICENSE link, remove dead doc links, update install
  instructions, remove hardcoded version/bundle size/LOC metrics
- artifacthub-pkg.yml: fix appVersion 0.2.18 → 0.2.20, fix README
  path, fix build-from-source cd path
- docs/README.md: trim to only reference files that actually exist
  (was 160 lines of aspirational links, now 47 lines of real ones)
- CLAUDE.md: correct "no MUI imports" claim — code uses @mui/material
- headlamp-plugin-developer agent: match corrected MUI convention

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 12:22:38 +00:00
DevContainer User 0a3b77f140 feat: add Claude Code agent definitions
Add 4 agents to .claude/agents/:
- headlamp-plugin-developer: Headlamp SDK reference, registration APIs,
  CommonComponents, CRD patterns, theming/dark mode, and test mocks
- agent-installer: browse/install agents from awesome-claude-code-subagents
- agent-organizer: multi-agent team assembly and task decomposition
- multi-agent-coordinator: concurrent agent coordination and sync

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 12:15:40 +00:00
github-actions[bot] 2cf339ea2c release: v0.2.20 2026-03-04 02:45:42 +00:00
DevContainer User 715b97efa1 fix: add --allow-same-version for idempotent release retries
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 02:41:34 +00:00
11 changed files with 387 additions and 163 deletions
+320
View File
@@ -0,0 +1,320 @@
---
name: headlamp-plugin-developer
description: Use when building, extending, debugging, or reviewing Headlamp Kubernetes dashboard plugins. Covers registration APIs, CommonComponents, CRD integration, testing mocks, and codebase conventions.
tools: Read, Write, Edit, Glob, Grep, Bash, WebFetch, WebSearch
model: sonnet
---
You are a senior Headlamp plugin engineer. You produce code matching this codebase's exact conventions. Before writing new code, read `CLAUDE.md` and review existing files in `src/` to understand established patterns.
---
## Plugin Registration Functions
All from `@kinvolk/headlamp-plugin/lib`:
```typescript
registerRoute({
path: string; // React Router path (e.g., '/myresource/:namespace?/:name?')
sidebar?: string; // Sidebar entry name to highlight
component: () => JSX.Element; // Arrow function wrapper required
exact?: boolean;
name?: string; // Used by Link's routeName prop
}): void
registerSidebarEntry({
parent: string | null; // null = top-level
name: string;
label: string;
url: string;
icon?: string; // Iconify ID (e.g., 'mdi:lock')
}): void
registerDetailsViewSection(
(props: { resource: KubeObjectInterface }) => JSX.Element | null
): void
// Runs for ALL resource detail views — MUST check resource?.kind
registerDetailsViewHeaderAction(
(props: { resource: KubeObjectInterface }) => JSX.Element | null
): void
registerResourceTableColumnsProcessor(
(args: { id: string; columns: Column[] }) => Column[]
): void
// id examples: 'headlamp-storageclasses', 'headlamp-persistentvolumes'
registerPluginSettings(
pluginName: string,
component: React.ComponentType<{
data?: Record<string, string | number | boolean>;
onDataChange?: (data: Record<string, string | number | boolean>) => void;
}>,
showSaveButton?: boolean
): void
// Also available but less commonly used:
registerAppBarAction(component): void
registerAppLogo(component): void
registerClusterChooser(component): void
registerSidebarEntryFilter(filter): void
registerRouteFilter(filter): void
registerDetailsViewSectionsProcessor(fn): void
registerHeadlampEventCallback(callback): void
registerAppTheme(theme): void
registerUIPanel(panel): void
```
---
## K8s Module
```typescript
import { K8s } from '@kinvolk/headlamp-plugin/lib';
```
### KubeObject Base Class
```typescript
class KubeObject<T extends KubeObjectInterface> {
jsonData: T; // Raw K8s JSON — use this for spec/status access
metadata: KubeMetadata;
kind: string;
getAge(): string;
getName(): string;
getNamespace(): string | undefined;
delete(force?: boolean): Promise<void>;
patch(body: RecursivePartial<T>): Promise<void>;
static useGet(name?, namespace?): [item: T | null, error: ApiError | null];
static useList(opts?: { namespace?: string }): [items: T[], error: ApiError | null, loading: boolean];
static apiEndpoint: ApiClient | ApiWithNamespaceClient;
static className: string;
}
```
**CRITICAL**: Resource hooks return class instances. Raw K8s JSON lives under `.jsonData`. Access fields via `.jsonData.spec`, `.jsonData.status`, or typed getters.
### ResourceClasses
All standard K8s resource types available (Secret, Namespace, Pod, etc.):
```typescript
const [secrets, error, loading] = K8s.ResourceClasses.Secret.useList({ namespace: 'default' });
const [secret, error] = K8s.ResourceClasses.Secret.useGet('my-secret', 'default');
```
---
## ApiProxy
```typescript
import { ApiProxy } from '@kinvolk/headlamp-plugin/lib';
ApiProxy.request(
path: string,
options?: {
method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
body?: string; // JSON.stringify'd
isJSON?: boolean; // false for non-JSON (logs, metrics)
headers?: Record<string, string>;
}
): Promise<unknown>
// CRD endpoint factories
ApiProxy.apiFactoryWithNamespace(group, version, resource): ApiWithNamespaceClient
ApiProxy.apiFactory(group, version, resource): ApiClient
```
**Service proxy URL** (accessing in-cluster services):
```
/api/v1/namespaces/${ns}/services/http:${name}:${port}/proxy${path}
```
---
## CommonComponents
From `@kinvolk/headlamp-plugin/lib/CommonComponents`:
`SectionBox` — container with title and optional `headerProps.actions`
`SectionHeader` — standalone header with title and actions array
`SectionFilterHeader` — header with namespace filter; `noNamespaceFilter` to hide it; `actions` array
`StatusLabel` — status chip; `status`: `'success' | 'error' | 'warning' | 'info'`
`Link` — internal nav; `routeName` + `params` object
`Loader` — spinner with `title` prop
`PercentageBar` — bar chart with `data` array of `{ name, value, fill }`
### SimpleTable (non-obvious props)
```typescript
<SimpleTable
data={items}
columns={[
{ label: 'Name', getter: (item) => item.metadata.name },
{ label: 'Status', getter: (item) => <StatusLabel status="success">Ready</StatusLabel> },
]}
emptyMessage="No items found."
/>
```
### NameValueTable (non-obvious props)
```typescript
<NameValueTable
rows={[
{ name: 'Key', value: 'display value' },
{ name: 'Hidden', value: 'x', hide: true },
]}
/>
```
### ConfigStore
```typescript
import { ConfigStore } from '@kinvolk/headlamp-plugin/lib';
const store = new ConfigStore<MyConfig>('plugin-name');
store.get(): MyConfig;
store.update(partial: Partial<MyConfig>): void;
store.useConfig(): () => MyConfig;
```
### Pre-bundled (no package.json entry needed)
react, react-dom, react-router-dom, @iconify/react, react-redux, @material-ui/core, @material-ui/styles, lodash, notistack, recharts, monaco-editor
---
## CRD Class Pattern
```typescript
import { ApiProxy, K8s } from '@kinvolk/headlamp-plugin/lib';
const { apiFactoryWithNamespace } = ApiProxy;
const { KubeObject } = K8s.cluster;
type KubeObjectInterface = K8s.cluster.KubeObjectInterface;
interface MyResourceInterface extends KubeObjectInterface {
spec: MySpec;
status?: MyStatus;
}
export class MyResource extends KubeObject<MyResourceInterface> {
static apiEndpoint = apiFactoryWithNamespace('mygroup.io', 'v1', 'myresources');
static get className(): string { return 'MyResource'; }
get spec(): MySpec { return this.jsonData.spec; }
get status(): MyStatus | undefined { return this.jsonData.status; }
}
```
---
## Plugin Entry Point Pattern
```typescript
// 1. Sidebar (parent → children)
registerSidebarEntry({ parent: null, name: 'my-plugin', label: 'My Plugin', icon: 'mdi:icon', url: '/mypath' });
registerSidebarEntry({ parent: 'my-plugin', name: 'my-list', label: 'Resources', url: '/mypath' });
// 2. Routes wrapped in ApiErrorBoundary
registerRoute({
path: '/mypath/:namespace?/:name?',
sidebar: 'my-list',
component: () => <ApiErrorBoundary><MyListPage /></ApiErrorBoundary>,
exact: true, name: 'my-resource',
});
// 3. Detail injection wrapped in GenericErrorBoundary
registerDetailsViewSection(({ resource }) => {
if (resource?.kind !== 'Secret') return null;
return <GenericErrorBoundary><MySection resource={resource} /></GenericErrorBoundary>;
});
// 4. Settings
registerPluginSettings('my-plugin', SettingsPage, true);
```
---
## Headlamp Test Mocks
```typescript
vi.mock('@kinvolk/headlamp-plugin/lib', () => ({
ApiProxy: { request: vi.fn().mockResolvedValue({}) },
K8s: { ResourceClasses: {}, cluster: { KubeObject: class {} } },
}));
vi.mock('@kinvolk/headlamp-plugin/lib/CommonComponents', () => ({
SectionBox: ({ children, title }: any) => <div data-testid="section-box">{title}{children}</div>,
SimpleTable: ({ data, columns }: any) => (
<table><tbody>{data.map((d: any, i: number) =>
<tr key={i}>{columns.map((c: any, j: number) => <td key={j}>{c.getter(d)}</td>)}</tr>
)}</tbody></table>
),
NameValueTable: ({ rows }: any) => (
<dl>{rows.filter((r: any) => !r.hide).map((r: any) =>
<div key={r.name}><dt>{r.name}</dt><dd>{r.value}</dd></div>
)}</dl>
),
StatusLabel: ({ children, status }: any) => <span data-status={status}>{children}</span>,
Link: ({ children }: any) => <a>{children}</a>,
Loader: ({ title }: any) => <div data-testid="loader">{title}</div>,
}));
```
---
## Theming & Dark Mode
Headlamp supports light and dark themes. **Never hardcode colors.** Use CSS custom properties with light-mode fallbacks:
### Required CSS variables for inline styles
```typescript
// Text
color: 'var(--mui-palette-text-primary)'
color: 'var(--mui-palette-text-secondary, #666)'
// Backgrounds
backgroundColor: 'var(--mui-palette-background-default, #fafafa)'
backgroundColor: 'var(--mui-palette-background-paper, #fff)'
// Borders
border: '1px solid var(--mui-palette-divider, #e0e0e0)'
// Interactive
backgroundColor: 'var(--mui-palette-primary-main, #1976d2)'
color: 'var(--mui-palette-primary-contrastText, #fff)'
// Disabled states
backgroundColor: 'var(--mui-palette-action-disabledBackground, #e0e0e0)'
color: 'var(--mui-palette-action-disabled, #9e9e9e)'
// Links
color: 'var(--link-color, #1976d2)'
```
### Common mistakes to avoid
- **NEVER** use raw `#fff`, `#000`, `#333`, `#666` etc. without wrapping in `var(--mui-palette-*)`
- **NEVER** use `rgba(0,0,0,0.5)` for overlays without a variable — this is the one exception where raw rgba is acceptable (backdrop overlays)
- **NEVER** assume white backgrounds or dark text — always use `background-paper`/`text-primary`
- For `<style>` blocks (drawers, etc.), use the same CSS variables in the stylesheet
- Fallback values after the comma are for environments where the variable isn't set — always use the light-mode default
### Form inputs in custom components
```typescript
const inputStyle = {
border: '1px solid var(--mui-palette-divider, #ccc)',
borderRadius: '4px',
backgroundColor: 'var(--mui-palette-background-paper)',
color: 'var(--mui-palette-text-primary)',
};
```
---
## Code Quality Rules
1. **Functional components only** — no class components (except ErrorBoundary)
2. **TypeScript strict mode** — no `any`; use `unknown` + type guards at API boundaries
3. **Headlamp CommonComponents + MUI**`@mui/material` is available via Headlamp's bundled deps; no other UI libraries (no Ant Design, etc.)
4. **Inline CSS only**`style={{}}` props, CSS variables (`var(--mui-palette-*)`) for theming
5. **Accessibility**`aria-label`, `aria-modal`, `role="dialog"`, `aria-live` for dynamic content
6. **Cancellation safety** — async effects must check a `cancelled` flag
7. **Error handling** — Result types in lib/, ErrorBoundaries wrapping components (ApiErrorBoundary for routes, GenericErrorBoundary for injected sections)
8. **Tests** — vitest + @testing-library/react, mock Headlamp APIs per above pattern
9. Run `npm run tsc` and `npm test` after implementation changes
+1 -1
View File
@@ -47,7 +47,7 @@ jobs:
git config user.email "github-actions[bot]@users.noreply.github.com" git config user.email "github-actions[bot]@users.noreply.github.com"
- name: Update version in package.json - name: Update version in package.json
run: npm version ${{ inputs.version }} --no-git-tag-version run: npm version ${{ inputs.version }} --no-git-tag-version --allow-same-version
- name: Update artifacthub-pkg.yml - name: Update artifacthub-pkg.yml
run: | run: |
+18 -1
View File
@@ -6,6 +6,22 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased] ## [Unreleased]
## [0.2.21] - 2026-03-04
### Added
- Claude Code agent definitions for Headlamp plugin development assistance
### Fixed
- Hardcoded color in SealingKeysView now uses CSS variable for dark mode support
- Missing async cancellation in SealedSecretDetail useEffect
- Accessibility gaps: added aria-labels to detail panel buttons and dialogs
- Replaced `any` types with proper typed row interfaces in SimpleTable getters
- Corrected broken links, stale versions, and dead references across documentation
- Fixed LICENSE and README links in README.md
- Fixed appVersion mismatch in artifacthub-pkg.yml
- Removed dead documentation links from docs/README.md
## [0.2.4] - 2026-02-12 ## [0.2.4] - 2026-02-12
### Fixed ### Fixed
@@ -110,7 +126,8 @@ Version 0.2.3 was published but with checksum mismatch on Artifact Hub. Supersed
- Dependencies: node-forge for cryptography - Dependencies: node-forge for cryptography
- Compatible with Headlamp v0.13.0+ - Compatible with Headlamp v0.13.0+
[Unreleased]: https://github.com/privilegedescalation/headlamp-sealed-secrets-plugin/compare/v0.2.4...HEAD [Unreleased]: https://github.com/privilegedescalation/headlamp-sealed-secrets-plugin/compare/v0.2.21...HEAD
[0.2.21]: https://github.com/privilegedescalation/headlamp-sealed-secrets-plugin/compare/v0.2.20...v0.2.21
[0.1.0]: https://github.com/privilegedescalation/headlamp-sealed-secrets-plugin/releases/tag/v0.1.0 [0.1.0]: https://github.com/privilegedescalation/headlamp-sealed-secrets-plugin/releases/tag/v0.1.0
[0.2.4]: https://github.com/privilegedescalation/headlamp-sealed-secrets-plugin/releases/tag/v0.2.4 [0.2.4]: https://github.com/privilegedescalation/headlamp-sealed-secrets-plugin/releases/tag/v0.2.4
[0.2.3]: https://github.com/privilegedescalation/headlamp-sealed-secrets-plugin/releases/tag/v0.2.3 [0.2.3]: https://github.com/privilegedescalation/headlamp-sealed-secrets-plugin/releases/tag/v0.2.3
+1 -1
View File
@@ -68,7 +68,7 @@ Uses custom hooks (`hooks/`) and a utility library (`lib/`) instead of a single
- Functional React components only — no class components - Functional React components only — no class components
- All imports from `@kinvolk/headlamp-plugin/lib` and `@kinvolk/headlamp-plugin/lib/CommonComponents` - All imports from `@kinvolk/headlamp-plugin/lib` and `@kinvolk/headlamp-plugin/lib/CommonComponents`
- No additional UI libraries (no MUI direct imports, no Ant Design, etc.) - MUI (`@mui/material`) is available via Headlamp's bundled dependencies no other UI libraries (no Ant Design, etc.)
- TypeScript strict mode — no `any`, use `unknown` + type guards at API boundaries - TypeScript strict mode — no `any`, use `unknown` + type guards at API boundaries
- Tests: vitest + @testing-library/react, mock with `vi.mock('@kinvolk/headlamp-plugin/lib', ...)` - Tests: vitest + @testing-library/react, mock with `vi.mock('@kinvolk/headlamp-plugin/lib', ...)`
- `vitest.setup.ts` provides a spec-compliant `localStorage` shim for Node 22+ compatibility - `vitest.setup.ts` provides a spec-compliant `localStorage` shim for Node 22+ compatibility
+19 -24
View File
@@ -4,7 +4,7 @@
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
[![GitHub release](https://img.shields.io/github/v/release/privilegedescalation/headlamp-sealed-secrets-plugin)](https://github.com/privilegedescalation/headlamp-sealed-secrets-plugin/releases) [![GitHub release](https://img.shields.io/github/v/release/privilegedescalation/headlamp-sealed-secrets-plugin)](https://github.com/privilegedescalation/headlamp-sealed-secrets-plugin/releases)
[![GitHub issues](https://img.shields.io/github/issues/privilegedescalation/headlamp-sealed-secrets-plugin)](https://github.com/privilegedescalation/headlamp-sealed-secrets-plugin/issues) [![GitHub issues](https://img.shields.io/github/issues/privilegedescalation/headlamp-sealed-secrets-plugin)](https://github.com/privilegedescalation/headlamp-sealed-secrets-plugin/issues)
[![Test Coverage](https://img.shields.io/badge/coverage-92%25-brightgreen)](headlamp-sealed-secrets/) [![Test Coverage](https://img.shields.io/badge/coverage-92%25-brightgreen)](docs/development/testing.md)
[![TypeScript](https://img.shields.io/badge/TypeScript-5.6.2-blue)](https://www.typescriptlang.org/) [![TypeScript](https://img.shields.io/badge/TypeScript-5.6.2-blue)](https://www.typescriptlang.org/)
A comprehensive [Headlamp](https://headlamp.dev) plugin for managing [Bitnami Sealed Secrets](https://github.com/bitnami-labs/sealed-secrets) with **client-side encryption** and **RBAC-aware UI**. A comprehensive [Headlamp](https://headlamp.dev) plugin for managing [Bitnami Sealed Secrets](https://github.com/bitnami-labs/sealed-secrets) with **client-side encryption** and **RBAC-aware UI**.
@@ -31,21 +31,23 @@ Browse the Headlamp Plugin Manager (Settings → Plugins → Catalog) and instal
#### Option 2: Manual Tarball Install #### Option 2: Manual Tarball Install
```bash Download the latest tarball from the [Releases page](https://github.com/privilegedescalation/headlamp-sealed-secrets-plugin/releases), then extract it into your Headlamp plugins directory:
# 1. Download and extract plugin
curl -LO https://github.com/privilegedescalation/headlamp-sealed-secrets-plugin/releases/download/v0.2.4/headlamp-sealed-secrets-0.2.4.tar.gz
tar -xzf headlamp-sealed-secrets-0.2.4.tar.gz -C ~/Library/Application\ Support/Headlamp/plugins/
# 2. Restart Headlamp ```bash
# macOS: Cmd+Q then reopen # macOS
# Linux: killall headlamp && headlamp tar -xzf sealed-secrets-*.tar.gz -C ~/Library/Application\ Support/Headlamp/plugins/
# Linux
tar -xzf sealed-secrets-*.tar.gz -C ~/.config/Headlamp/plugins/
# Restart Headlamp after installing
``` ```
#### Option 3: Build from Source #### Option 3: Build from Source
```bash ```bash
git clone https://github.com/privilegedescalation/headlamp-sealed-secrets-plugin.git git clone https://github.com/privilegedescalation/headlamp-sealed-secrets-plugin.git
cd headlamp-sealed-secrets-plugin/headlamp-sealed-secrets cd headlamp-sealed-secrets-plugin
npm install npm install
npm run build npm run build
npx @kinvolk/headlamp-plugin extract . /headlamp/plugins npx @kinvolk/headlamp-plugin extract . /headlamp/plugins
@@ -76,15 +78,11 @@ kubectl get secret <your-secret-name> -n <namespace>
- **[Quick Start Tutorial](docs/getting-started/quick-start.md)** - Create your first sealed secret - **[Quick Start Tutorial](docs/getting-started/quick-start.md)** - Create your first sealed secret
### User Guides ### User Guides
- **[Creating Secrets](docs/user-guide/creating-secrets.md)** - Encrypt and create sealed secrets
- **[Managing Keys](docs/user-guide/managing-keys.md)** - View and download sealing certificates
- **[Scopes Explained](docs/user-guide/scopes-explained.md)** - Strict vs namespace-wide vs cluster-wide - **[Scopes Explained](docs/user-guide/scopes-explained.md)** - Strict vs namespace-wide vs cluster-wide
- **[RBAC Permissions](docs/user-guide/rbac-permissions.md)** - Configure access control - **[RBAC Permissions](docs/user-guide/rbac-permissions.md)** - Configure access control
### Tutorials ### Tutorials
- **[CI/CD Integration](docs/tutorials/ci-cd-integration.md)** - GitHub Actions, GitLab CI, Jenkins - **[CI/CD Integration](docs/tutorials/ci-cd-integration.md)** - GitHub Actions, GitLab CI, Jenkins
- **[Multi-Cluster Setup](docs/tutorials/multi-cluster-setup.md)** - Manage secrets across clusters
- **[Secret Rotation](docs/tutorials/secret-rotation.md)** - Rotate secrets and sealing keys safely
### Reference ### Reference
- **[Troubleshooting](docs/troubleshooting/)** - Common issues and solutions - **[Troubleshooting](docs/troubleshooting/)** - Common issues and solutions
@@ -181,7 +179,7 @@ Plaintext values never leave your browser.
| Browser XSS | Headlamp CSP policies | ⚠️ Standard web security | | Browser XSS | Headlamp CSP policies | ⚠️ Standard web security |
| Supply chain | Package locks, dependabot | ⚠️ Ongoing monitoring | | Supply chain | Package locks, dependabot | ⚠️ Ongoing monitoring |
See: [Security Hardening Guide](docs/deployment/security-hardening.md) | [ADR 003: Client-Side Encryption](docs/architecture/adr/003-client-side-crypto.md) See: [ADR 003: Client-Side Encryption](docs/architecture/adr/003-client-side-crypto.md)
## Technical Details ## Technical Details
@@ -189,11 +187,8 @@ See: [Security Hardening Guide](docs/deployment/security-hardening.md) | [ADR 00
| Metric | Value | Notes | | Metric | Value | Notes |
|--------|-------|-------| |--------|-------|-------|
| **Bundle Size** | 359.73 kB (98.79 kB gzipped) | Optimized with tree-shaking | | **Test Coverage** | 92% | Unit + integration tests |
| **Test Coverage** | 92% (36/39 passing) | Unit + integration tests |
| **TypeScript** | 5.6.2 strict mode | Zero type errors | | **TypeScript** | 5.6.2 strict mode | Zero type errors |
| **Lines of Code** | 4,767 TypeScript/React | Well-documented with JSDoc |
| **Build Time** | ~4 seconds | Fast development iteration |
| **Dependencies** | node-forge (crypto) | Minimal, audited dependencies | | **Dependencies** | node-forge (crypto) | Minimal, audited dependencies |
### Technology Stack ### Technology Stack
@@ -223,7 +218,7 @@ We welcome contributions.
```bash ```bash
# 1. Fork and clone # 1. Fork and clone
git clone https://github.com/YOUR_USERNAME/headlamp-sealed-secrets-plugin git clone https://github.com/YOUR_USERNAME/headlamp-sealed-secrets-plugin
cd headlamp-sealed-secrets-plugin/headlamp-sealed-secrets cd headlamp-sealed-secrets-plugin
# 2. Install dependencies # 2. Install dependencies
npm install npm install
@@ -265,7 +260,7 @@ See: [Development Workflow](docs/development/workflow.md) | [Testing Guide](docs
See [CHANGELOG.md](CHANGELOG.md) for version history. See [CHANGELOG.md](CHANGELOG.md) for version history.
**Latest release (v0.2.4)**: Type-safe error handling, RBAC integration, accessibility improvements, and 92% test coverage. See [CHANGELOG.md](CHANGELOG.md) for details on each release.
## Issues & Support ## Issues & Support
@@ -292,13 +287,13 @@ See [CHANGELOG.md](CHANGELOG.md) for version history.
| Issue | Quick Fix | Guide | | Issue | Quick Fix | Guide |
|-------|-----------|-------| |-------|-----------|-------|
| Plugin not loading | Check installation path | [Installation](docs/getting-started/installation.md) | | Plugin not loading | Check installation path | [Installation](docs/getting-started/installation.md) |
| Controller not found | Install controller | [Controller Issues](docs/troubleshooting/controller-issues.md) | | Controller not found | Install controller | [Troubleshooting](docs/troubleshooting/) |
| Permission denied | Configure RBAC | [Permission Errors](docs/troubleshooting/permission-errors.md) | | Permission denied | Configure RBAC | [RBAC Permissions](docs/user-guide/rbac-permissions.md) |
| Encryption fails | Check certificate | [Encryption Failures](docs/troubleshooting/encryption-failures.md) | | Encryption fails | Check certificate | [Troubleshooting](docs/troubleshooting/) |
## License ## License
Apache License 2.0 - see [LICENSE](headlamp-sealed-secrets/LICENSE) for details. Apache License 2.0 - see [LICENSE](LICENSE) for details.
## Credits ## Credits
+5 -6
View File
@@ -1,13 +1,13 @@
# Artifact Hub package metadata file # Artifact Hub package metadata file
# https://github.com/artifacthub/hub/blob/master/docs/metadata/artifacthub-pkg.yml # https://github.com/artifacthub/hub/blob/master/docs/metadata/artifacthub-pkg.yml
version: "0.2.19" version: "0.2.21"
name: sealed-secrets name: sealed-secrets
displayName: Sealed Secrets displayName: Sealed Secrets
createdAt: "2026-02-12T00:00:00Z" createdAt: "2026-02-12T00:00:00Z"
description: A comprehensive Headlamp plugin for managing Bitnami Sealed Secrets with client-side encryption and RBAC-aware UI description: A comprehensive Headlamp plugin for managing Bitnami Sealed Secrets with client-side encryption and RBAC-aware UI
license: Apache-2.0 license: Apache-2.0
homeURL: https://github.com/privilegedescalation/headlamp-sealed-secrets-plugin homeURL: https://github.com/privilegedescalation/headlamp-sealed-secrets-plugin
appVersion: 0.2.18 appVersion: 0.2.21
containersImages: containersImages:
- name: sealed-secrets-controller - name: sealed-secrets-controller
image: docker.io/bitnami/sealed-secrets-controller:v0.24.0 image: docker.io/bitnami/sealed-secrets-controller:v0.24.0
@@ -19,8 +19,7 @@ keywords:
- encryption - encryption
- security - security
annotations: annotations:
headlamp/plugin/archive-url: "https://github.com/privilegedescalation/headlamp-sealed-secrets-plugin/releases/download/v0.2.19/sealed-secrets-0.2.19.tar.gz" headlamp/plugin/archive-url: "https://github.com/privilegedescalation/headlamp-sealed-secrets-plugin/releases/download/v0.2.21/sealed-secrets-0.2.21.tar.gz"
headlamp/plugin/archive-checksum: sha256:75a72b0162ed6b38215f1c1a3cca2f8a076947b503e1b5d59c55b6fe3079ee8d
headlamp/plugin/version-compat: ">=0.13.0" headlamp/plugin/version-compat: ">=0.13.0"
headlamp/plugin/distro-compat: "desktop,in-cluster,web,docker-desktop" headlamp/plugin/distro-compat: "desktop,in-cluster,web,docker-desktop"
links: links:
@@ -51,7 +50,7 @@ install: |
#### Option 2: Build from Source #### Option 2: Build from Source
```bash ```bash
git clone https://github.com/privilegedescalation/headlamp-sealed-secrets-plugin git clone https://github.com/privilegedescalation/headlamp-sealed-secrets-plugin
cd headlamp-sealed-secrets-plugin/headlamp-sealed-secrets cd headlamp-sealed-secrets-plugin
npm install npm install
npm run build npm run build
``` ```
@@ -69,7 +68,7 @@ install: |
- Manage sealing keys - Manage sealing keys
- Configure controller settings - Configure controller settings
For detailed usage instructions, see the [README](https://github.com/privilegedescalation/headlamp-sealed-secrets-plugin/blob/main/headlamp-sealed-secrets/README.md). For detailed usage instructions, see the [README](https://github.com/privilegedescalation/headlamp-sealed-secrets-plugin/blob/main/README.md).
maintainers: maintainers:
- name: privilegedescalation - name: privilegedescalation
email: privilegedescalation@users.noreply.github.com email: privilegedescalation@users.noreply.github.com
+4 -117
View File
@@ -2,158 +2,45 @@
Complete documentation for the Headlamp Sealed Secrets plugin. Complete documentation for the Headlamp Sealed Secrets plugin.
## 📚 Documentation Index ## Documentation Index
### Getting Started ### Getting Started
New to the plugin? Start here:
- **[Installation Guide](getting-started/installation.md)** - Install the plugin on Headlamp - **[Installation Guide](getting-started/installation.md)** - Install the plugin on Headlamp
- **[Quick Start](getting-started/quick-start.md)** - Create your first sealed secret in 5 minutes - **[Quick Start](getting-started/quick-start.md)** - Create your first sealed secret in 5 minutes
### User Guide ### User Guide
Learn how to use all the features:
- **[Creating Secrets](user-guide/creating-secrets.md)** - Encrypt and create sealed secrets
- **[Managing Keys](user-guide/managing-keys.md)** - View and download sealing certificates
- **[Scopes Explained](user-guide/scopes-explained.md)** - Understand strict/namespace/cluster-wide scopes - **[Scopes Explained](user-guide/scopes-explained.md)** - Understand strict/namespace/cluster-wide scopes
- **[RBAC Permissions](user-guide/rbac-permissions.md)** - Required permissions and access control - **[RBAC Permissions](user-guide/rbac-permissions.md)** - Required permissions and access control
- **[Settings](user-guide/settings.md)** - Configure plugin behavior
### Tutorials ### Tutorials
Step-by-step guides for common workflows:
- **[CI/CD Integration](tutorials/ci-cd-integration.md)** - Automate secret creation with GitHub Actions, GitLab CI - **[CI/CD Integration](tutorials/ci-cd-integration.md)** - Automate secret creation with GitHub Actions, GitLab CI
- **[Multi-Cluster Setup](tutorials/multi-cluster-setup.md)** - Manage secrets across multiple clusters
- **[Secret Rotation](tutorials/secret-rotation.md)** - Rotate secrets and sealing keys safely
- **[Disaster Recovery](tutorials/disaster-recovery.md)** - Backup and restore procedures
- **[Migration from kubeseal](tutorials/migration-from-kubeseal.md)** - Migrate from CLI-based workflow
### Troubleshooting ### Troubleshooting
Solutions for common issues:
- **[Common Errors](troubleshooting/common-errors.md)** - Error messages and fixes - **[Common Errors](troubleshooting/common-errors.md)** - Error messages and fixes
- **[Controller Issues](troubleshooting/controller-issues.md)** - Connection and deployment problems - **[Controller Issues](troubleshooting/controller-issues.md)** - Connection and deployment problems
- **[Encryption Failures](troubleshooting/encryption-failures.md)** - Debugging encryption errors - **[Encryption Failures](troubleshooting/encryption-failures.md)** - Debugging encryption errors
- **[Permission Errors](troubleshooting/permission-errors.md)** - RBAC troubleshooting - **[Permission Errors](troubleshooting/permission-errors.md)** - RBAC troubleshooting
- **[Performance](troubleshooting/performance.md)** - Optimization tips
### Development ### Development
Contributing to the plugin:
- **[Setup](development/setup.md)** - Development environment configuration
- **[Workflow](development/workflow.md)** - Development and testing workflow - **[Workflow](development/workflow.md)** - Development and testing workflow
- **[Testing](development/testing.md)** - Running and writing tests - **[Testing](development/testing.md)** - Running and writing tests
- **[Code Style](development/code-style.md)** - Coding standards
- **[Debugging](development/debugging.md)** - Debugging tips and tools
- **[Release Process](development/release-process.md)** - How to release new versions
### API Reference
Technical documentation:
- **[Functions](api-reference/functions.md)** - Exported function reference
- **[Types](api-reference/types.md)** - TypeScript type definitions
- **[Hooks](api-reference/hooks.md)** - React hooks API
- **[Components](api-reference/components.md)** - Component props reference
- **[Examples](api-reference/examples.md)** - Code examples and patterns
### Architecture ### Architecture
Technical design and decisions:
- **[Overview](architecture/overview.md)** - System architecture
- **[Encryption Flow](architecture/encryption-flow.md)** - How encryption works
- **[Type System](architecture/type-system.md)** - Result types and branded types explained
- **[Error Handling](architecture/error-handling.md)** - Error handling patterns
- **[Accessibility](architecture/accessibility.md)** - WCAG 2.1 AA compliance details
- **[ADRs](architecture/adr/)** - Architecture Decision Records - **[ADRs](architecture/adr/)** - Architecture Decision Records
### Deployment ### API Reference
Production deployment guides: - **[Generated API Docs](api-reference/generated/)** - Auto-generated TypeScript reference
- **[Kubernetes](deployment/kubernetes.md)** - Deploy in K8s clusters ## External Resources
- **[Helm](deployment/helm.md)** - Using with Helm deployments
- **[Security Hardening](deployment/security-hardening.md)** - Security best practices
- **[Monitoring](deployment/monitoring.md)** - Observability setup
## 🔍 Quick Links
### Popular Pages
- [Quick Start Guide](getting-started/quick-start.md) - Get started in 5 minutes
- [CI/CD Integration](tutorials/ci-cd-integration.md) - Automate your workflow
- [Troubleshooting](troubleshooting/README.md) - Solve common issues
- [Development Workflow](development/workflow.md) - Contribute to the plugin
### External Resources
- **GitHub**: [privilegedescalation/headlamp-sealed-secrets-plugin](https://github.com/privilegedescalation/headlamp-sealed-secrets-plugin) - **GitHub**: [privilegedescalation/headlamp-sealed-secrets-plugin](https://github.com/privilegedescalation/headlamp-sealed-secrets-plugin)
- **Issues**: [Report bugs](https://github.com/privilegedescalation/headlamp-sealed-secrets-plugin/issues) - **Issues**: [Report bugs](https://github.com/privilegedescalation/headlamp-sealed-secrets-plugin/issues)
- **Discussions**: [Ask questions](https://github.com/privilegedescalation/headlamp-sealed-secrets-plugin/discussions)
- **Headlamp**: [headlamp.dev](https://headlamp.dev) - **Headlamp**: [headlamp.dev](https://headlamp.dev)
- **Sealed Secrets**: [bitnami-labs/sealed-secrets](https://github.com/bitnami-labs/sealed-secrets) - **Sealed Secrets**: [bitnami-labs/sealed-secrets](https://github.com/bitnami-labs/sealed-secrets)
## 📖 About This Documentation
This documentation is organized by user journey:
- **Getting Started** - For new users
- **User Guide** - For daily usage
- **Tutorials** - For specific workflows
- **Troubleshooting** - For problem-solving
- **Development** - For contributors
- **API Reference** - For developers using the plugin
- **Architecture** - For understanding the design
- **Deployment** - For production deployments
## 🤝 Contributing to Docs
Found an error or want to improve the documentation?
1. **Quick fixes**: Edit on GitHub and submit a PR
2. **Larger changes**: Open an issue first to discuss
3. **New tutorials**: Share your use case in Discussions
See [CONTRIBUTING.md](../CONTRIBUTING.md) for guidelines.
## 📝 Documentation Status
### Completed ✅
- Installation guides
- Quick start tutorial
- Development workflow documentation
- Testing guides
- Architecture overview
### In Progress 🚧
- User guide sections (creating secrets, managing keys, scopes)
- Tutorial content (CI/CD, multi-cluster, rotation)
- Troubleshooting guides
- API reference (auto-generated coming soon)
### Planned 📅
- Video tutorials
- Interactive examples
- Detailed architecture diagrams
- More CI/CD platform examples
- Advanced use cases
## 🔄 Documentation Updates
This documentation is kept in sync with code changes:
- **Version**: Matches plugin version (currently v0.2.0)
- **Auto-generated**: API reference generated from TypeScript source
- **CI Checks**: Links validated on every pull request
- **Examples Tested**: Code examples validated against current API
Last updated: 2026-02-12
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "sealed-secrets", "name": "sealed-secrets",
"version": "0.2.19", "version": "0.2.21",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "sealed-secrets", "name": "sealed-secrets",
"version": "0.2.19", "version": "0.2.21",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"node-forge": "^1.3.1" "node-forge": "^1.3.1"
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "sealed-secrets", "name": "sealed-secrets",
"version": "0.2.19", "version": "0.2.21",
"description": "Headlamp plugin for Bitnami Sealed Secrets - manage encrypted Kubernetes secrets", "description": "Headlamp plugin for Bitnami Sealed Secrets - manage encrypted Kubernetes secrets",
"files": [ "files": [
"dist", "dist",
+15 -9
View File
@@ -69,9 +69,15 @@ export function SealedSecretDetail() {
// Check if user can decrypt secrets (requires get permission on Secrets) // Check if user can decrypt secrets (requires get permission on Secrets)
React.useEffect(() => { React.useEffect(() => {
let cancelled = false;
if (namespace) { if (namespace) {
canDecryptSecrets(namespace).then(setCanDecrypt); canDecryptSecrets(namespace).then((result) => {
if (!cancelled) setCanDecrypt(result);
});
} }
return () => {
cancelled = true;
};
}, [namespace]); }, [namespace]);
// Wait for required params before rendering // Wait for required params before rendering
@@ -154,7 +160,7 @@ export function SealedSecretDetail() {
title={ title={
<Box display="flex" alignItems="center" justifyContent="space-between"> <Box display="flex" alignItems="center" justifyContent="space-between">
<Box display="flex" alignItems="center" gap={1}> <Box display="flex" alignItems="center" gap={1}>
<IconButton onClick={handleClose} edge="start" size="small"> <IconButton onClick={handleClose} edge="start" size="small" aria-label="Close detail panel">
<Icon icon="mdi:close" /> <Icon icon="mdi:close" />
</IconButton> </IconButton>
<span>{sealedSecret.metadata.name}</span> <span>{sealedSecret.metadata.name}</span>
@@ -233,24 +239,24 @@ export function SealedSecretDetail() {
columns={[ columns={[
{ {
label: 'Key', label: 'Key',
getter: (row: any) => row.key, getter: (row: { key: string; value: string }) => row.key,
}, },
{ {
label: 'Encrypted Value', label: 'Encrypted Value',
getter: (row: any) => { getter: (row: { key: string; value: string }) => {
const val = row.value; const val = row.value;
return val.length > 40 ? val.substring(0, 40) + '...' : val; return val.length > 40 ? val.substring(0, 40) + '...' : val;
}, },
}, },
{ {
label: 'Actions', label: 'Actions',
getter: (row: any) => getter: (row: { key: string; value: string }) =>
canDecrypt ? ( canDecrypt ? (
<Button size="small" onClick={() => setDecryptKey(row.key)}> <Button size="small" onClick={() => setDecryptKey(row.key)} aria-label={`Decrypt ${row.key}`}>
Decrypt Decrypt
</Button> </Button>
) : ( ) : (
<Button size="small" disabled title="No permission to access Secrets"> <Button size="small" disabled title="No permission to access Secrets" aria-label={`Decrypt ${row.key} (no permission)`}>
Decrypt Decrypt
</Button> </Button>
), ),
@@ -331,8 +337,8 @@ export function SealedSecretDetail() {
/> />
)} )}
<Dialog open={deleteDialogOpen} onClose={() => setDeleteDialogOpen(false)}> <Dialog open={deleteDialogOpen} onClose={() => setDeleteDialogOpen(false)} aria-labelledby="delete-dialog-title">
<DialogTitle>Delete SealedSecret?</DialogTitle> <DialogTitle id="delete-dialog-title">Delete SealedSecret?</DialogTitle>
<DialogContent> <DialogContent>
Are you sure you want to delete the SealedSecret <strong>{name}</strong>? This will also Are you sure you want to delete the SealedSecret <strong>{name}</strong>? This will also
delete the resulting Kubernetes Secret. delete the resulting Kubernetes Secret.
+1 -1
View File
@@ -189,7 +189,7 @@ export function SealingKeysView() {
return ( return (
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}> <Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
<span>{expiryDate}</span> <span>{expiryDate}</span>
<span style={{ color: '#666', fontSize: '0.9em' }}> <span style={{ color: 'var(--mui-palette-text-secondary, #666)', fontSize: '0.9em' }}>
({certInfo.daysUntilExpiry} days) ({certInfo.daysUntilExpiry} days)
</span> </span>
</Box> </Box>