diff --git a/README.md b/README.md index 27e7d84..ca347e0 100644 --- a/README.md +++ b/README.md @@ -172,21 +172,28 @@ Every proxied request is recorded in Kubernetes API audit logs as a `get` on `se ## Documentation -Comprehensive documentation is available in the `docs/` directory: +πŸ“š **[Complete Documentation](docs/README.md)** - Documentation hub with all guides -| Document | Description | -| ------------------------------------------------- | --------------------------------------------------------------------- | -| **[ARCHITECTURE.md](docs/ARCHITECTURE.md)** | System architecture, data flow, component hierarchy, design decisions | -| **[DEPLOYMENT.md](docs/DEPLOYMENT.md)** | Complete deployment guide with Helm, FluxCD, RBAC, network policies | -| **[SECURITY.md](SECURITY.md)** | Security model, RBAC requirements, vulnerability reporting | -| **[TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md)** | Common issues, debugging, RBAC testing, network debugging | -| **[TESTING.md](docs/TESTING.md)** | Unit tests, E2E tests, CI/CD, best practices | -| **[CONTRIBUTING.md](CONTRIBUTING.md)** | Development workflow, branching strategy, PR process | -| **[CHANGELOG.md](CHANGELOG.md)** | Complete release history (v0.0.1 to current) | +### Quick Links + +- **[Quick Start](docs/getting-started/quick-start.md)** - Get up and running in 5 minutes +- **[Installation Guide](docs/getting-started/installation.md)** - All installation methods (Plugin Manager, Sidecar, Manual, Source) +- **[Troubleshooting](docs/troubleshooting/README.md)** - Quick diagnosis and common issues + +### Comprehensive Guides + +| Guide | Description | +|-------|-------------| +| **[Architecture](docs/architecture/overview.md)** | System architecture, data flow, component hierarchy, design decisions | +| **[Deployment](docs/deployment/helm.md)** | Production deployment with Helm, Kubernetes, FluxCD | +| **[Security](SECURITY.md)** | Security model, RBAC requirements, vulnerability reporting | +| **[Testing](docs/development/testing.md)** | Unit tests, E2E tests, CI/CD, best practices | +| **[Contributing](CONTRIBUTING.md)** | Development workflow, branching strategy, PR process | +| **[Changelog](CHANGELOG.md)** | Complete release history (v0.0.1 to current) | ## Troubleshooting -**For comprehensive troubleshooting, see [docs/TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md).** +**For comprehensive troubleshooting, see [docs/troubleshooting/README.md](docs/troubleshooting/README.md).** Quick reference: diff --git a/docs/DOCUMENTATION_STANDARDIZATION_PLAN.md b/docs/DOCUMENTATION_STANDARDIZATION_PLAN.md new file mode 100644 index 0000000..fd3a057 --- /dev/null +++ b/docs/DOCUMENTATION_STANDARDIZATION_PLAN.md @@ -0,0 +1,544 @@ +# Documentation Standardization Plan + +**Date**: 2026-02-12 +**Repositories**: headlamp-polaris-plugin, headlamp-sealed-secrets-plugin +**Goal**: Establish consistent documentation standards across Headlamp plugin projects + +## Executive Summary + +This plan standardizes documentation structure, formatting, and content across two Headlamp plugins to create a consistent, professional documentation experience. The standardization adopts the best practices from both repositories while maintaining each plugin's unique technical content. + +## Current State Analysis + +### Polaris Plugin (v0.3.5) +**Structure**: Topic-focused with monolithic files +**Strengths**: +- Comprehensive CONTRIBUTING.md with branching strategy and commit conventions +- Complete CHANGELOG.md (35 versions documented) +- Dedicated SECURITY.md with vulnerability reporting +- JSDoc comments on all API exports +- CI/CD badges in README +- Well-organized TROUBLESHOOTING.md with common issues + +**Gaps**: +- No user journey-based organization +- No Architecture Decision Records +- Limited quick-start tutorials +- No FAQ section +- Deployment guide is monolithic (needs breakdown) + +### Sealed Secrets Plugin +**Structure**: User journey-based with granular topic files +**Strengths**: +- Excellent user journey organization (Getting Started β†’ User Guide β†’ Tutorials) +- Architecture Decision Records (5 ADRs) +- Quick diagnosis flowchart in troubleshooting +- Multi-platform installation guides +- Auto-generated API reference +- Visual hierarchy with strategic emoji use + +**Gaps**: +- No dedicated CONTRIBUTING.md (content in README) +- No SECURITY.md for vulnerability reporting +- Incomplete tutorial placeholders +- No comprehensive CHANGELOG +- Missing E2E testing documentation + +## Standardization Principles + +### 1. File Structure Standard + +**Root-Level Files** (Common to Both): +``` +README.md # Main entry point with badges, quick links +CHANGELOG.md # Keep a Changelog format, semantic versioning +CONTRIBUTING.md # Development workflow, branching, PR process +SECURITY.md # Security model, vulnerability reporting, RBAC +LICENSE # MIT License +package.json # Plugin metadata +``` + +**Documentation Directory** (Organized by User Journey): +``` +docs/ +β”œβ”€β”€ README.md # Documentation hub with quick links +β”œβ”€β”€ getting-started/ +β”‚ β”œβ”€β”€ installation.md +β”‚ β”œβ”€β”€ prerequisites.md +β”‚ └── quick-start.md +β”œβ”€β”€ user-guide/ +β”‚ β”œβ”€β”€ features.md +β”‚ β”œβ”€β”€ configuration.md +β”‚ └── rbac-permissions.md +β”œβ”€β”€ tutorials/ +β”‚ └── (plugin-specific) +β”œβ”€β”€ troubleshooting/ +β”‚ β”œβ”€β”€ README.md (quick diagnosis) +β”‚ └── common-issues.md +β”œβ”€β”€ architecture/ +β”‚ β”œβ”€β”€ overview.md +β”‚ β”œβ”€β”€ data-flow.md +β”‚ β”œβ”€β”€ design-decisions.md +β”‚ └── adr/ (Architecture Decision Records) +β”œβ”€β”€ development/ +β”‚ β”œβ”€β”€ workflow.md +β”‚ β”œβ”€β”€ testing.md +β”‚ β”œβ”€β”€ code-style.md +β”‚ └── release-process.md +└── deployment/ + β”œβ”€β”€ kubernetes.md + β”œβ”€β”€ helm.md + └── production.md +``` + +### 2. README.md Standard + +**Required Sections** (Order Matters): +1. Title + Badges (ArtifactHub, CI, E2E, License) +2. Quick navigation links (πŸ“š Documentation | πŸš€ Installation | πŸ”’ Security | πŸ› οΈ Development) +3. **What It Does** (features with visual hierarchy) +4. **Prerequisites** (table format) +5. **Installing** (4 options: Plugin Manager, Sidecar, Manual, Source) +6. **RBAC / Security Setup** (minimal manifests) +7. **Documentation** (table linking to docs/) +8. **Troubleshooting** (quick reference table + link to full guide) +9. **Development** (quick start commands + link to CONTRIBUTING.md) +10. **Known Limitations** (if applicable) +11. **Releasing** (brief + link to development/release-process.md) +12. **Contributing** (link to CONTRIBUTING.md) +13. **Links** (GitHub, ArtifactHub, Headlamp, related tools) +14. **License** (MIT with link) +15. Footer ("Made with ❀️ for the Kubernetes community") + +**Formatting Standards**: +- Use emojis strategically for visual scanning (not excessive) +- Quick navigation at top +- Tables for structured data (prerequisites, troubleshooting quick ref) +- Code blocks with language hints +- Keep main README under 400 lines (details go in docs/) + +### 3. CHANGELOG.md Standard + +**Format**: Keep a Changelog (https://keepachangelog.com/) + +**Structure**: +```markdown +# Changelog + +All notable changes will be documented in this file. + +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). + +## [Unreleased] + +## [X.Y.Z] - YYYY-MM-DD + +### Added +- New features + +### Changed +- Changes to existing functionality + +### Deprecated +- Soon-to-be removed features + +### Removed +- Removed features + +### Fixed +- Bug fixes + +### Security +- Security fixes + +[Unreleased]: https://github.com/user/repo/compare/vX.Y.Z...HEAD +[X.Y.Z]: https://github.com/user/repo/releases/tag/vX.Y.Z +``` + +**Standards**: +- One entry per version, newest first +- Date in ISO 8601 format (YYYY-MM-DD) +- Link to GitHub release +- Group changes by type (Added, Changed, Fixed, Security) +- Keep descriptions concise (1-2 lines per item) + +### 4. CONTRIBUTING.md Standard + +**Required Sections**: +1. Code of Conduct (brief, respectful) +2. Getting Started (prerequisites, setup) +3. Development Workflow (feature development, testing) +4. Branching Strategy (feat/, fix/, docs/, chore/) +5. Commit Message Guidelines (Conventional Commits) +6. Pull Request Process (before creating, creating, review) +7. Code Style (TypeScript, React, linting, formatting) +8. Testing Requirements (unit, E2E, coverage goals) +9. Documentation (when to update docs) +10. Release Process (version numbering, creating releases) + +**Formatting**: +- Use tables for branch naming conventions +- Code blocks for commit message examples +- Checklists for PR requirements +- Links to detailed guides in docs/development/ + +### 5. SECURITY.md Standard + +**Required Sections**: +1. Overview (security model, read-only vs. write operations) +2. Data Flow Diagram (how data moves through system) +3. RBAC Requirements (minimal permissions table) +4. Network Security (NetworkPolicies, TLS) +5. Authentication Methods (service account, OIDC) +6. Vulnerability Reporting (supported versions table, how to report) +7. Dependency Security (scanning, update process) +8. Deployment Security (production checklist) +9. Common Security Scenarios (FAQs with solutions) +10. Compliance Considerations (audit trail, GDPR/privacy) + +**Formatting**: +- Tables for permissions and supported versions +- YAML examples for RBAC manifests +- Bash commands for security verification +- Clear "Do NOT" warnings for unsafe practices + +### 6. Documentation Hub (docs/README.md) Standard + +**Purpose**: Central navigation for all documentation + +**Structure**: +```markdown +# Documentation + +Central hub for [Plugin Name] documentation. + +## Quick Links + +- πŸš€ [Quick Start](getting-started/quick-start.md) +- πŸ“– [User Guide](user-guide/README.md) +- πŸ”§ [Troubleshooting](troubleshooting/README.md) +- πŸ—οΈ [Architecture](architecture/overview.md) +- πŸ’» [Development](development/workflow.md) + +## Getting Started +Description + links to installation, prerequisites, quick-start + +## User Guide +Description + links to features, configuration, RBAC + +## Tutorials +Description + links to plugin-specific tutorials + +## Troubleshooting +Description + link to quick diagnosis + common issues + +## Architecture +Description + links to overview, data flow, ADRs + +## Development +Description + links to workflow, testing, code style, release + +## Deployment +Description + links to Kubernetes, Helm, production + +## API Reference +Link to JSDoc or generated API docs +``` + +**Formatting**: +- Emojis for visual scanning +- Brief descriptions (1-2 sentences) for each section +- Organized by user journey (beginner β†’ advanced) + +### 7. Architecture Decision Records (ADR) Standard + +**When to Create ADRs**: +- Significant architectural choices +- Technology selection (libraries, patterns) +- Security or performance trade-offs +- Design patterns that impact maintainability + +**Template** (Based on Michael Nygard's ADR): +```markdown +# ADR-NNN: Title + +**Status**: [Proposed | Accepted | Deprecated | Superseded by ADR-XXX] +**Date**: YYYY-MM-DD +**Deciders**: [List key decision makers] + +## Context + +What is the issue that we're seeing that is motivating this decision or change? + +## Decision + +What is the change that we're proposing and/or doing? + +## Consequences + +What becomes easier or more difficult to do because of this change? + +### Positive +- ... + +### Negative +- ... + +### Neutral +- ... + +## Alternatives Considered + +### Option 1: Name +**Pros**: ... +**Cons**: ... +**Decision**: Not chosen because... + +## References + +- [Link to related issues, docs, discussions] +``` + +**Numbering**: ADR-001, ADR-002, etc. (zero-padded 3 digits) + +**Index File** (architecture/adr/README.md): +```markdown +# Architecture Decision Records + +| ADR | Title | Status | Date | +|-----|-------|--------|------| +| [001](001-title.md) | Title | Accepted | 2026-01-01 | +``` + +### 8. Troubleshooting Standard + +**Structure**: + +**troubleshooting/README.md** (Quick Diagnosis): +```markdown +# Troubleshooting + +Quick diagnosis guide for common issues. + +## Quick Reference + +| Symptom | Likely Cause | Quick Fix | +|---------|-------------|-----------| +| ... | ... | ... | + +## Detailed Guides + +- [Common Errors](common-errors.md) +- [RBAC Issues](rbac-issues.md) +- [Network Problems](network-problems.md) +``` + +**Individual Issue Files**: +- Symptom-based organization +- Step-by-step resolution +- Bash commands for verification +- Links to related docs +- "Still Having Issues?" section with bug report link + +### 9. Testing Documentation Standard + +**docs/development/testing.md**: + +**Required Sections**: +1. Overview (testing philosophy, types of tests) +2. Unit Testing (framework, running tests, writing tests, examples) +3. E2E Testing (framework, prerequisites, running tests, examples) +4. CI/CD Integration (workflows, required secrets) +5. Test Coverage (goals, generating reports) +6. Best Practices (unit, E2E, general) +7. Debugging (common issues, useful commands) + +**Formatting**: +- Tables for test types and coverage goals +- Code blocks for examples +- Bash commands for running tests +- Links to test files in repository + +### 10. Visual Formatting Standards + +**Emoji Usage** (Strategic, Not Excessive): +- πŸ“š Documentation +- πŸš€ Installation/Quick Start +- πŸ”’ Security +- πŸ› οΈ Development +- βœ… Success/Completed +- ❌ Error/Failed +- ⚠️ Warning/Important +- πŸ”§ Troubleshooting/Fix +- πŸ—οΈ Architecture +- πŸ’» Code/Technical + +**Code Block Languages**: +- `bash` for shell commands +- `yaml` for Kubernetes/Helm manifests +- `typescript` for TypeScript code +- `json` for JSON config +- `diff` for showing changes + +**Tables**: +- Use for structured data (prerequisites, commands, permissions, troubleshooting) +- Keep columns concise +- Left-align text columns, center-align status columns + +**Links**: +- Use descriptive text, not "click here" +- Relative paths within repo (`docs/architecture/overview.md`) +- Absolute URLs for external resources +- Link to specific sections with anchors where helpful + +## Implementation Plan + +### Phase 1: Polaris Plugin Enhancements + +**Priority 1: Granular Documentation Structure** +- [ ] Create docs/README.md (documentation hub) +- [ ] Break down DEPLOYMENT.md: + - [ ] docs/getting-started/installation.md + - [ ] docs/getting-started/prerequisites.md + - [ ] docs/deployment/kubernetes.md + - [ ] docs/deployment/helm.md + - [ ] docs/deployment/production.md +- [ ] Break down ARCHITECTURE.md: + - [ ] docs/architecture/overview.md + - [ ] docs/architecture/data-flow.md + - [ ] docs/architecture/design-decisions.md +- [ ] Move TROUBLESHOOTING.md β†’ docs/troubleshooting/ + - [ ] Create troubleshooting/README.md (quick diagnosis) + - [ ] Break into common-issues.md, rbac-issues.md, etc. +- [ ] Move TESTING.md β†’ docs/development/testing.md + +**Priority 2: Add Missing Content** +- [ ] Create docs/getting-started/quick-start.md (5-minute tutorial) +- [ ] Create docs/user-guide/features.md +- [ ] Create docs/user-guide/configuration.md +- [ ] Create docs/architecture/adr/ directory with ADR template +- [ ] Create FAQ section in troubleshooting + +**Priority 3: Content Refinement** +- [ ] Add multi-platform instructions to installation.md +- [ ] Enhance README.md with better visual hierarchy +- [ ] Add more code examples to user guide +- [ ] Create architecture diagrams (ASCII art or mermaid) + +### Phase 2: Sealed Secrets Plugin Enhancements + +**Priority 1: Root-Level Documentation** +- [ ] Extract CONTRIBUTING.md from README +- [ ] Create SECURITY.md with vulnerability reporting +- [ ] Expand CHANGELOG.md to include all versions +- [ ] Update README.md to match standardized format + +**Priority 2: Complete Incomplete Files** +- [ ] Finish placeholder tutorial files +- [ ] Add E2E testing guide to docs/development/testing.md +- [ ] Expand API reference (ensure generated docs are readable) +- [ ] Add FAQ section + +**Priority 3: Content Refinement** +- [ ] Add CI/CD badges to README +- [ ] Ensure consistent emoji usage +- [ ] Standardize code block languages +- [ ] Add more cross-links between related topics + +### Phase 3: Cross-Repository Standards + +**Documentation Templates** +- [ ] ADR template in both repos +- [ ] Bug report template (GitHub issue template) +- [ ] Feature request template +- [ ] PR template + +**Shared Patterns** +- [ ] Consistent branching strategy docs +- [ ] Identical commit message conventions +- [ ] Same release process documentation +- [ ] Unified code style guidelines + +## Success Metrics + +**Completeness**: +- [ ] All standard files present in both repos +- [ ] No broken links in documentation +- [ ] All code examples tested and functional + +**Consistency**: +- [ ] Same file structure in both repos +- [ ] Same formatting standards applied +- [ ] Same terminology used for common concepts + +**Usability**: +- [ ] New users can get started in < 5 minutes +- [ ] Contributors can find development workflow easily +- [ ] Troubleshooting guides resolve 80%+ of common issues + +**Maintainability**: +- [ ] Documentation updates documented in CHANGELOG +- [ ] ADRs created for all major decisions +- [ ] Test documentation kept in sync with code + +## Maintenance Guidelines + +**When to Update Documentation**: +1. **New Feature**: Add to CHANGELOG, update user guide, add tutorial if complex +2. **Bug Fix**: Add to CHANGELOG, update troubleshooting if user-facing +3. **Architecture Change**: Create ADR, update architecture docs +4. **Breaking Change**: Add to CHANGELOG with migration guide, update SECURITY.md if relevant +5. **New Dependency**: Document in prerequisites, update installation guide +6. **Configuration Change**: Update user guide, add migration notes if needed + +**Documentation Review Checklist**: +- [ ] Spelling and grammar checked +- [ ] Links tested (no 404s) +- [ ] Code examples tested +- [ ] Screenshots/diagrams up to date (if applicable) +- [ ] Cross-references added where relevant +- [ ] CHANGELOG updated +- [ ] Version numbers current + +**Annual Documentation Audit**: +- Review all docs for accuracy (especially version numbers, screenshots) +- Check for outdated information +- Update ADR status if superseded +- Archive obsolete tutorials +- Refresh getting-started for latest best practices + +## Appendix: File Mapping + +### Polaris Plugin Current β†’ Standard + +| Current | Standard Location | +|---------|-------------------| +| README.md | README.md (enhanced) | +| CHANGELOG.md | CHANGELOG.md (no change) | +| CONTRIBUTING.md | CONTRIBUTING.md (no change) | +| SECURITY.md | SECURITY.md (no change) | +| docs/ARCHITECTURE.md | docs/architecture/overview.md + data-flow.md + design-decisions.md | +| docs/DEPLOYMENT.md | docs/getting-started/installation.md + docs/deployment/kubernetes.md + helm.md + production.md | +| docs/TROUBLESHOOTING.md | docs/troubleshooting/README.md + common-issues.md | +| docs/TESTING.md | docs/development/testing.md | +| β€” (new) | docs/README.md | +| β€” (new) | docs/getting-started/quick-start.md | +| β€” (new) | docs/user-guide/features.md | +| β€” (new) | docs/architecture/adr/ | + +### Sealed Secrets Plugin Current β†’ Standard + +| Current | Standard Location | +|---------|-------------------| +| README.md | README.md (extract contributing section) | +| CHANGELOG.md | CHANGELOG.md (expand) | +| β€” (new) | CONTRIBUTING.md (extract from README) | +| β€” (new) | SECURITY.md (new file) | +| docs/* | docs/* (mostly keep, enhance incomplete files) | + +--- + +**Document Version**: 1.0 +**Last Updated**: 2026-02-12 +**Approved By**: [Pending] diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..7bb0805 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,71 @@ +# Documentation + +Central hub for Headlamp Polaris Plugin documentation. + +## Quick Links + +- πŸš€ [Quick Start](getting-started/quick-start.md) +- πŸ“– [Installation Guide](getting-started/installation.md) +- πŸ”§ [Troubleshooting](troubleshooting/README.md) +- πŸ—οΈ [Architecture](architecture/overview.md) +- πŸ’» [Development](development/workflow.md) + +## Getting Started + +New to the Headlamp Polaris Plugin? Start here: + +- **[Prerequisites](getting-started/prerequisites.md)** - System requirements, Headlamp version, Polaris installation +- **[Installation](getting-started/installation.md)** - Four installation methods: Plugin Manager, Sidecar, Manual, Source +- **[Quick Start](getting-started/quick-start.md)** - Get up and running in 5 minutes + +## User Guide + +Learn how to use the plugin: + +- **[Features](user-guide/features.md)** - Overview dashboard, namespace views, inline audits, exemption management +- **[Configuration](user-guide/configuration.md)** - Refresh intervals, dashboard URLs, settings +- **[RBAC Permissions](user-guide/rbac-permissions.md)** - Required permissions, service proxy access, token-auth mode + +## Troubleshooting + +Having issues? Check here: + +- **[Quick Diagnosis](troubleshooting/README.md)** - Quick reference table for common symptoms +- **[Common Issues](troubleshooting/common-issues.md)** - Detailed resolution steps for frequent problems +- **[RBAC Issues](troubleshooting/rbac-issues.md)** - Permission debugging, 403 errors, token-auth +- **[Network Problems](troubleshooting/network-problems.md)** - NetworkPolicies, connectivity, proxy issues + +## Architecture + +Understand how the plugin works: + +- **[Overview](architecture/overview.md)** - High-level architecture, component hierarchy +- **[Data Flow](architecture/data-flow.md)** - How data moves from Polaris to the UI +- **[Design Decisions](architecture/design-decisions.md)** - Key architectural choices and rationale +- **[ADRs](architecture/adr/README.md)** - Architecture Decision Records + +## Development + +Contributing to the plugin: + +- **[Development Workflow](development/workflow.md)** - Setup, building, hot reload +- **[Testing](development/testing.md)** - Unit tests, E2E tests, CI/CD +- **[Code Style](development/code-style.md)** - TypeScript, React, linting, formatting +- **[Release Process](development/release-process.md)** - Versioning, changelog, GitHub Actions + +## Deployment + +Production deployment guides: + +- **[Kubernetes](deployment/kubernetes.md)** - Direct Kubernetes manifest deployment +- **[Helm](deployment/helm.md)** - Helm chart configuration, values +- **[Production Checklist](deployment/production.md)** - RBAC, NetworkPolicies, security, monitoring + +## API Reference + +- **[polaris.ts](../src/api/polaris.ts)** - JSDoc-annotated TypeScript API (data fetching, types, utilities) +- **[PolarisDataContext.tsx](../src/api/PolarisDataContext.tsx)** - React Context provider for shared data + +--- + +**Need help?** Open an issue on [GitHub](https://github.com/cpfarhood/headlamp-polaris-plugin/issues) or check [CONTRIBUTING.md](../CONTRIBUTING.md) for development guidelines. diff --git a/docs/architecture/adr/001-react-context-for-state.md b/docs/architecture/adr/001-react-context-for-state.md new file mode 100644 index 0000000..b53ab2e --- /dev/null +++ b/docs/architecture/adr/001-react-context-for-state.md @@ -0,0 +1,205 @@ +# ADR-001: Use React Context for State Management + +**Status:** Accepted +**Date:** 2026-02-12 +**Deciders:** Plugin maintainers + +## Context + +The Headlamp Polaris Plugin needs to fetch Polaris audit data once and share it across multiple components: +- Dashboard view (cluster overview) +- Namespaces list view +- Namespace detail view (drawer) +- Inline audit sections on resource detail pages +- App bar score badge + +Multiple state management approaches are available: Redux, Zustand, Jotai, Recoil, React Context (built-in), or component props with prop drilling. + +**Constraints:** +- Headlamp plugin environment does not allow adding external dependencies (peer dependencies only) +- Redux, Zustand, Jotai, Recoil are not available in the plugin runtime +- Plugin must work with Headlamp's existing React context (React 17+) +- Bundle size should remain small (<50 KB) + +**Requirements:** +- Share `AuditData` object across all views without duplicate API calls +- Support auto-refresh on user-configurable interval (1-30 minutes) +- Handle loading and error states consistently +- Minimal re-renders (data updates infrequently) + +## Decision + +Use **React Context API** (built-in, no dependencies) for shared state management. + +**Implementation:** +- `PolarisDataProvider` wraps all plugin routes +- `usePolarisDataContext()` hook provides `{ data, loading, error, refresh }` to consumers +- Single fetch shared across all views +- Auto-refresh via `useEffect` + interval timer + +## Consequences + +### Positive + +- βœ… **No additional dependencies** - Plugins cannot add external libraries (Headlamp constraint) +- βœ… **Simple implementation** - Single AuditData object, read-only, no complex mutations +- βœ… **Built into React** - No learning curve, well-documented, stable API +- βœ… **Small bundle impact** - 0 KB additional (built-in feature) +- βœ… **Works with Headlamp** - Compatible with Headlamp's React version and plugin system +- βœ… **TypeScript support** - Full type safety with `React.createContext()` + +### Negative + +- ❌ **Less powerful for complex state** - No built-in middleware, time-travel debugging, or DevTools +- ❌ **Potential for unnecessary re-renders** - All consumers re-render on context update + - **Mitigated by:** Data updates every 5-30 minutes (low frequency), memoization not needed +- ❌ **No built-in async handling** - Must implement loading/error states manually + - **Mitigated by:** Simple `useState` + `useEffect` pattern sufficient + +### Neutral + +- Performance is excellent for this use case (infrequent updates, small consumer count) +- Context providers work well for read-only or mostly-read state +- Standard React pattern, familiar to contributors + +## Alternatives Considered + +### Option 1: Redux + +**Pros:** +- Powerful state management with middleware +- Excellent DevTools for debugging +- Time-travel debugging +- Well-established patterns + +**Cons:** +- Redux is not available as a peer dependency in Headlamp plugins +- Massive overkill for single AuditData object +- Adds significant bundle size (~10-15 KB) +- Requires additional boilerplate (actions, reducers, store) + +**Decision:** Rejected (dependency not available, too heavy) + +### Option 2: Zustand + +**Pros:** +- Lightweight (~1 KB) +- Simple API similar to `useState` +- No provider boilerplate + +**Cons:** +- External peer dependency (not available in plugin runtime) +- Still adds bundle size +- Unnecessary for read-only state + +**Decision:** Rejected (dependency not available) + +### Option 3: Component Props (Prop Drilling) + +**Pros:** +- No dependencies +- Explicit data flow +- TypeScript tracks prop types + +**Cons:** +- Prop drilling through 5+ component layers (index.tsx β†’ route β†’ view β†’ subcomponent) +- Duplicate fetches if not carefully managed +- Refactoring nightmare if component tree changes +- Each route would need its own fetch logic + +**Decision:** Rejected (poor code organization, maintenance burden) + +### Option 4: Global Variable / Module State + +**Pros:** +- Simple to implement +- No React dependencies + +**Cons:** +- No reactivity (components don't re-render on data change) +- No built-in loading/error handling +- Breaks React's declarative model +- Testing difficulties (global mutable state) + +**Decision:** Rejected (not idiomatic React, no reactivity) + +## Implementation Details + +**Context Definition:** +```typescript +interface PolarisDataContextValue { + data: AuditData | null; + loading: boolean; + error: string | null; + refresh: () => void; +} + +const PolarisDataContext = React.createContext(undefined); +``` + +**Provider Implementation:** +```typescript +export function PolarisDataProvider({ children }: { children: React.ReactNode }) { + const [data, setData] = useState(null); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + const [refreshKey, setRefreshKey] = useState(0); + + const refresh = useCallback(() => { + setRefreshKey(k => k + 1); + }, []); + + useEffect(() => { + // Fetch logic here + // Auto-refresh on interval + }, [refreshKey]); + + return ( + + {children} + + ); +} +``` + +**Consumer Hook:** +```typescript +export function usePolarisDataContext() { + const context = useContext(PolarisDataContext); + if (!context) { + throw new Error('usePolarisDataContext must be used within PolarisDataProvider'); + } + return context; +} +``` + +## Validation Criteria + +**Success Metrics:** +- βœ… All views share single fetch (verified via network tab - one request per refresh) +- βœ… No duplicate API calls (verified via Kubernetes audit logs) +- βœ… Auto-refresh works correctly (5-30 minute intervals) +- βœ… Loading states consistent across views +- βœ… Error handling consistent across views +- βœ… Bundle size remains <50 KB (currently ~27 KB) + +**Tested Scenarios:** +- βœ… Initial load with loading spinner +- βœ… Error handling (403, 404, network errors) +- βœ… Manual refresh via button +- βœ… Auto-refresh interval (configurable via settings) +- βœ… Multiple views consuming same data (no duplicate fetches) +- βœ… Navigation between routes (data persists) + +## References + +- [React Context API](https://react.dev/reference/react/useContext) +- [React Context Performance](https://react.dev/reference/react/useContext#optimizing-re-renders-when-passing-objects-and-functions) +- [Headlamp Plugin Constraints](https://headlamp.dev/docs/latest/development/plugins/) +- [Plugin Implementation](../../api/PolarisDataContext.tsx) + +## Revision History + +| Date | Author | Change | +|------|--------|--------| +| 2026-02-12 | Plugin Team | Initial decision | diff --git a/docs/architecture/adr/README.md b/docs/architecture/adr/README.md new file mode 100644 index 0000000..8a07d5b --- /dev/null +++ b/docs/architecture/adr/README.md @@ -0,0 +1,91 @@ +# Architecture Decision Records + +This directory contains Architecture Decision Records (ADRs) for significant architectural choices made in the Headlamp Polaris Plugin. + +## What is an ADR? + +An Architecture Decision Record (ADR) captures an important architectural decision made along with its context and consequences. AD Rs provide historical context for future developers and serve as documentation for why certain approaches were chosen. + +## When to Create an ADR + +Create an ADR when: + +- Making a significant architectural choice (e.g., state management approach) +- Selecting between multiple technology options (e.g., React Context vs. Redux) +- Establishing a pattern that impacts multiple components +- Making a trade-off decision with non-trivial consequences +- Introducing a new dependency or external integration +- Defining security or performance constraints + +## ADR Format + +Each ADR follows this template (based on Michael Nygard's format): + +```markdown +# ADR-NNN: Title + +**Status**: [Proposed | Accepted | Deprecated | Superseded by ADR-XXX] +**Date**: YYYY-MM-DD +**Deciders**: [List key decision makers] + +## Context + +What is the issue that we're seeing that is motivating this decision or change? + +## Decision + +What is the change that we're proposing and/or doing? + +## Consequences + +What becomes easier or more difficult to do because of this change? + +### Positive +- ... + +### Negative +- ... + +### Neutral +- ... + +## Alternatives Considered + +### Option 1: Name +**Pros**: ... +**Cons**: ... +**Decision**: Not chosen because... + +## References + +- [Link to related issues, docs, discussions] +``` + +## ADR Index + +| ADR | Title | Status | Date | +|-----|-------|--------|------| +| [001](001-react-context-for-state.md) | Use React Context for State Management | Accepted | 2026-02-12 | + +**Note:** Additional ADRs documenting other significant decisions (service proxy approach, drawer navigation, MUI import restrictions) can be created following the template above. + +## Creating a New ADR + +1. **Determine the next ADR number** (e.g., if last ADR is 004, new ADR is 005) +2. **Create a new file**: `NNN-short-title.md` (e.g., `005-exemption-management.md`) +3. **Use the template above** and fill in all sections +4. **Add entry to this README** in the ADR Index table +5. **Submit for review** via pull request + +## ADR Lifecycle + +- **Proposed**: ADR is drafted and under discussion +- **Accepted**: Decision has been made and is currently in effect +- **Deprecated**: Decision is no longer recommended but not yet superseded +- **Superseded by ADR-XXX**: Decision has been replaced by a newer ADR + +## References + +- [ADR GitHub Organization](https://adr.github.io/) +- [Michael Nygard's ADR Template](https://github.com/joelparkerhenderson/architecture-decision-record/blob/main/templates/decision-record-template-by-michael-nygard/index.md) +- [ADR Tools](https://github.com/npryce/adr-tools) diff --git a/docs/architecture/data-flow.md b/docs/architecture/data-flow.md new file mode 100644 index 0000000..b2ccc7d --- /dev/null +++ b/docs/architecture/data-flow.md @@ -0,0 +1,393 @@ +# Data Flow + +Detailed data flow sequences for the Headlamp Polaris Plugin. + +## 1. Initial Load + +``` +User loads Headlamp + ↓ +Headlamp loads plugins + ↓ +Plugin registers routes, sidebar, app bar actions + ↓ +User navigates to /polaris + ↓ +DashboardView mounts + ↓ +PolarisDataContext.Provider wraps component + ↓ +usePolarisDataContext() hook triggers fetch + ↓ +ApiProxy.request() β†’ K8s API β†’ Service Proxy β†’ Polaris + ↓ +AuditData returned and cached in Context + ↓ +Components receive data and render +``` + +## 2. Data Refresh + +``` +User clicks "Refresh" button or auto-refresh interval elapses + ↓ +refresh() function called in Context + ↓ +setRefreshKey() increments (forces re-fetch) + ↓ +useEffect dependency triggers new fetch + ↓ +ApiProxy.request() β†’ Polaris Dashboard + ↓ +Context state updated with new data + ↓ +All consuming components re-render automatically +``` + +## 3. Navigation Flow + +``` +User clicks "Polaris" in sidebar + ↓ +Route: /c/main/polaris (DashboardView) + ↓ +Display cluster score, check distribution + ↓ +User clicks "Namespaces" submenu + ↓ +Route: /c/main/polaris/namespaces (NamespacesListView) + ↓ +Display table of namespaces with scores + ↓ +User clicks namespace button in table + ↓ +Drawer opens, URL hash updates (#namespace-name) + ↓ +NamespaceDetailView renders in drawer + ↓ +Display namespace score + resource table +``` + +## 4. Error Handling Flow + +``` +ApiProxy.request() called + ↓ +Fetch fails with HTTP error + ↓ +Error caught in usePolarisData hook + ↓ +Error status code checked (403, 404, 503, etc.) + ↓ +Context-specific error message set: + β€’ 403: RBAC permission denied + β€’ 404/503: Polaris not installed + β€’ Other: Generic network error + ↓ +Error state propagated to consuming components + ↓ +Components render error UI with StatusLabel + ↓ +User sees error message with actionable guidance +``` + +## 5. Service Proxy Request Flow + +``` +Plugin code: ApiProxy.request(path) + ↓ +Headlamp backend proxies request + ↓ +HTTP GET to Kubernetes API server + ↓ +API server authenticates request (service account or user token) + ↓ +API server checks RBAC: + β€’ Verb: get + β€’ Resource: services/proxy + β€’ ResourceName: polaris-dashboard + β€’ Namespace: polaris + ↓ +If authorized: + API server proxies to Polaris service + ↓ +Polaris dashboard returns results.json + ↓ +Response flows back to plugin + ↓ +If denied (403): + RBAC error returned to plugin + ↓ +Plugin displays error with RBAC guidance +``` + +## 6. Settings Persistence Flow + +``` +User navigates to Settings β†’ Plugins β†’ Polaris + ↓ +PolarisSettings component mounts + ↓ +Component reads localStorage: + β€’ polaris-plugin-refresh-interval + β€’ polaris-plugin-dashboard-url + ↓ +Form populated with current values + ↓ +User modifies settings (refresh interval, dashboard URL) + ↓ +User clicks "Save" + ↓ +Settings written to localStorage: + localStorage.setItem('polaris-plugin-refresh-interval', value) + localStorage.setItem('polaris-plugin-dashboard-url', url) + ↓ +Success message displayed + ↓ +Context refreshes data with new interval + ↓ +All plugin views use new settings immediately +``` + +## 7. App Bar Badge Flow + +``` +Headlamp renders app bar + ↓ +Plugin's registerAppBarAction called + ↓ +AppBarScoreBadge component rendered in app bar + ↓ +Component uses usePolarisDataContext() + ↓ +Data fetched from Polaris (shared with views) + ↓ +Score computed: (pass / total) * 100 + ↓ +Badge color determined: + β€’ Green: score β‰₯ 80 + β€’ Yellow: score 50-79 + β€’ Red: score < 50 + ↓ +Badge rendered with score and shield icon + ↓ +User clicks badge + ↓ +Navigate to /polaris (overview page) +``` + +## 8. Inline Audit Section Flow + +``` +User views Deployment/StatefulSet detail page + ↓ +Headlamp calls registered details view sections + ↓ +Plugin's InlineAuditSection component rendered + ↓ +Component receives resource metadata from Headlamp + ↓ +Component uses usePolarisDataContext() + ↓ +Filters audit results by: + β€’ Namespace === resource.namespace + β€’ Kind === resource.kind + β€’ Name === resource.name + ↓ +If matching audit result found: + Extract check counts (pass/warning/danger) + ↓ +Render compact audit section: + β€’ Score badge + β€’ Check counts + β€’ Link to full Polaris report + ↓ +If no match found: + Render "No audit data available" message +``` + +## Data Structures + +### AuditData Schema + +```typescript +interface AuditData { + PolarisOutputVersion: string; // "1.0" + AuditTime: string; // ISO 8601 timestamp + SourceType: string; // "Cluster" + SourceName: string; // Cluster identifier + DisplayName: string; // Human-readable name + ClusterInfo: { + Version: string; // K8s version + Nodes: number; + Pods: number; + Namespaces: number; + Controllers: number; + }; + Results: Result[]; // Array of resource audit results +} + +interface Result { + Name: string; // Resource name + Namespace: string; // Kubernetes namespace + Kind: string; // "Deployment", "StatefulSet", etc. + Results: ResultSet; // Resource-level checks + PodResult?: { + Name: string; + Results: ResultSet; // Pod-level checks + ContainerResults: { + Name: string; + Results: ResultSet; // Container-level checks + }[]; + }; + CreatedTime: string; // ISO 8601 timestamp +} + +type ResultSet = Record; + +interface ResultMessage { + ID: string; // Check ID (e.g., "cpuLimitsMissing") + Message: string; // Human-readable message + Details: string[]; // Additional context + Success: boolean; // true = passed, false = failed + Severity: "ignore" | "warning" | "danger"; + Category: string; // "Security", "Efficiency", etc. +} +``` + +### Result Counts + +```typescript +interface ResultCounts { + total: number; // Total checks performed + pass: number; // Checks that passed (Success: true) + warning: number; // Failed checks with Severity: "warning" + danger: number; // Failed checks with Severity: "danger" + skipped: number; // Failed checks with Severity: "ignore" +} +``` + +## Data Transformations + +### 1. Aggregating Counts + +```typescript +// Input: AuditData.Results[] +// Output: ResultCounts + +function countResults(data: AuditData): ResultCounts { + const counts = { total: 0, pass: 0, warning: 0, danger: 0, skipped: 0 }; + + for (const result of data.Results) { + // Count resource-level checks + countResultSet(result.Results, counts); + + // Count pod-level checks + if (result.PodResult) { + countResultSet(result.PodResult.Results, counts); + + // Count container-level checks + for (const container of result.PodResult.ContainerResults) { + countResultSet(container.Results, counts); + } + } + } + + return counts; +} + +function countResultSet(rs: ResultSet, counts: ResultCounts): void { + for (const key in rs) { + const msg = rs[key]; + counts.total++; + if (msg.Success) { + counts.pass++; + } else if (msg.Severity === 'ignore') { + counts.skipped++; + } else if (msg.Severity === 'warning') { + counts.warning++; + } else if (msg.Severity === 'danger') { + counts.danger++; + } + } +} +``` + +### 2. Computing Score + +```typescript +// Input: ResultCounts +// Output: Score (0-100) + +function computeScore(counts: ResultCounts): number { + if (counts.total === 0) return 0; + return Math.round((counts.pass / counts.total) * 100); +} + +// Examples: +// { total: 100, pass: 90, ... } β†’ 90 +// { total: 100, pass: 50, ... } β†’ 50 +// { total: 0, pass: 0, ... } β†’ 0 +``` + +### 3. Filtering by Namespace + +```typescript +// Input: AuditData, namespace string +// Output: Result[] for that namespace + +function filterResultsByNamespace(data: AuditData, namespace: string): Result[] { + return data.Results.filter(r => r.Namespace === namespace); +} +``` + +### 4. Extracting Namespaces + +```typescript +// Input: AuditData +// Output: Sorted array of unique namespace names + +function getNamespaces(data: AuditData): string[] { + const namespaces = new Set(); + for (const result of data.Results) { + if (result.Namespace) { + namespaces.add(result.Namespace); + } + } + return Array.from(namespaces).sort(); +} +``` + +## Caching Strategy + +**Current Implementation:** +- Data fetched once and stored in React Context +- Shared across all plugin views (no duplicate fetches) +- Cached until manual refresh or auto-refresh interval + +**Cache Invalidation:** +- Manual refresh button click +- Auto-refresh interval elapses +- Settings change (dashboard URL) + +**No Persistence:** +- Data NOT persisted to localStorage +- Each browser session fetches fresh data +- No offline mode + +**Future Enhancement:** +- IndexedDB caching for offline access +- Incremental updates (fetch only changed namespaces) +- Service Worker for background refresh + +## Next Steps + +- **[Architecture Overview](overview.md)** - High-level component hierarchy +- **[Design Decisions](design-decisions.md)** - Key architectural choices +- **[ADRs](adr/README.md)** - Formal Architecture Decision Records + +## References + +- [Polaris API Documentation](https://polaris.docs.fairwinds.com/) +- [React Context API](https://react.dev/reference/react/useContext) +- [Headlamp ApiProxy](https://headlamp.dev/docs/latest/development/api/) diff --git a/docs/architecture/design-decisions.md b/docs/architecture/design-decisions.md new file mode 100644 index 0000000..4ef0528 --- /dev/null +++ b/docs/architecture/design-decisions.md @@ -0,0 +1,263 @@ +# Design Decisions + +Key architectural choices and their rationale for the Headlamp Polaris Plugin. + +## 1. Service Proxy vs. Direct Access + +**Decision:** Use Kubernetes service proxy, not direct ClusterIP access + +**Context:** +- Plugin needs to access Polaris dashboard API +- Two options: Direct ClusterIP access or Kubernetes service proxy +-Headlamp already has K8s API credentials + +**Decision:** +Use service proxy path: `/api/v1/namespaces/polaris/services/polaris-dashboard:80/proxy/results.json` + +**Rationale:** +- Headlamp already has K8s API credentials (service account or user token) +- Service proxy leverages existing RBAC (no new credentials needed) +- Works with Headlamp's token auth and OIDC +- Simpler deployment (no additional network policies for plugin) +- Consistent with Headlamp's architecture (all API calls go through K8s API) + +**Trade-offs:** +- βœ… **Pros:** Simpler RBAC, works with user tokens, no new credentials +- ❌ **Cons:** Longer URL path, requires `services/proxy` permission + +**Alternatives Considered:** +- Direct ClusterIP access β†’ Rejected (requires new credentials, network policies) +- External Polaris URL β†’ Supported as optional feature (custom URL setting) + +## 2. React Context vs. Redux/Zustand + +**Decision:** Use React Context for state management + +**Context:** +- Plugin needs to share Polaris audit data across multiple views +- Options: React Context, Redux, Zustand, or component props + +**Decision:** +Use React Context with `PolarisDataProvider` + +**Rationale:** +1. **Simple state:** Single AuditData object, no complex mutations +2. **Read-only:** No transactions, undo/redo, or optimistic updates +3. **Headlamp constraints:** Cannot add external dependencies (Redux not bundled) +4. **Performance:** Data changes infrequently (5-30 minute refresh interval) + +**Trade-offs:** +- βœ… **Pros:** No dependencies, simple API, built-in React feature +- ❌ **Cons:** All consumers re-render on data change (acceptable for infrequent updates) + +**Alternatives Considered:** +- Redux β†’ Rejected (not available in plugin environment) +- Zustand β†’ Rejected (requires external dependency) +- Component props β†’ Rejected (prop drilling, duplicate fetches) + +## 3. Drawer Navigation vs. Dedicated Routes + +**Decision:** Use drawer for namespace detail, not dedicated route + +**Context:** +- Namespaces list needs drill-down to per-namespace detail +- Options: Dedicated route (`/polaris/ns/:namespace`) or drawer overlay + +**Decision:** +Use drawer with URL hash (`/polaris/namespaces#kube-system`) + +**Rationale:** +- **Better UX:** Drawer overlays table, preserves scroll position and context +- **URL hash:** Preserves navigation state, supports browser back/forward +- **Keyboard shortcuts:** Escape key to close drawer +- **Sidebar limitation:** Headlamp sidebar doesn't support 3-level nesting + +**Trade-offs:** +- βœ… **Pros:** Better UX, preserves context, keyboard navigation +- ❌ **Cons:** Hash-based routing (not "true" route), drawer accessibility considerations + +**Alternatives Considered:** +- Dedicated route β†’ Rejected (loses table context, requires back navigation) +- Modal β†’ Rejected (less natural for drill-down, no URL state) + +## 4. No MUI Direct Imports + +**Decision:** Never import from `@mui/material` or `@mui/icons-material` + +**Context:** +- Plugin needs UI components (buttons, icons, etc.) +- Headlamp uses MUI but doesn't expose full library to plugins + +**Decision:** +Use only Headlamp CommonComponents or HTML elements with inline styles + +**Rationale:** +- Importing MUI causes `createSvgIcon undefined` runtime error +- Headlamp plugin environment provides limited MUI exports +- CommonComponents cover 90% of use cases + +**Implementation:** +- Use `StatusLabel`, `SectionBox`, `SimpleTable` from CommonComponents +- Use standard HTML elements (`