Compare commits
45 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b772209b65 | |||
| f2b0e4c66f | |||
| 4f937efe26 | |||
| d23ccf3a84 | |||
| 13bdb9901a | |||
| f575623b93 | |||
| a46d0e7519 | |||
| 2da1fb3099 | |||
| 28f432f2bf | |||
| 23148bfaff | |||
| ed38df7215 | |||
| 40a4b8accc | |||
| 86f959486a | |||
| c621bd1384 | |||
| e574ea66e2 | |||
| 49bcbe24af | |||
| fdad1a6da2 | |||
| 7bf00593ef | |||
| 1ca90a7570 | |||
| dbc69fb41f | |||
| 24033ca977 | |||
| 0faa50cd9d | |||
| de5feb68a3 | |||
| 42df8dd7cc | |||
| 3796d57d12 | |||
| 88541bd328 | |||
| e884894840 | |||
| 189ae50024 | |||
| e62fba9cc1 | |||
| 062ac72340 | |||
| 515758c829 | |||
| 40c4add01b | |||
| cdc1ce0303 | |||
| dd5a76e348 | |||
| 3b6d7e6b6c | |||
| 0e5ff9b7b7 | |||
| 8fab7828f4 | |||
| 1733eab21b | |||
| 44fe9ab749 | |||
| 0b081246b0 | |||
| 765f081867 | |||
| d4fa1674dc | |||
| 9655514066 | |||
| ece87a9824 | |||
| 5adcca2eb9 |
@@ -0,0 +1,81 @@
|
||||
---
|
||||
name: agent-installer
|
||||
description: Use this agent when the user wants to discover, browse, or install Claude Code agents from the awesome-claude-code-subagents repository.
|
||||
tools: Bash, WebFetch, Read, Write, Glob
|
||||
model: haiku
|
||||
---
|
||||
|
||||
You are an agent installer that helps users browse and install Claude Code agents from the awesome-claude-code-subagents repository on GitHub.
|
||||
|
||||
## Your Capabilities
|
||||
|
||||
You can:
|
||||
1. List all available agent categories
|
||||
2. List agents within a category
|
||||
3. Search for agents by name or description
|
||||
4. Install agents to global (~/.claude/agents/) or local (.claude/agents/) directory
|
||||
5. Show details about a specific agent before installing
|
||||
6. Uninstall agents
|
||||
|
||||
## GitHub API Endpoints
|
||||
|
||||
- Categories list: `https://api.github.com/repos/VoltAgent/awesome-claude-code-subagents/contents/categories`
|
||||
- Agents in category: `https://api.github.com/repos/VoltAgent/awesome-claude-code-subagents/contents/categories/{category-name}`
|
||||
- Raw agent file: `https://raw.githubusercontent.com/VoltAgent/awesome-claude-code-subagents/main/categories/{category-name}/{agent-name}.md`
|
||||
|
||||
## Workflow
|
||||
|
||||
### When user asks to browse or list agents:
|
||||
1. Fetch categories from GitHub API using WebFetch or Bash with curl
|
||||
2. Parse the JSON response to extract directory names
|
||||
3. Present categories in a numbered list
|
||||
4. When user selects a category, fetch and list agents in that category
|
||||
|
||||
### When user wants to install an agent:
|
||||
1. Ask if they want global installation (~/.claude/agents/) or local (.claude/agents/)
|
||||
2. For local: Check if .claude/ directory exists, create .claude/agents/ if needed
|
||||
3. Download the agent .md file from GitHub raw URL
|
||||
4. Save to the appropriate directory
|
||||
5. Confirm successful installation
|
||||
|
||||
### When user wants to search:
|
||||
1. Fetch the README.md which contains all agent listings
|
||||
2. Search for the term in agent names and descriptions
|
||||
3. Present matching results
|
||||
|
||||
## Example Interactions
|
||||
|
||||
**User:** "Show me available agent categories"
|
||||
**You:** Fetch from GitHub API, then present:
|
||||
```
|
||||
Available categories:
|
||||
1. Core Development (11 agents)
|
||||
2. Language Specialists (22 agents)
|
||||
3. Infrastructure (14 agents)
|
||||
...
|
||||
```
|
||||
|
||||
**User:** "Install the python-pro agent"
|
||||
**You:**
|
||||
1. Ask: "Install globally (~/.claude/agents/) or locally (.claude/agents/)?"
|
||||
2. Download from GitHub
|
||||
3. Save to chosen directory
|
||||
4. Confirm: "✓ Installed python-pro.md to ~/.claude/agents/"
|
||||
|
||||
**User:** "Search for typescript"
|
||||
**You:** Search and present matching agents with descriptions
|
||||
|
||||
## Important Notes
|
||||
|
||||
- Always confirm before installing/uninstalling
|
||||
- Show the agent's description before installing if possible
|
||||
- Handle GitHub API rate limits gracefully (60 requests/hour without auth)
|
||||
- Use `curl -s` for silent downloads
|
||||
- Preserve exact file content when downloading (don't modify agent files)
|
||||
|
||||
## Communication Protocol
|
||||
|
||||
- Be concise and helpful
|
||||
- Use checkmarks (✓) for successful operations
|
||||
- Use clear error messages if something fails
|
||||
- Offer next steps after each action
|
||||
@@ -0,0 +1,286 @@
|
||||
---
|
||||
name: agent-organizer
|
||||
description: Use when assembling and optimizing multi-agent teams to execute complex projects that require careful task decomposition, agent capability matching, and workflow coordination.
|
||||
tools: Read, Write, Edit, Glob, Grep
|
||||
model: sonnet
|
||||
---
|
||||
|
||||
You are a senior agent organizer with expertise in assembling and coordinating multi-agent teams. Your focus spans task analysis, agent capability mapping, workflow design, and team optimization with emphasis on selecting the right agents for each task and ensuring efficient collaboration.
|
||||
|
||||
When invoked:
|
||||
1. Query context manager for task requirements and available agents
|
||||
2. Review agent capabilities, performance history, and current workload
|
||||
3. Analyze task complexity, dependencies, and optimization opportunities
|
||||
4. Orchestrate agent teams for maximum efficiency and success
|
||||
|
||||
Agent organization checklist:
|
||||
- Agent selection accuracy > 95% achieved
|
||||
- Task completion rate > 99% maintained
|
||||
- Resource utilization optimal consistently
|
||||
- Response time < 5s ensured
|
||||
- Error recovery automated properly
|
||||
- Cost tracking enabled thoroughly
|
||||
- Performance monitored continuously
|
||||
- Team synergy maximized effectively
|
||||
|
||||
Task decomposition:
|
||||
- Requirement analysis
|
||||
- Subtask identification
|
||||
- Dependency mapping
|
||||
- Complexity assessment
|
||||
- Resource estimation
|
||||
- Timeline planning
|
||||
- Risk evaluation
|
||||
- Success criteria
|
||||
|
||||
Agent capability mapping:
|
||||
- Skill inventory
|
||||
- Performance metrics
|
||||
- Specialization areas
|
||||
- Availability status
|
||||
- Cost factors
|
||||
- Compatibility matrix
|
||||
- Historical success
|
||||
- Workload capacity
|
||||
|
||||
Team assembly:
|
||||
- Optimal composition
|
||||
- Skill coverage
|
||||
- Role assignment
|
||||
- Communication setup
|
||||
- Coordination rules
|
||||
- Backup planning
|
||||
- Resource allocation
|
||||
- Timeline synchronization
|
||||
|
||||
Orchestration patterns:
|
||||
- Sequential execution
|
||||
- Parallel processing
|
||||
- Pipeline patterns
|
||||
- Map-reduce workflows
|
||||
- Event-driven coordination
|
||||
- Hierarchical delegation
|
||||
- Consensus mechanisms
|
||||
- Failover strategies
|
||||
|
||||
Workflow design:
|
||||
- Process modeling
|
||||
- Data flow planning
|
||||
- Control flow design
|
||||
- Error handling paths
|
||||
- Checkpoint definition
|
||||
- Recovery procedures
|
||||
- Monitoring points
|
||||
- Result aggregation
|
||||
|
||||
Agent selection criteria:
|
||||
- Capability matching
|
||||
- Performance history
|
||||
- Cost considerations
|
||||
- Availability checking
|
||||
- Load balancing
|
||||
- Specialization mapping
|
||||
- Compatibility verification
|
||||
- Backup selection
|
||||
|
||||
Dependency management:
|
||||
- Task dependencies
|
||||
- Resource dependencies
|
||||
- Data dependencies
|
||||
- Timing constraints
|
||||
- Priority handling
|
||||
- Conflict resolution
|
||||
- Deadlock prevention
|
||||
- Flow optimization
|
||||
|
||||
Performance optimization:
|
||||
- Bottleneck identification
|
||||
- Load distribution
|
||||
- Parallel execution
|
||||
- Cache utilization
|
||||
- Resource pooling
|
||||
- Latency reduction
|
||||
- Throughput maximization
|
||||
- Cost minimization
|
||||
|
||||
Team dynamics:
|
||||
- Optimal team size
|
||||
- Skill complementarity
|
||||
- Communication overhead
|
||||
- Coordination patterns
|
||||
- Conflict resolution
|
||||
- Progress synchronization
|
||||
- Knowledge sharing
|
||||
- Result integration
|
||||
|
||||
Monitoring & adaptation:
|
||||
- Real-time tracking
|
||||
- Performance metrics
|
||||
- Anomaly detection
|
||||
- Dynamic adjustment
|
||||
- Rebalancing triggers
|
||||
- Failure recovery
|
||||
- Continuous improvement
|
||||
- Learning integration
|
||||
|
||||
## Communication Protocol
|
||||
|
||||
### Organization Context Assessment
|
||||
|
||||
Initialize agent organization by understanding task and team requirements.
|
||||
|
||||
Organization context query:
|
||||
```json
|
||||
{
|
||||
"requesting_agent": "agent-organizer",
|
||||
"request_type": "get_organization_context",
|
||||
"payload": {
|
||||
"query": "Organization context needed: task requirements, available agents, performance constraints, budget limits, and success criteria."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Development Workflow
|
||||
|
||||
Execute agent organization through systematic phases:
|
||||
|
||||
### 1. Task Analysis
|
||||
|
||||
Decompose and understand task requirements.
|
||||
|
||||
Analysis priorities:
|
||||
- Task breakdown
|
||||
- Complexity assessment
|
||||
- Dependency identification
|
||||
- Resource requirements
|
||||
- Timeline constraints
|
||||
- Risk factors
|
||||
- Success metrics
|
||||
- Quality standards
|
||||
|
||||
Task evaluation:
|
||||
- Parse requirements
|
||||
- Identify subtasks
|
||||
- Map dependencies
|
||||
- Estimate complexity
|
||||
- Assess resources
|
||||
- Define milestones
|
||||
- Plan workflow
|
||||
- Set checkpoints
|
||||
|
||||
### 2. Implementation Phase
|
||||
|
||||
Assemble and coordinate agent teams.
|
||||
|
||||
Implementation approach:
|
||||
- Select agents
|
||||
- Assign roles
|
||||
- Setup communication
|
||||
- Configure workflow
|
||||
- Monitor execution
|
||||
- Handle exceptions
|
||||
- Coordinate results
|
||||
- Optimize performance
|
||||
|
||||
Organization patterns:
|
||||
- Capability-based selection
|
||||
- Load-balanced assignment
|
||||
- Redundant coverage
|
||||
- Efficient communication
|
||||
- Clear accountability
|
||||
- Flexible adaptation
|
||||
- Continuous monitoring
|
||||
- Result validation
|
||||
|
||||
Progress tracking:
|
||||
```json
|
||||
{
|
||||
"agent": "agent-organizer",
|
||||
"status": "orchestrating",
|
||||
"progress": {
|
||||
"agents_assigned": 12,
|
||||
"tasks_distributed": 47,
|
||||
"completion_rate": "94%",
|
||||
"avg_response_time": "3.2s"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Orchestration Excellence
|
||||
|
||||
Achieve optimal multi-agent coordination.
|
||||
|
||||
Excellence checklist:
|
||||
- Tasks completed
|
||||
- Performance optimal
|
||||
- Resources efficient
|
||||
- Errors minimal
|
||||
- Adaptation smooth
|
||||
- Results integrated
|
||||
- Learning captured
|
||||
- Value delivered
|
||||
|
||||
Delivery notification:
|
||||
"Agent orchestration completed. Coordinated 12 agents across 47 tasks with 94% first-pass success rate. Average response time 3.2s with 67% resource utilization. Achieved 23% performance improvement through optimal team composition and workflow design."
|
||||
|
||||
Team composition strategies:
|
||||
- Skill diversity
|
||||
- Redundancy planning
|
||||
- Communication efficiency
|
||||
- Workload balance
|
||||
- Cost optimization
|
||||
- Performance history
|
||||
- Compatibility factors
|
||||
- Scalability design
|
||||
|
||||
Workflow optimization:
|
||||
- Parallel execution
|
||||
- Pipeline efficiency
|
||||
- Resource sharing
|
||||
- Cache utilization
|
||||
- Checkpoint optimization
|
||||
- Recovery planning
|
||||
- Monitoring integration
|
||||
- Result synthesis
|
||||
|
||||
Dynamic adaptation:
|
||||
- Performance monitoring
|
||||
- Bottleneck detection
|
||||
- Agent reallocation
|
||||
- Workflow adjustment
|
||||
- Failure recovery
|
||||
- Load rebalancing
|
||||
- Priority shifting
|
||||
- Resource scaling
|
||||
|
||||
Coordination excellence:
|
||||
- Clear communication
|
||||
- Efficient handoffs
|
||||
- Synchronized execution
|
||||
- Conflict prevention
|
||||
- Progress tracking
|
||||
- Result validation
|
||||
- Knowledge transfer
|
||||
- Continuous improvement
|
||||
|
||||
Learning & improvement:
|
||||
- Performance analysis
|
||||
- Pattern recognition
|
||||
- Best practice extraction
|
||||
- Failure analysis
|
||||
- Optimization opportunities
|
||||
- Team effectiveness
|
||||
- Workflow refinement
|
||||
- Knowledge base update
|
||||
|
||||
Integration with other agents:
|
||||
- Collaborate with context-manager on information sharing
|
||||
- Support multi-agent-coordinator on execution
|
||||
- Work with task-distributor on load balancing
|
||||
- Guide workflow-orchestrator on process design
|
||||
- Help performance-monitor on metrics
|
||||
- Assist error-coordinator on recovery
|
||||
- Partner with knowledge-synthesizer on learning
|
||||
- Coordinate with all agents on task execution
|
||||
|
||||
Always prioritize optimal agent selection, efficient coordination, and continuous improvement while orchestrating multi-agent teams that deliver exceptional results through synergistic collaboration.
|
||||
@@ -0,0 +1,286 @@
|
||||
---
|
||||
name: multi-agent-coordinator
|
||||
description: Use when coordinating multiple concurrent agents that need to communicate, share state, synchronize work, and handle distributed failures across a system.
|
||||
tools: Read, Write, Edit, Glob, Grep
|
||||
model: opus
|
||||
---
|
||||
|
||||
You are a senior multi-agent coordinator with expertise in orchestrating complex distributed workflows. Your focus spans inter-agent communication, task dependency management, parallel execution control, and fault tolerance with emphasis on ensuring efficient, reliable coordination across large agent teams.
|
||||
|
||||
When invoked:
|
||||
1. Query context manager for workflow requirements and agent states
|
||||
2. Review communication patterns, dependencies, and resource constraints
|
||||
3. Analyze coordination bottlenecks, deadlock risks, and optimization opportunities
|
||||
4. Implement robust multi-agent coordination strategies
|
||||
|
||||
Multi-agent coordination checklist:
|
||||
- Coordination overhead < 5% maintained
|
||||
- Deadlock prevention 100% ensured
|
||||
- Message delivery guaranteed thoroughly
|
||||
- Scalability to 100+ agents verified
|
||||
- Fault tolerance built-in properly
|
||||
- Monitoring comprehensive continuously
|
||||
- Recovery automated effectively
|
||||
- Performance optimal consistently
|
||||
|
||||
Workflow orchestration:
|
||||
- Process design
|
||||
- Flow control
|
||||
- State management
|
||||
- Checkpoint handling
|
||||
- Rollback procedures
|
||||
- Compensation logic
|
||||
- Event coordination
|
||||
- Result aggregation
|
||||
|
||||
Inter-agent communication:
|
||||
- Protocol design
|
||||
- Message routing
|
||||
- Channel management
|
||||
- Broadcast strategies
|
||||
- Request-reply patterns
|
||||
- Event streaming
|
||||
- Queue management
|
||||
- Backpressure handling
|
||||
|
||||
Dependency management:
|
||||
- Dependency graphs
|
||||
- Topological sorting
|
||||
- Circular detection
|
||||
- Resource locking
|
||||
- Priority scheduling
|
||||
- Constraint solving
|
||||
- Deadlock prevention
|
||||
- Race condition handling
|
||||
|
||||
Coordination patterns:
|
||||
- Master-worker
|
||||
- Peer-to-peer
|
||||
- Hierarchical
|
||||
- Publish-subscribe
|
||||
- Request-reply
|
||||
- Pipeline
|
||||
- Scatter-gather
|
||||
- Consensus-based
|
||||
|
||||
Parallel execution:
|
||||
- Task partitioning
|
||||
- Work distribution
|
||||
- Load balancing
|
||||
- Synchronization points
|
||||
- Barrier coordination
|
||||
- Fork-join patterns
|
||||
- Map-reduce workflows
|
||||
- Result merging
|
||||
|
||||
Communication mechanisms:
|
||||
- Message passing
|
||||
- Shared memory
|
||||
- Event streams
|
||||
- RPC calls
|
||||
- WebSocket connections
|
||||
- REST APIs
|
||||
- GraphQL subscriptions
|
||||
- Queue systems
|
||||
|
||||
Resource coordination:
|
||||
- Resource allocation
|
||||
- Lock management
|
||||
- Semaphore control
|
||||
- Quota enforcement
|
||||
- Priority handling
|
||||
- Fair scheduling
|
||||
- Starvation prevention
|
||||
- Efficiency optimization
|
||||
|
||||
Fault tolerance:
|
||||
- Failure detection
|
||||
- Timeout handling
|
||||
- Retry mechanisms
|
||||
- Circuit breakers
|
||||
- Fallback strategies
|
||||
- State recovery
|
||||
- Checkpoint restoration
|
||||
- Graceful degradation
|
||||
|
||||
Workflow management:
|
||||
- DAG execution
|
||||
- State machines
|
||||
- Saga patterns
|
||||
- Compensation logic
|
||||
- Checkpoint/restart
|
||||
- Dynamic workflows
|
||||
- Conditional branching
|
||||
- Loop handling
|
||||
|
||||
Performance optimization:
|
||||
- Bottleneck analysis
|
||||
- Pipeline optimization
|
||||
- Batch processing
|
||||
- Caching strategies
|
||||
- Connection pooling
|
||||
- Message compression
|
||||
- Latency reduction
|
||||
- Throughput maximization
|
||||
|
||||
## Communication Protocol
|
||||
|
||||
### Coordination Context Assessment
|
||||
|
||||
Initialize multi-agent coordination by understanding workflow needs.
|
||||
|
||||
Coordination context query:
|
||||
```json
|
||||
{
|
||||
"requesting_agent": "multi-agent-coordinator",
|
||||
"request_type": "get_coordination_context",
|
||||
"payload": {
|
||||
"query": "Coordination context needed: workflow complexity, agent count, communication patterns, performance requirements, and fault tolerance needs."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Development Workflow
|
||||
|
||||
Execute multi-agent coordination through systematic phases:
|
||||
|
||||
### 1. Workflow Analysis
|
||||
|
||||
Design efficient coordination strategies.
|
||||
|
||||
Analysis priorities:
|
||||
- Workflow mapping
|
||||
- Agent capabilities
|
||||
- Communication needs
|
||||
- Dependency analysis
|
||||
- Resource requirements
|
||||
- Performance targets
|
||||
- Risk assessment
|
||||
- Optimization opportunities
|
||||
|
||||
Workflow evaluation:
|
||||
- Map processes
|
||||
- Identify dependencies
|
||||
- Analyze communication
|
||||
- Assess parallelism
|
||||
- Plan synchronization
|
||||
- Design recovery
|
||||
- Document patterns
|
||||
- Validate approach
|
||||
|
||||
### 2. Implementation Phase
|
||||
|
||||
Orchestrate complex multi-agent workflows.
|
||||
|
||||
Implementation approach:
|
||||
- Setup communication
|
||||
- Configure workflows
|
||||
- Manage dependencies
|
||||
- Control execution
|
||||
- Monitor progress
|
||||
- Handle failures
|
||||
- Coordinate results
|
||||
- Optimize performance
|
||||
|
||||
Coordination patterns:
|
||||
- Efficient messaging
|
||||
- Clear dependencies
|
||||
- Parallel execution
|
||||
- Fault tolerance
|
||||
- Resource efficiency
|
||||
- Progress tracking
|
||||
- Result validation
|
||||
- Continuous optimization
|
||||
|
||||
Progress tracking:
|
||||
```json
|
||||
{
|
||||
"agent": "multi-agent-coordinator",
|
||||
"status": "coordinating",
|
||||
"progress": {
|
||||
"active_agents": 87,
|
||||
"messages_processed": "234K/min",
|
||||
"workflow_completion": "94%",
|
||||
"coordination_efficiency": "96%"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Coordination Excellence
|
||||
|
||||
Achieve seamless multi-agent collaboration.
|
||||
|
||||
Excellence checklist:
|
||||
- Workflows smooth
|
||||
- Communication efficient
|
||||
- Dependencies resolved
|
||||
- Failures handled
|
||||
- Performance optimal
|
||||
- Scaling proven
|
||||
- Monitoring active
|
||||
- Value delivered
|
||||
|
||||
Delivery notification:
|
||||
"Multi-agent coordination completed. Orchestrated 87 agents processing 234K messages/minute with 94% workflow completion rate. Achieved 96% coordination efficiency with zero deadlocks and 99.9% message delivery guarantee."
|
||||
|
||||
Communication optimization:
|
||||
- Protocol efficiency
|
||||
- Message batching
|
||||
- Compression strategies
|
||||
- Route optimization
|
||||
- Connection pooling
|
||||
- Async patterns
|
||||
- Event streaming
|
||||
- Queue management
|
||||
|
||||
Dependency resolution:
|
||||
- Graph algorithms
|
||||
- Priority scheduling
|
||||
- Resource allocation
|
||||
- Lock optimization
|
||||
- Conflict resolution
|
||||
- Parallel planning
|
||||
- Critical path analysis
|
||||
- Bottleneck removal
|
||||
|
||||
Fault handling:
|
||||
- Failure detection
|
||||
- Isolation strategies
|
||||
- Recovery procedures
|
||||
- State restoration
|
||||
- Compensation execution
|
||||
- Retry policies
|
||||
- Timeout management
|
||||
- Graceful degradation
|
||||
|
||||
Scalability patterns:
|
||||
- Horizontal scaling
|
||||
- Vertical partitioning
|
||||
- Load distribution
|
||||
- Connection management
|
||||
- Resource pooling
|
||||
- Batch optimization
|
||||
- Pipeline design
|
||||
- Cluster coordination
|
||||
|
||||
Performance tuning:
|
||||
- Latency analysis
|
||||
- Throughput optimization
|
||||
- Resource utilization
|
||||
- Cache effectiveness
|
||||
- Network efficiency
|
||||
- CPU optimization
|
||||
- Memory management
|
||||
- I/O optimization
|
||||
|
||||
Integration with other agents:
|
||||
- Collaborate with agent-organizer on team assembly
|
||||
- Support context-manager on state synchronization
|
||||
- Work with workflow-orchestrator on process execution
|
||||
- Guide task-distributor on work allocation
|
||||
- Help performance-monitor on metrics collection
|
||||
- Assist error-coordinator on failure handling
|
||||
- Partner with knowledge-synthesizer on patterns
|
||||
- Coordinate with all agents on communication
|
||||
|
||||
Always prioritize efficiency, reliability, and scalability while coordinating multi-agent systems that deliver exceptional performance through seamless collaboration.
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"enabledMcpjsonServers": [
|
||||
"github",
|
||||
"kubernetes",
|
||||
"flux",
|
||||
"playwright"
|
||||
]
|
||||
}
|
||||
@@ -5,10 +5,11 @@ on:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
lint-and-test:
|
||||
runs-on: ubuntu-latest
|
||||
ci:
|
||||
runs-on: local-ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
|
||||
steps:
|
||||
@@ -18,7 +19,7 @@ jobs:
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
node-version: '22'
|
||||
cache: 'npm'
|
||||
|
||||
- name: Install dependencies
|
||||
@@ -28,13 +29,13 @@ jobs:
|
||||
run: npx @kinvolk/headlamp-plugin build
|
||||
|
||||
- name: Lint
|
||||
run: npx eslint --ext .ts,.tsx src/
|
||||
run: npm run lint
|
||||
|
||||
- name: Type-check
|
||||
run: npx tsc --noEmit
|
||||
run: npm run tsc
|
||||
|
||||
- name: Format check
|
||||
run: npx prettier --check src/
|
||||
run: npm run format:check
|
||||
|
||||
- name: Run unit tests
|
||||
- name: Run tests
|
||||
run: npm test
|
||||
|
||||
@@ -9,7 +9,7 @@ on:
|
||||
|
||||
jobs:
|
||||
e2e:
|
||||
runs-on: k3s-animaniacs
|
||||
runs-on: local-ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
|
||||
steps:
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
- name: Run E2E tests
|
||||
run: npm run e2e
|
||||
env:
|
||||
HEADLAMP_URL: ${{ secrets.HEADLAMP_URL || 'https://headlamp.animaniacs.farh.net' }}
|
||||
HEADLAMP_URL: ${{ secrets.HEADLAMP_URL || 'http://headlamp.kube-system.svc.cluster.local' }}
|
||||
HEADLAMP_TOKEN: ${{ secrets.HEADLAMP_TOKEN }}
|
||||
AUTHENTIK_USERNAME: ${{ secrets.AUTHENTIK_USERNAME }}
|
||||
AUTHENTIK_PASSWORD: ${{ secrets.AUTHENTIK_PASSWORD }}
|
||||
|
||||
+85
-108
@@ -1,129 +1,106 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: 'Release version (e.g. 1.0.0)'
|
||||
required: true
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
concurrency:
|
||||
group: release
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
uses: ./.github/workflows/ci.yaml
|
||||
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
packages: write
|
||||
needs: ci
|
||||
runs-on: local-ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Check if release is already finalized
|
||||
- name: Validate version format
|
||||
run: |
|
||||
VERSION=${GITHUB_REF_NAME#v}
|
||||
TARBALL_URL="https://github.com/${{ github.repository }}/releases/download/${GITHUB_REF_NAME}/polaris-${VERSION}.tar.gz"
|
||||
HTTP_CODE=$(curl -sL -o /tmp/release.tar.gz -w "%{http_code}" "$TARBALL_URL" 2>/dev/null)
|
||||
if [ "$HTTP_CODE" = "200" ]; then
|
||||
ACTUAL="sha256:$(sha256sum /tmp/release.tar.gz | awk '{print $1}')"
|
||||
EXPECTED=$(grep 'archive-checksum' artifacthub-pkg.yml | awk '{print $2}')
|
||||
echo "Release tarball checksum: $ACTUAL"
|
||||
echo "Metadata checksum: $EXPECTED"
|
||||
if [ "$ACTUAL" = "$EXPECTED" ]; then
|
||||
echo "SKIP_BUILD=true" >> $GITHUB_ENV
|
||||
echo "Checksums match - release is finalized, nothing to do"
|
||||
fi
|
||||
else
|
||||
echo "No existing release (HTTP $HTTP_CODE) - will build"
|
||||
fi
|
||||
rm -f /tmp/release.tar.gz
|
||||
|
||||
- name: Setup Node.js
|
||||
if: env.SKIP_BUILD != 'true'
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
|
||||
- name: Install dependencies
|
||||
if: env.SKIP_BUILD != 'true'
|
||||
run: npm ci
|
||||
|
||||
- name: Build plugin
|
||||
if: env.SKIP_BUILD != 'true'
|
||||
run: npx @kinvolk/headlamp-plugin build
|
||||
|
||||
- name: Package tarball
|
||||
if: env.SKIP_BUILD != 'true'
|
||||
run: npx @kinvolk/headlamp-plugin package
|
||||
|
||||
- name: Validate tarball name matches package.json
|
||||
if: env.SKIP_BUILD != 'true'
|
||||
run: |
|
||||
PACKAGE_NAME=$(jq -r '.name' package.json)
|
||||
VERSION=${GITHUB_REF_NAME#v}
|
||||
EXPECTED_TARBALL="${PACKAGE_NAME}-${VERSION}.tar.gz"
|
||||
ACTUAL_TARBALL=$(ls *.tar.gz)
|
||||
|
||||
if [ "$EXPECTED_TARBALL" != "$ACTUAL_TARBALL" ]; then
|
||||
echo "::error::Tarball name mismatch!"
|
||||
echo "Expected: $EXPECTED_TARBALL"
|
||||
echo "Actual: $ACTUAL_TARBALL"
|
||||
echo "Update workflow to use correct tarball name pattern"
|
||||
if [[ ! "${{ inputs.version }}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
echo "Error: Version must be in X.Y.Z format"
|
||||
exit 1
|
||||
fi
|
||||
echo "✓ Tarball name validation passed: $ACTUAL_TARBALL"
|
||||
|
||||
- name: Compute tarball checksum
|
||||
if: env.SKIP_BUILD != 'true'
|
||||
run: |
|
||||
TARBALL=$(ls *.tar.gz)
|
||||
CHECKSUM=$(sha256sum "$TARBALL" | awk '{print $1}')
|
||||
echo "TARBALL=$TARBALL" >> $GITHUB_ENV
|
||||
echo "CHECKSUM=$CHECKSUM" >> $GITHUB_ENV
|
||||
echo "Tarball: $TARBALL"
|
||||
echo "Checksum: sha256:$CHECKSUM"
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Create draft release and upload tarball
|
||||
if: env.SKIP_BUILD != 'true'
|
||||
uses: softprops/action-gh-release@v2
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
files: ${{ env.TARBALL }}
|
||||
fail_on_unmatched_files: true
|
||||
draft: true
|
||||
prerelease: false
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
node-version: '22'
|
||||
cache: 'npm'
|
||||
|
||||
- name: Publish release
|
||||
if: env.SKIP_BUILD != 'true'
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
draft: false
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Update metadata and align tag
|
||||
if: env.SKIP_BUILD != 'true'
|
||||
- name: Configure Git
|
||||
run: |
|
||||
VERSION=${GITHUB_REF_NAME#v}
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
|
||||
# Update metadata
|
||||
git fetch origin main
|
||||
git checkout origin/main -B temp-update
|
||||
- name: Update version in package.json
|
||||
run: npm version ${{ inputs.version }} --no-git-tag-version --allow-same-version
|
||||
|
||||
- name: Update artifacthub-pkg.yml
|
||||
run: |
|
||||
VERSION="${{ inputs.version }}"
|
||||
PKG_NAME=$(jq -r .name package.json)
|
||||
RELEASE_URL="https://github.com/${{ github.repository }}/releases/download/v${VERSION}/${PKG_NAME}-${VERSION}.tar.gz"
|
||||
sed -i "s/^version:.*/version: \"${VERSION}\"/" artifacthub-pkg.yml
|
||||
sed -i "s|headlamp/plugin/archive-url:.*|headlamp/plugin/archive-url: \"${RELEASE_URL}\"|" artifacthub-pkg.yml
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Build plugin
|
||||
run: npx @kinvolk/headlamp-plugin build
|
||||
|
||||
- name: Package plugin
|
||||
run: npx @kinvolk/headlamp-plugin package
|
||||
|
||||
- name: Prepare release tarball
|
||||
run: |
|
||||
VERSION="${{ inputs.version }}"
|
||||
PKG_NAME=$(jq -r .name package.json)
|
||||
TARBALL="${PKG_NAME}-${VERSION}.tar.gz"
|
||||
echo "TARBALL=$TARBALL" >> $GITHUB_ENV
|
||||
echo "PKG_NAME=$PKG_NAME" >> $GITHUB_ENV
|
||||
|
||||
- name: Validate tarball
|
||||
run: |
|
||||
echo "Tarball: ${{ env.TARBALL }}"
|
||||
ls -lh "${{ env.TARBALL }}"
|
||||
tar -tzf "${{ env.TARBALL }}" | head -20
|
||||
tar -tzf "${{ env.TARBALL }}" | grep -q "main.js" || { echo "Error: main.js not found in tarball"; exit 1; }
|
||||
|
||||
- name: Compute checksum
|
||||
run: |
|
||||
CHECKSUM=$(sha256sum "${{ env.TARBALL }}" | awk '{print $1}')
|
||||
echo "CHECKSUM=$CHECKSUM" >> $GITHUB_ENV
|
||||
sed -i "s|headlamp/plugin/archive-checksum:.*|headlamp/plugin/archive-checksum: sha256:${CHECKSUM}|" artifacthub-pkg.yml
|
||||
sed -i "s|headlamp/plugin/archive-url:.*|headlamp/plugin/archive-url: \"https://github.com/${{ github.repository }}/releases/download/${GITHUB_REF_NAME}/polaris-${VERSION}.tar.gz\"|" artifacthub-pkg.yml
|
||||
sed -i "s|^version:.*|version: ${VERSION}|" artifacthub-pkg.yml
|
||||
git add artifacthub-pkg.yml
|
||||
|
||||
if ! git diff --cached --quiet; then
|
||||
git commit -m "ci: update artifact hub metadata for ${GITHUB_REF_NAME}"
|
||||
git push origin temp-update:main
|
||||
fi
|
||||
- name: Commit and tag
|
||||
run: |
|
||||
VERSION="${{ inputs.version }}"
|
||||
git add package.json package-lock.json artifacthub-pkg.yml
|
||||
git commit -m "release: v${VERSION}"
|
||||
git tag "v${VERSION}"
|
||||
git push origin main --tags
|
||||
|
||||
# Force-move tag to the commit with correct checksum.
|
||||
# This triggers a new CI run, but the guard step will detect
|
||||
# that the release checksum already matches and skip the build.
|
||||
git tag -f ${GITHUB_REF_NAME}
|
||||
git push -f origin ${GITHUB_REF_NAME}
|
||||
echo "Tag ${GITHUB_REF_NAME} aligned with updated metadata"
|
||||
- name: Create GitHub Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: "v${{ inputs.version }}"
|
||||
files: ${{ env.TARBALL }}
|
||||
fail_on_unmatched_files: true
|
||||
generate_release_notes: true
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
+1
-1
@@ -1,10 +1,10 @@
|
||||
node_modules/
|
||||
dist/
|
||||
.headlamp-plugin/
|
||||
.mcp.json
|
||||
*.tar.gz
|
||||
e2e/.auth/
|
||||
test-results/
|
||||
.playwright-mcp/
|
||||
.env
|
||||
.env.local
|
||||
.eslintcache
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"mcpServers": {
|
||||
"github": {
|
||||
"type": "http",
|
||||
"url": "https://api.githubcopilot.com/mcp/",
|
||||
"headers": {
|
||||
"Authorization": "Bearer ${GITHUB_TOKEN}"
|
||||
}
|
||||
},
|
||||
"kubernetes": {
|
||||
"type": "sse",
|
||||
"url": "http://localhost:8080/sse"
|
||||
},
|
||||
"flux": {
|
||||
"type": "sse",
|
||||
"url": "http://localhost:8081/sse"
|
||||
},
|
||||
"playwright": {
|
||||
"type": "sse",
|
||||
"url": "http://localhost:8086/sse"
|
||||
}
|
||||
}
|
||||
}
|
||||
+31
-32
@@ -31,7 +31,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- App bar badge, settings buttons, and UI elements now use theme-aware CSS variables
|
||||
|
||||
### Infrastructure
|
||||
- Migrated from Gitea to GitHub Actions exclusively
|
||||
- Added CI workflow for lint, type-check, build, and test
|
||||
- Enhanced E2E testing documentation with comprehensive guides
|
||||
- Added documentation-engineer subagent
|
||||
@@ -243,34 +242,34 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Automated release workflow
|
||||
- Basic CI/CD pipeline
|
||||
|
||||
[Unreleased]: https://github.com/cpfarhood/headlamp-polaris-plugin/compare/v0.3.5...HEAD
|
||||
[0.3.5]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.3.5
|
||||
[0.3.4]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.3.4
|
||||
[0.3.3]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.3.3
|
||||
[0.3.2]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.3.2
|
||||
[0.3.1]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.3.1
|
||||
[0.3.0]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.3.0
|
||||
[0.2.5]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.2.5
|
||||
[0.2.4]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.2.4
|
||||
[0.2.3]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.2.3
|
||||
[0.2.2]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.2.2
|
||||
[0.2.1]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.2.1
|
||||
[0.2.0]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.2.0
|
||||
[0.1.7]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.1.7
|
||||
[0.1.6]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.1.6
|
||||
[0.1.5]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.1.5
|
||||
[0.1.4]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.1.4
|
||||
[0.1.3]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.1.3
|
||||
[0.1.2]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.1.2
|
||||
[0.1.1]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.1.1
|
||||
[0.1.0]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.1.0
|
||||
[0.0.10]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.0.10
|
||||
[0.0.9]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.0.9
|
||||
[0.0.8]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.0.8
|
||||
[0.0.7]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.0.7
|
||||
[0.0.6]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.0.6
|
||||
[0.0.5]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.0.5
|
||||
[0.0.4]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.0.4
|
||||
[0.0.3]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.0.3
|
||||
[0.0.2]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.0.2
|
||||
[0.0.1]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.0.1
|
||||
[Unreleased]: https://github.com/privilegedescalation/headlamp-polaris-plugin/compare/v0.3.5...HEAD
|
||||
[0.3.5]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.3.5
|
||||
[0.3.4]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.3.4
|
||||
[0.3.3]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.3.3
|
||||
[0.3.2]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.3.2
|
||||
[0.3.1]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.3.1
|
||||
[0.3.0]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.3.0
|
||||
[0.2.5]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.2.5
|
||||
[0.2.4]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.2.4
|
||||
[0.2.3]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.2.3
|
||||
[0.2.2]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.2.2
|
||||
[0.2.1]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.2.1
|
||||
[0.2.0]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.2.0
|
||||
[0.1.7]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.1.7
|
||||
[0.1.6]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.1.6
|
||||
[0.1.5]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.1.5
|
||||
[0.1.4]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.1.4
|
||||
[0.1.3]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.1.3
|
||||
[0.1.2]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.1.2
|
||||
[0.1.1]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.1.1
|
||||
[0.1.0]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.1.0
|
||||
[0.0.10]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.0.10
|
||||
[0.0.9]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.0.9
|
||||
[0.0.8]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.0.8
|
||||
[0.0.7]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.0.7
|
||||
[0.0.6]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.0.6
|
||||
[0.0.5]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.0.5
|
||||
[0.0.4]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.0.4
|
||||
[0.0.3]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.0.3
|
||||
[0.0.2]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.0.2
|
||||
[0.0.1]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.0.1
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Project
|
||||
|
||||
Headlamp plugin surfacing Fairwinds Polaris audit results. Queries the Polaris dashboard API via Kubernetes service proxy (`/api/v1/namespaces/polaris/services/polaris-dashboard/proxy/results.json`). Read-only — no cluster write operations except exemption annotation patches.
|
||||
|
||||
- **Plugin name**: `polaris`
|
||||
- **Target**: Headlamp >= v0.26
|
||||
- **Data source**: Polaris dashboard service in `polaris` namespace
|
||||
- **RBAC**: `get` on `services/proxy` resource `polaris-dashboard` in `polaris` namespace
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
npm start # dev server with hot reload
|
||||
npm run build # production build
|
||||
npm run package # package for headlamp
|
||||
npm run tsc # TypeScript type check (no emit)
|
||||
npm run lint # ESLint
|
||||
npm run lint:fix # ESLint with auto-fix
|
||||
npm run format # Prettier write
|
||||
npm run format:check # Prettier check
|
||||
npm test # vitest run
|
||||
npm run test:watch # vitest watch mode
|
||||
npx vitest run src/api/polaris.test.ts # run a single test file
|
||||
npm run e2e # Playwright E2E tests
|
||||
npm run e2e:headed # Playwright headed mode
|
||||
```
|
||||
|
||||
All tests and `tsc` must pass before committing.
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
src/
|
||||
├── index.tsx # Plugin entry: registerRoute, registerSidebarEntry, registerDetailsViewSection, registerAppBarAction, registerPluginSettings
|
||||
├── test-utils.tsx # Shared test utilities
|
||||
├── api/
|
||||
│ ├── polaris.ts # Types (AuditData schema), countResults utilities, refresh settings
|
||||
│ ├── checkMapping.ts # Polaris check ID → human-readable name mapping
|
||||
│ ├── topIssues.ts # Top failing checks aggregation logic
|
||||
│ └── PolarisDataContext.tsx # Shared React context provider (ApiProxy.request + configurable refresh)
|
||||
└── components/
|
||||
├── DashboardView.tsx # Overview page (score gauge, check distribution, top failing checks)
|
||||
├── NamespacesListView.tsx # Namespace list with per-namespace scores
|
||||
├── NamespaceDetailView.tsx # Per-namespace drill-down with resource table
|
||||
├── InlineAuditSection.tsx # Injected into Deployment/StatefulSet/DaemonSet/Job/CronJob detail views
|
||||
├── ExemptionManager.tsx # Polaris exemption annotation management
|
||||
├── AppBarScoreBadge.tsx # App bar cluster score chip
|
||||
└── PolarisSettings.tsx # Plugin settings (refresh interval, dashboard URL)
|
||||
```
|
||||
|
||||
## Data flow
|
||||
|
||||
Data is fetched via `ApiProxy.request` to the Polaris dashboard service proxy and refreshed on a user-configurable interval (stored in localStorage under `polaris-plugin-refresh-interval`, default 5 minutes). Score is computed from result counts (pass/total). `PolarisDataProvider` wraps each route component and detail-section registration in `index.tsx`.
|
||||
|
||||
**Sidebar limitation**: Headlamp's sidebar only supports 2-level nesting (parent → children). Namespace navigation is handled via the in-content table on the Namespaces page instead.
|
||||
|
||||
## Code conventions
|
||||
|
||||
- Functional React components only — no class components
|
||||
- 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.)
|
||||
- TypeScript strict mode — no `any`, use `unknown` + type guards at API boundaries
|
||||
- Context provider (`PolarisDataProvider`) wraps each route component in `index.tsx`
|
||||
- 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
|
||||
|
||||
## Testing
|
||||
|
||||
Mock pattern for headlamp APIs:
|
||||
```typescript
|
||||
vi.mock('@kinvolk/headlamp-plugin/lib', () => ({
|
||||
ApiProxy: { request: vi.fn().mockResolvedValue({}) },
|
||||
K8s: { ResourceClasses: {} },
|
||||
}));
|
||||
```
|
||||
+575
@@ -0,0 +1,575 @@
|
||||
# CONTEXT.md - Headlamp Polaris Plugin
|
||||
|
||||
**Purpose**: Comprehensive reverse prompt for AI assistants working on this project.
|
||||
|
||||
---
|
||||
|
||||
## Project Overview
|
||||
|
||||
The Headlamp Polaris Plugin surfaces [Fairwinds Polaris](https://www.fairwinds.com/polaris) audit results directly inside the [Headlamp](https://headlamp.dev) Kubernetes UI. It provides a read-only dashboard showing cluster-wide security, reliability, and efficiency scores derived from Polaris policy checks.
|
||||
|
||||
- **Stack**: React + TypeScript plugin for Headlamp (v0.26+)
|
||||
- **Data Source**: Polaris dashboard API via Kubernetes service proxy (read-only)
|
||||
- **Current Version**: v0.4.1
|
||||
- **Key Constraint**: No direct Kubernetes resource access - all data fetched through service proxy
|
||||
|
||||
## Architecture & Data Flow
|
||||
|
||||
### Component Hierarchy
|
||||
|
||||
```
|
||||
src/index.tsx # Entry point: registers routes, sidebar, settings
|
||||
├── PolarisDataContext.tsx # Shared data fetch with auto-refresh
|
||||
├── components/
|
||||
│ ├── DashboardView.tsx # Overview (score, checks, top issues)
|
||||
│ ├── NamespacesListView.tsx # Namespace list with scores
|
||||
│ ├── NamespaceDetailView.tsx # Per-namespace drill-down (drawer)
|
||||
│ ├── PolarisSettings.tsx # Settings (refresh interval, URL, test)
|
||||
│ ├── AppBarScoreBadge.tsx # Cluster score badge in top nav
|
||||
│ └── InlineAuditSection.tsx # Injected into workload detail views
|
||||
└── api/
|
||||
└── polaris.ts # Types, hooks, utilities
|
||||
```
|
||||
|
||||
### Data Source
|
||||
|
||||
- **Service Proxy Path**: `/api/v1/namespaces/polaris/services/polaris-dashboard:80/proxy/results.json`
|
||||
- **Schema**: `AuditData` with `ClusterInfo`, `Results[]` containing nested `PodResult` and `ContainerResults`
|
||||
- **Method**: `ApiProxy.request()` from Headlamp plugin SDK (handles K8s API auth automatically)
|
||||
|
||||
### State Management
|
||||
|
||||
- **Pattern**: React Context (see `src/api/PolarisDataContext.tsx`)
|
||||
- **Rationale**: ADR-001 - Prevents duplicate API calls when multiple components need same data
|
||||
- **Auto-refresh**: User-configurable interval (1/5/10/30 min, default 5 min)
|
||||
- **Storage**: Refresh interval and dashboard URL stored in `localStorage`
|
||||
|
||||
### Score Computation
|
||||
|
||||
```typescript
|
||||
// Formula: (pass / total) * 100, rounded to nearest integer
|
||||
function computeScore(counts: ResultCounts): number {
|
||||
if (counts.total === 0) return 0;
|
||||
return Math.round((counts.pass / counts.total) * 100);
|
||||
}
|
||||
```
|
||||
|
||||
## Technology Constraints
|
||||
|
||||
### ⚠️ CRITICAL: Headlamp Components Only
|
||||
|
||||
**MUST** use `@kinvolk/headlamp-plugin/lib/CommonComponents`
|
||||
**NEVER** import from `@mui/material` or `@mui/icons-material`
|
||||
|
||||
**Why**: Historical issue (v0.3.2) - MUI imports caused plugin load failures. Headlamp provides all needed components as re-exports.
|
||||
|
||||
```typescript
|
||||
// ✅ Correct
|
||||
import { SectionBox, StatusLabel } from '@kinvolk/headlamp-plugin/lib/CommonComponents';
|
||||
|
||||
// ❌ Wrong - will break plugin
|
||||
import { Box, Chip } from '@mui/material';
|
||||
```
|
||||
|
||||
### Other Constraints
|
||||
|
||||
- **TypeScript Strictness**: No `any`, explicit types, strict mode enabled
|
||||
- **Packaging**: `@kinvolk/headlamp-plugin` is peer dependency - don't bundle React/MUI
|
||||
- **Theme Handling**: Use CSS variables (`--mui-palette-*`), not theme imports
|
||||
- **Sidebar Limitation**: Headlamp only supports 2-level nesting (parent → children)
|
||||
|
||||
## Component Patterns & Gotchas
|
||||
|
||||
### Headlamp Component Issues
|
||||
|
||||
1. **StatusLabel with empty status**
|
||||
```typescript
|
||||
// ❌ Renders near-invisible (muted background)
|
||||
<StatusLabel status="">{value}</StatusLabel>
|
||||
|
||||
// ✅ Use plain String() for neutral values
|
||||
<span>{String(value)}</span>
|
||||
```
|
||||
|
||||
2. **Link component crashes on plugin routes**
|
||||
```typescript
|
||||
// ❌ Headlamp Link crashes on plugin-registered routes
|
||||
import { Link } from '@kinvolk/headlamp-plugin/lib/CommonComponents';
|
||||
|
||||
// ✅ Use react-router-dom Link with Router.createRouteURL
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Router } from '@kinvolk/headlamp-plugin/lib';
|
||||
|
||||
<Link to={Router.createRouteURL('/polaris/namespaces')}>View</Link>
|
||||
```
|
||||
|
||||
3. **Visual components that work well**
|
||||
- `PercentageCircle` - Great for score display
|
||||
- `PercentageBar` - Great for check distribution
|
||||
- `SimpleTable` - Fast, clean tables
|
||||
- `NameValueTable` - Key-value pairs
|
||||
- `SectionBox` - Card containers with titles
|
||||
|
||||
### Code Conventions
|
||||
|
||||
- **Functional Components**: Always use function components with hooks
|
||||
- **Named Exports**: Prefer named exports over default exports
|
||||
- **Props Interfaces**: Define as TypeScript interfaces, not inline types
|
||||
- **Import Order**: React → third-party → Headlamp → local (auto-sorted by eslint)
|
||||
|
||||
## RBAC & Security
|
||||
|
||||
### Minimal Permission Required
|
||||
|
||||
The plugin requires **only** this RBAC permission:
|
||||
|
||||
| Verb | API Group | Resource | Resource Name | Namespace |
|
||||
|------|-----------|----------|---------------|-----------|
|
||||
| `get` | `""` (core) | `services/proxy` | `polaris-dashboard` | `polaris` |
|
||||
|
||||
### Example Role
|
||||
|
||||
```yaml
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: polaris-proxy-reader
|
||||
namespace: polaris
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["services/proxy"]
|
||||
resourceNames: ["polaris-dashboard"]
|
||||
verbs: ["get"]
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: headlamp-polaris-proxy
|
||||
namespace: polaris
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: headlamp
|
||||
namespace: kube-system
|
||||
roleRef:
|
||||
kind: Role
|
||||
name: polaris-proxy-reader
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
```
|
||||
|
||||
### Security Notes
|
||||
|
||||
- **Namespaced Role**: MUST be namespaced Role, NOT ClusterRole
|
||||
- **ResourceNames Required**: Always specify `resourceNames: ["polaris-dashboard"]`
|
||||
- **No Write Operations**: Plugin only performs GET, never create/update/delete
|
||||
- **Token-Auth Mode**: When Headlamp uses user tokens, each user needs the RoleBinding
|
||||
- **Network Policy**: If enforced, allow API server → `polaris-dashboard:80` ingress
|
||||
- **Audit Logging**: Every proxy request logged as K8s API audit event
|
||||
|
||||
## Development Workflow
|
||||
|
||||
### Commands
|
||||
|
||||
```bash
|
||||
# Install dependencies
|
||||
npm install
|
||||
|
||||
# Start development mode (hot reload at localhost:4466)
|
||||
npm start
|
||||
|
||||
# Build plugin
|
||||
npm run build
|
||||
|
||||
# Create tarball for distribution
|
||||
npm run package
|
||||
|
||||
# Type-check without emitting
|
||||
npm run tsc
|
||||
|
||||
# Lint
|
||||
npm run lint
|
||||
|
||||
# Run unit tests
|
||||
npm test
|
||||
|
||||
# Run E2E tests (requires cluster access)
|
||||
npm run e2e
|
||||
|
||||
# Format code
|
||||
npm run format
|
||||
|
||||
# Check formatting (CI)
|
||||
npm run format:check
|
||||
```
|
||||
|
||||
### Branching Strategy
|
||||
|
||||
- ✅ **ALWAYS use feature branches** for code changes (`feat/*`, `fix/*`, `docs/*`)
|
||||
- ✅ **MAY push directly to main** for: documentation-only changes, version bump commits
|
||||
- ❌ **NEVER push code changes directly to main**
|
||||
|
||||
### Commit Convention
|
||||
|
||||
Use Conventional Commits:
|
||||
- `feat:` - New feature
|
||||
- `fix:` - Bug fix
|
||||
- `docs:` - Documentation only
|
||||
- `chore:` - Maintenance (deps, config)
|
||||
- `test:` - Test changes
|
||||
- `ci:` - CI/CD changes
|
||||
|
||||
### PR Process
|
||||
|
||||
All PRs must pass:
|
||||
1. Build (`npm run build`)
|
||||
2. Lint (`npm run lint`)
|
||||
3. Type-check (`npm run tsc`)
|
||||
4. Unit tests (`npm test`)
|
||||
5. Format check (`npm run format:check`)
|
||||
|
||||
**Before committing**: Always run `npx prettier --write src/`
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
### Unit Tests (Vitest)
|
||||
|
||||
```bash
|
||||
npm test # Run once
|
||||
npm run test:watch # Watch mode
|
||||
```
|
||||
|
||||
- **Framework**: Vitest with jsdom environment
|
||||
- **Test files**: `*.test.ts`, `*.test.tsx` in `src/`
|
||||
- **Setup**: `vitest.setup.ts` with `@testing-library/jest-dom`
|
||||
- **Coverage**: Focus on meaningful tests, not just numbers
|
||||
- **Test utilities**: `src/test-utils.tsx` provides test wrapper with context
|
||||
|
||||
### E2E Tests (Playwright)
|
||||
|
||||
```bash
|
||||
npm run e2e # Headless
|
||||
npm run e2e:headed # With browser UI
|
||||
```
|
||||
|
||||
- **Framework**: Playwright
|
||||
- **Test files**: `e2e/*.spec.ts`
|
||||
- `polaris.spec.ts` - Sidebar, overview, namespaces, detail drawer
|
||||
- `settings.spec.ts` - Plugin settings page
|
||||
- `appbar.spec.ts` - App bar score badge
|
||||
- **Auth**: Supports both OIDC (Authentik) and token-based auth (see `e2e/auth.setup.ts`)
|
||||
- **CI**: Runs on GitHub Actions with `k3s-animaniacs` runner
|
||||
|
||||
### Local E2E Setup
|
||||
|
||||
```bash
|
||||
# Token-based auth
|
||||
export HEADLAMP_TOKEN=$(kubectl create token headlamp -n kube-system --duration=24h)
|
||||
npm run e2e
|
||||
|
||||
# OIDC auth (Authentik)
|
||||
export AUTHENTIK_USERNAME=your-username
|
||||
export AUTHENTIK_PASSWORD=your-password
|
||||
npm run e2e
|
||||
```
|
||||
|
||||
## CI/CD & Release
|
||||
|
||||
### CI Workflow (`.github/workflows/ci.yaml`)
|
||||
|
||||
Runs on push to main and all PRs:
|
||||
1. Checkout
|
||||
2. `npm ci`
|
||||
3. `npm run build`
|
||||
4. `npm run lint`
|
||||
5. `npm run tsc`
|
||||
6. `npm run format:check`
|
||||
7. `npm test`
|
||||
|
||||
Runner: `local-ubuntu-latest`
|
||||
|
||||
### E2E Workflow (`.github/workflows/e2e.yaml`)
|
||||
|
||||
Runs on push, PR, and manual trigger:
|
||||
1. Checkout
|
||||
2. `npm ci`
|
||||
3. `npm run e2e`
|
||||
|
||||
Runner: `k3s-animaniacs` (has cluster access)
|
||||
Requires: `HEADLAMP_URL`, `HEADLAMP_TOKEN` or `AUTHENTIK_USERNAME`/`AUTHENTIK_PASSWORD`
|
||||
|
||||
### Release Workflow (`.github/workflows/release.yaml`)
|
||||
|
||||
**Manual trigger** via workflow_dispatch with version input:
|
||||
|
||||
```bash
|
||||
# Via GitHub UI or CLI
|
||||
gh workflow run release.yaml -f version=0.4.2
|
||||
```
|
||||
|
||||
Steps:
|
||||
1. Validate version format (semver)
|
||||
2. Bump `package.json` + `artifacthub-pkg.yml`
|
||||
3. Build plugin
|
||||
4. Package tarball
|
||||
5. Compute SHA256 checksum
|
||||
6. Commit version bump
|
||||
7. Create git tag
|
||||
8. Create GitHub release
|
||||
9. Upload tarball to release
|
||||
|
||||
**Guard**: Skips if checksum already matches (prevents infinite loop)
|
||||
|
||||
**Post-release**: ArtifactHub pulls metadata every 30 min (no webhook, pull-based)
|
||||
|
||||
### Version Bump Requirements
|
||||
|
||||
**ALWAYS bump both files in the same commit**:
|
||||
- `package.json` - `version` field
|
||||
- `artifacthub-pkg.yml` - `version` field + `digest` (checksum) + `archive.url`
|
||||
|
||||
## Known Issues & Workarounds
|
||||
|
||||
### ⚠️ Headlamp v0.39.0 Known Issues
|
||||
|
||||
**AutoSizer JavaScript Error**
|
||||
- **Symptom**: Console shows `TypeError: undefined is not an object (evaluating 'io.AutoSizer')`
|
||||
- **Impact**: Cosmetic error in Settings page, doesn't break functionality
|
||||
- **Root Cause**: Headlamp core bug, not plugin-related
|
||||
- **Workaround**: None needed, can be ignored
|
||||
|
||||
**Plugin Loading (RESOLVED)**
|
||||
- **Old Issue**: Previously thought `config.watchPlugins: false` was required
|
||||
- **Resolution**: Plugins load correctly with default `watchPlugins: true`
|
||||
- **Note**: If you see old docs mentioning `watchPlugins: false`, ignore them
|
||||
|
||||
### Polaris Dashboard Behavior
|
||||
|
||||
**Stale Audit Data**
|
||||
- **Symptom**: Plugin shows old audit timestamp
|
||||
- **Root Cause**: Polaris dashboard runs audit once at pod startup, then caches results
|
||||
- **Does NOT**: Continuously re-audit in real-time
|
||||
- **Workaround**: Restart Polaris pods for fresh data
|
||||
```bash
|
||||
kubectl rollout restart deployment -n polaris polaris-dashboard
|
||||
```
|
||||
- **Load Balancing**: Service balances across multiple pods - each may have different audit timestamps
|
||||
- **Plugin Auto-Refresh**: Works correctly - just fetches whatever Polaris currently has cached
|
||||
|
||||
### Skipped Count Limitation
|
||||
|
||||
**What It Shows**:
|
||||
- Only checks with `Severity: "ignore"` in Polaris API response
|
||||
- Does NOT include annotation-based exemptions (`polaris.fairwinds.com/*-exempt`)
|
||||
|
||||
**Why**:
|
||||
- Polaris omits exempted checks from `results.json`
|
||||
- Plugin has no access to raw K8s resources to compute exemptions
|
||||
- By design: service proxy limitation
|
||||
|
||||
**Workaround**:
|
||||
- Link to native Polaris dashboard for full exemption count
|
||||
- UI tooltip explains this limitation
|
||||
|
||||
## Deployment Patterns
|
||||
|
||||
### Plugin Manager (Recommended)
|
||||
|
||||
Install via Headlamp UI (Settings → Plugins → Catalog) or Helm values:
|
||||
|
||||
```yaml
|
||||
pluginsManager:
|
||||
enabled: true
|
||||
configContent: |
|
||||
plugins:
|
||||
- name: polaris
|
||||
source: https://artifacthub.io/packages/headlamp/polaris/headlamp-polaris-plugin
|
||||
```
|
||||
|
||||
### Sidecar Container (Alternative)
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
containers:
|
||||
- name: headlamp
|
||||
# ... main container
|
||||
- name: headlamp-plugin
|
||||
image: node:lts-alpine
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- |
|
||||
npx @headlamp-k8s/pluginctl@latest install \
|
||||
--config /config/plugin.yml \
|
||||
--folderName /headlamp/plugins \
|
||||
--watch
|
||||
volumeMounts:
|
||||
- name: plugins-dir
|
||||
mountPath: /headlamp/plugins
|
||||
- name: plugin-config
|
||||
mountPath: /config
|
||||
volumes:
|
||||
- name: plugins-dir
|
||||
emptyDir: {}
|
||||
- name: plugin-config
|
||||
configMap:
|
||||
name: headlamp-plugin-config
|
||||
```
|
||||
|
||||
### Manual Tarball
|
||||
|
||||
```bash
|
||||
# Download release
|
||||
wget https://github.com/cpfarhood/headlamp-polaris-plugin/releases/download/v0.4.1/headlamp-polaris-plugin-0.4.1.tgz
|
||||
|
||||
# Extract to plugin directory
|
||||
tar -xzf headlamp-polaris-plugin-0.4.1.tgz -C /headlamp/plugins/
|
||||
|
||||
# Restart Headlamp
|
||||
kubectl rollout restart deployment headlamp -n kube-system
|
||||
```
|
||||
|
||||
## Project Files Reference
|
||||
|
||||
```
|
||||
src/
|
||||
index.tsx # Entry point: registers sidebar, routes, settings, etc.
|
||||
api/
|
||||
polaris.ts # Core types, usePolarisData hook, utilities
|
||||
PolarisDataContext.tsx # React Context provider for shared data
|
||||
components/
|
||||
DashboardView.tsx # Overview page (score, checks, top issues)
|
||||
NamespacesListView.tsx # Namespace table with scores
|
||||
NamespaceDetailView.tsx # Drawer panel with per-namespace drill-down
|
||||
PolarisSettings.tsx # Settings page (refresh, URL, test)
|
||||
AppBarScoreBadge.tsx # Cluster score chip in top nav bar
|
||||
InlineAuditSection.tsx # Injected into resource detail views
|
||||
test-utils.tsx # Test helpers (wrapper with context)
|
||||
|
||||
.github/workflows/
|
||||
ci.yaml # Lint, type-check, build, test
|
||||
e2e.yaml # Playwright E2E tests
|
||||
release.yaml # Automated releases
|
||||
|
||||
e2e/ # Playwright tests
|
||||
polaris.spec.ts # Main plugin functionality
|
||||
settings.spec.ts # Settings page
|
||||
appbar.spec.ts # App bar badge
|
||||
auth.setup.ts # OIDC/token auth setup
|
||||
|
||||
docs/ # Comprehensive documentation
|
||||
architecture/ # Overview, design decisions, ADRs
|
||||
deployment/ # Helm, Kubernetes, production guides
|
||||
troubleshooting/ # Common issues, RBAC, network problems
|
||||
getting-started/ # Quick start, prerequisites, installation
|
||||
|
||||
package.json # Version, scripts, dependencies
|
||||
artifacthub-pkg.yml # ArtifactHub metadata (version, checksum)
|
||||
tsconfig.json # Extends @kinvolk/headlamp-plugin config
|
||||
vitest.config.mts # Vitest config (jsdom, excludes e2e/)
|
||||
.eslintrc.js # Extends @headlamp-k8s/eslint-config
|
||||
.prettierrc.js # Uses @headlamp-k8s prettier config
|
||||
```
|
||||
|
||||
## MCP Servers (Claude Code)
|
||||
|
||||
- **GitHub**: Source control (`github-mcp-server`), repo at `cpfarhood/headlamp-polaris-plugin`
|
||||
- **Kubernetes (local)**: Cluster access via `kubernetes-mcp-server`
|
||||
- **Flux (local)**: Flux Operator access via `flux-operator-mcp`
|
||||
- **Playwright**: Browser automation via `@playwright/mcp`
|
||||
|
||||
## Common Tasks Quick Reference
|
||||
|
||||
```bash
|
||||
# Start development
|
||||
npm install && npm start
|
||||
|
||||
# Run all checks before PR
|
||||
npm run build && npm run lint && npm run tsc && npm test && npm run format
|
||||
|
||||
# Create release (maintainers only)
|
||||
# 1. Edit CHANGELOG.md
|
||||
# 2. Trigger release workflow:
|
||||
gh workflow run release.yaml -f version=0.4.2
|
||||
|
||||
# Run E2E tests locally
|
||||
export HEADLAMP_TOKEN=$(kubectl create token headlamp -n kube-system --duration=24h)
|
||||
npm run e2e
|
||||
|
||||
# Fix formatting issues
|
||||
npx prettier --write src/
|
||||
|
||||
# Check Polaris audit freshness
|
||||
kubectl get --raw "/api/v1/namespaces/polaris/services/polaris-dashboard:80/proxy/results.json" | jq -r '.AuditTime'
|
||||
|
||||
# Restart Polaris for fresh audit
|
||||
kubectl rollout restart deployment -n polaris polaris-dashboard
|
||||
```
|
||||
|
||||
## Anti-Patterns (What NOT to Do)
|
||||
|
||||
- ❌ Import from `@mui/material` or `@mui/icons-material` → breaks plugin
|
||||
- ❌ Use `any` type → strict TypeScript required
|
||||
- ❌ Push code changes directly to main → always use feature branches
|
||||
- ❌ Grant broader RBAC than `get services/proxy` → security risk
|
||||
- ❌ Use ClusterRole instead of namespaced Role → violates least privilege
|
||||
- ❌ Forget to run `npx prettier --write src/` → CI will fail
|
||||
- ❌ Use inline styles without CSS variables → breaks dark mode
|
||||
- ❌ Try to query K8s resources directly → plugin only has service proxy access
|
||||
- ❌ Import Headlamp `Link` for plugin routes → use react-router-dom `Link` + `Router.createRouteURL()`
|
||||
- ❌ Assume Polaris continuously re-audits → it only audits at pod startup
|
||||
|
||||
## Quick Diagnosis Guide
|
||||
|
||||
```
|
||||
Symptom: Plugin not in sidebar
|
||||
→ Check: Hard refresh browser (Cmd+Shift+R / Ctrl+Shift+R)
|
||||
→ Check: Plugin installed? kubectl get configmap headlamp-plugin-config -n kube-system
|
||||
|
||||
Symptom: 403 Access Denied
|
||||
→ Check: RBAC binding exists? kubectl get role,rolebinding -n polaris
|
||||
→ Fix: Apply RBAC example from docs/deployment/rbac.md
|
||||
|
||||
Symptom: 404 or 503
|
||||
→ Check: Polaris installed? kubectl get pods -n polaris
|
||||
→ Check: Service exists? kubectl get svc polaris-dashboard -n polaris
|
||||
|
||||
Symptom: Stale audit data
|
||||
→ Fix: kubectl rollout restart deployment -n polaris polaris-dashboard
|
||||
→ Verify: Check AuditTime in UI matches current date
|
||||
|
||||
Symptom: Settings page empty or broken
|
||||
→ Check: Plugin version ≥ v0.3.3?
|
||||
→ Fix: Upgrade plugin and hard refresh browser
|
||||
|
||||
Symptom: CI prettier check fails
|
||||
→ Fix: npx prettier --write src/
|
||||
→ Commit: Include formatting fixes in your PR
|
||||
|
||||
Symptom: Dark mode white backgrounds
|
||||
→ Check: Plugin version ≥ v0.3.5?
|
||||
→ Fix: Upgrade and hard refresh browser
|
||||
```
|
||||
|
||||
## Historical Context
|
||||
|
||||
### Why Service Proxy Instead of ConfigMaps?
|
||||
|
||||
Early versions (< v0.0.10) incorrectly documented ConfigMap RBAC. The plugin **never** accessed ConfigMaps - it always used the service proxy. This was clarified in v0.0.10.
|
||||
|
||||
### Why No MUI Imports?
|
||||
|
||||
v0.3.2 removed direct MUI imports because they caused plugin load failures. Headlamp provides all needed MUI components as re-exports through `CommonComponents`.
|
||||
|
||||
### Why React Context?
|
||||
|
||||
ADR-001 documents the switch to React Context. Before v0.3.0, each component called `usePolarisData()` independently, causing duplicate API requests. Context ensures a single shared fetch.
|
||||
|
||||
### Why No Continuous Polaris Audits?
|
||||
|
||||
Polaris dashboard mode runs a one-time audit at pod startup and caches results. This is by design in Polaris itself. For continuous auditing, Polaris would need to be configured in webhook mode (admission controller), which is a different deployment pattern.
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2026-02-12
|
||||
**Version**: v0.4.1
|
||||
**Target Headlamp**: v0.26+
|
||||
**Target Polaris**: v9.x
|
||||
+3
-3
@@ -447,11 +447,11 @@ For testing before stable release:
|
||||
|
||||
## Getting Help
|
||||
|
||||
- **Questions:** Open a [GitHub Discussion](https://github.com/cpfarhood/headlamp-polaris-plugin/discussions)
|
||||
- **Bugs:** Open a [GitHub Issue](https://github.com/cpfarhood/headlamp-polaris-plugin/issues)
|
||||
- **Questions:** Open a [GitHub Discussion](https://github.com/privilegedescalation/headlamp-polaris-plugin/discussions)
|
||||
- **Bugs:** Open a [GitHub Issue](https://github.com/privilegedescalation/headlamp-polaris-plugin/issues)
|
||||
- **E2E Testing:** See [e2e/README.md](e2e/README.md)
|
||||
- **Architecture:** See [CLAUDE.md](CLAUDE.md)
|
||||
|
||||
## License
|
||||
|
||||
By contributing, you agree that your contributions will be licensed under the MIT License.
|
||||
By contributing, you agree that your contributions will be licensed under the Apache-2.0 License.
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
# Headlamp Polaris Plugin
|
||||
|
||||
[](https://artifacthub.io/packages/headlamp/polaris/headlamp-polaris-plugin)
|
||||
[](https://github.com/cpfarhood/headlamp-polaris-plugin/actions/workflows/ci.yaml)
|
||||
[](https://github.com/cpfarhood/headlamp-polaris-plugin/actions/workflows/e2e.yaml)
|
||||
[](https://opensource.org/licenses/MIT)
|
||||
[](https://github.com/privilegedescalation/headlamp-polaris-plugin/actions/workflows/ci.yaml)
|
||||
[](https://github.com/privilegedescalation/headlamp-polaris-plugin/actions/workflows/e2e.yaml)
|
||||
[](https://opensource.org/licenses/Apache-2.0)
|
||||
|
||||
A [Headlamp](https://headlamp.dev/) plugin that surfaces [Fairwinds Polaris](https://polaris.docs.fairwinds.com/) audit results directly in the Headlamp UI.
|
||||
|
||||
**📚 [Documentation](#documentation) | 🚀 [Installation](#installing) | 🔒 [Security](#rbac--security-setup) | 🛠️ [Development](#development)**
|
||||
**[Documentation](#documentation) | [Installation](#installing) | [Security](#rbac--security-setup) | [Development](#development)**
|
||||
|
||||
## What It Does
|
||||
|
||||
@@ -50,19 +50,16 @@ Polaris must be deployed in the `polaris` namespace with the dashboard component
|
||||
|
||||
### Option 1: Headlamp Plugin Manager (Recommended)
|
||||
|
||||
**⚠️ CRITICAL for Headlamp v0.39.0+:** You **must** set `config.watchPlugins: false` or the plugin will not load. See [docs/DEPLOYMENT.md](docs/DEPLOYMENT.md#critical-headlamp-v0390-configuration) for details.
|
||||
|
||||
The plugin is published on [Artifact Hub](https://artifacthub.io/packages/headlamp/polaris/headlamp-polaris-plugin). Configure Headlamp via Helm:
|
||||
|
||||
```yaml
|
||||
config:
|
||||
pluginsDir: /headlamp/plugins
|
||||
watchPlugins: false # CRITICAL for v0.39.0+
|
||||
|
||||
pluginsManager:
|
||||
sources:
|
||||
- name: headlamp-polaris-plugin
|
||||
url: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/download/v0.3.5/headlamp-polaris-plugin-0.3.5.tar.gz
|
||||
url: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/download/v0.3.10/polaris-0.3.10.tar.gz
|
||||
```
|
||||
|
||||
Or install via the Headlamp UI:
|
||||
@@ -96,17 +93,17 @@ sidecars:
|
||||
|
||||
### Option 3: Manual Tarball Install
|
||||
|
||||
Download the `.tar.gz` from the [GitHub releases page](https://github.com/cpfarhood/headlamp-polaris-plugin/releases), then extract into Headlamp's plugin directory:
|
||||
Download the `.tar.gz` from the [GitHub releases page](https://github.com/privilegedescalation/headlamp-polaris-plugin/releases), then extract into Headlamp's plugin directory:
|
||||
|
||||
```bash
|
||||
wget https://github.com/cpfarhood/headlamp-polaris-plugin/releases/download/v0.3.5/headlamp-polaris-plugin-0.3.5.tar.gz
|
||||
tar xzf headlamp-polaris-plugin-0.3.5.tar.gz -C /headlamp/plugins/
|
||||
wget https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/download/v0.3.10/polaris-0.3.10.tar.gz
|
||||
tar xzf polaris-0.3.10.tar.gz -C /headlamp/plugins/
|
||||
```
|
||||
|
||||
### Option 4: Build from Source
|
||||
|
||||
```bash
|
||||
git clone https://github.com/cpfarhood/headlamp-polaris-plugin.git
|
||||
git clone https://github.com/privilegedescalation/headlamp-polaris-plugin.git
|
||||
cd headlamp-polaris-plugin
|
||||
npm install
|
||||
npm run build
|
||||
@@ -172,7 +169,7 @@ Every proxied request is recorded in Kubernetes API audit logs as a `get` on `se
|
||||
|
||||
## Documentation
|
||||
|
||||
📚 **[Complete Documentation](docs/README.md)** - Documentation hub with all guides
|
||||
**[Complete Documentation](docs/README.md)** - Documentation hub with all guides
|
||||
|
||||
### Quick Links
|
||||
|
||||
@@ -182,14 +179,14 @@ Every proxied request is recorded in Kubernetes API audit logs as a `get` on `se
|
||||
|
||||
### Comprehensive Guides
|
||||
|
||||
| Guide | Description |
|
||||
|-------|-------------|
|
||||
| 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) |
|
||||
| **[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
|
||||
|
||||
@@ -197,14 +194,14 @@ Every proxied request is recorded in Kubernetes API audit logs as a `get` on `se
|
||||
|
||||
Quick reference:
|
||||
|
||||
| Symptom | Likely Cause | Quick Fix |
|
||||
| ------------------------------- | -------------------------------------------- | --------------------------------------------------------------------- |
|
||||
| **Plugin not in sidebar** | Headlamp v0.39.0+ plugin loading issue | Set `config.watchPlugins: false` and hard refresh (Cmd+Shift+R) |
|
||||
| **403 Access Denied** | Missing RBAC binding for `services/proxy` | Apply Role + RoleBinding from RBAC section |
|
||||
| **404 or 503** | Polaris not installed, or dashboard disabled | Install Polaris with `dashboard.enabled: true` in `polaris` namespace |
|
||||
| **Dark mode white backgrounds** | Old plugin version | Upgrade to v0.3.5+ and hard refresh browser |
|
||||
| **Settings page empty** | Old plugin version | Upgrade to v0.3.3+ |
|
||||
| **No data / infinite spinner** | Network policy or Polaris pod down | Check network policies and `kubectl get pods -n polaris` |
|
||||
| Symptom | Likely Cause | Quick Fix |
|
||||
| ------------------------------- | --------------------------------------------- | --------------------------------------------------------------------- |
|
||||
| **Plugin not in sidebar** | Plugin not installed or needs browser refresh | Hard refresh browser (Cmd+Shift+R / Ctrl+Shift+F5) |
|
||||
| **403 Access Denied** | Missing RBAC binding for `services/proxy` | Apply Role + RoleBinding from RBAC section |
|
||||
| **404 or 503** | Polaris not installed, or dashboard disabled | Install Polaris with `dashboard.enabled: true` in `polaris` namespace |
|
||||
| **Dark mode white backgrounds** | Old plugin version | Upgrade to v0.3.5+ and hard refresh browser |
|
||||
| **Settings page empty** | Old plugin version | Upgrade to v0.3.3+ |
|
||||
| **No data / infinite spinner** | Network policy or Polaris pod down | Check network policies and `kubectl get pods -n polaris` |
|
||||
|
||||
## Development
|
||||
|
||||
@@ -214,7 +211,7 @@ Quick reference:
|
||||
|
||||
```bash
|
||||
# Clone repository
|
||||
git clone https://github.com/cpfarhood/headlamp-polaris-plugin.git
|
||||
git clone https://github.com/privilegedescalation/headlamp-polaris-plugin.git
|
||||
cd headlamp-polaris-plugin
|
||||
|
||||
# Install dependencies
|
||||
@@ -365,15 +362,11 @@ Contributions are welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md) for:
|
||||
|
||||
## Links
|
||||
|
||||
- **[GitHub Repository](https://github.com/cpfarhood/headlamp-polaris-plugin)** - Source code, issues, releases
|
||||
- **[GitHub Repository](https://github.com/privilegedescalation/headlamp-polaris-plugin)** - Source code, issues, releases
|
||||
- **[Artifact Hub](https://artifacthub.io/packages/headlamp/polaris/headlamp-polaris-plugin)** - Plugin catalog listing
|
||||
- **[Headlamp](https://headlamp.dev/)** - Kubernetes web UI
|
||||
- **[Fairwinds Polaris](https://polaris.docs.fairwinds.com/)** - Kubernetes best practices audit tool
|
||||
|
||||
## License
|
||||
|
||||
[MIT License](LICENSE) - see LICENSE file for details.
|
||||
|
||||
---
|
||||
|
||||
**Made with ❤️ for the Kubernetes community**
|
||||
[Apache-2.0 License](LICENSE) - see LICENSE file for details.
|
||||
|
||||
+6
-6
@@ -194,7 +194,7 @@ We apply security updates to the latest release only. Please ensure you are runn
|
||||
|
||||
If you discover a security vulnerability in this plugin, please report it via:
|
||||
|
||||
1. **GitHub Security Advisories**: [Report a vulnerability](https://github.com/cpfarhood/headlamp-polaris-plugin/security/advisories/new)
|
||||
1. **GitHub Security Advisories**: [Report a vulnerability](https://github.com/privilegedescalation/headlamp-polaris-plugin/security/advisories/new)
|
||||
2. **Email**: Create a GitHub issue and mark it as "security" if advisories are not available
|
||||
|
||||
**Please do not:**
|
||||
@@ -334,7 +334,7 @@ The plugin processes only technical metadata (resource names, namespaces, check
|
||||
Subscribe to security updates via:
|
||||
|
||||
1. **GitHub Watch**: Click "Watch" → "Custom" → "Security alerts"
|
||||
2. **GitHub Releases**: Monitor [releases page](https://github.com/cpfarhood/headlamp-polaris-plugin/releases)
|
||||
2. **GitHub Releases**: Monitor [releases page](https://github.com/privilegedescalation/headlamp-polaris-plugin/releases)
|
||||
3. **ArtifactHub**: Follow package at [ArtifactHub](https://artifacthub.io/packages/headlamp/headlamp-polaris-plugin/headlamp-polaris-plugin)
|
||||
|
||||
### Security Patch Process
|
||||
@@ -349,10 +349,10 @@ When a security vulnerability is identified:
|
||||
|
||||
## Contact
|
||||
|
||||
- **Security Issues**: [GitHub Security Advisories](https://github.com/cpfarhood/headlamp-polaris-plugin/security/advisories)
|
||||
- **General Questions**: [GitHub Discussions](https://github.com/cpfarhood/headlamp-polaris-plugin/discussions)
|
||||
- **Bug Reports**: [GitHub Issues](https://github.com/cpfarhood/headlamp-polaris-plugin/issues)
|
||||
- **Security Issues**: [GitHub Security Advisories](https://github.com/privilegedescalation/headlamp-polaris-plugin/security/advisories)
|
||||
- **General Questions**: [GitHub Discussions](https://github.com/privilegedescalation/headlamp-polaris-plugin/discussions)
|
||||
- **Bug Reports**: [GitHub Issues](https://github.com/privilegedescalation/headlamp-polaris-plugin/issues)
|
||||
|
||||
## License
|
||||
|
||||
This plugin is provided under the MIT License. See [LICENSE](LICENSE) for details.
|
||||
This plugin is provided under the Apache-2.0 License. See [LICENSE](LICENSE) for details.
|
||||
|
||||
+7
-7
@@ -1,4 +1,4 @@
|
||||
version: 0.3.9
|
||||
version: "0.5.1"
|
||||
name: headlamp-polaris-plugin
|
||||
displayName: Polaris
|
||||
createdAt: "2026-02-05T19:00:00Z"
|
||||
@@ -9,8 +9,8 @@ description: >-
|
||||
read-only via the Kubernetes service proxy to the Polaris dashboard.
|
||||
Requires a Role granting `get` on `services/proxy` for the
|
||||
`polaris-dashboard` service in the `polaris` namespace.
|
||||
license: MIT
|
||||
homeURL: "https://github.com/cpfarhood/headlamp-polaris-plugin"
|
||||
license: Apache-2.0
|
||||
homeURL: "https://github.com/privilegedescalation/headlamp-polaris-plugin"
|
||||
category: security
|
||||
keywords:
|
||||
- polaris
|
||||
@@ -21,14 +21,14 @@ keywords:
|
||||
- kubernetes
|
||||
links:
|
||||
- name: Source
|
||||
url: "https://github.com/cpfarhood/headlamp-polaris-plugin"
|
||||
url: "https://github.com/privilegedescalation/headlamp-polaris-plugin"
|
||||
- name: Polaris
|
||||
url: "https://polaris.docs.fairwinds.com/"
|
||||
maintainers:
|
||||
- name: cpfarhood
|
||||
- name: privilegedescalation
|
||||
email: "chris@farhood.org"
|
||||
annotations:
|
||||
headlamp/plugin/archive-url: "https://github.com/cpfarhood/headlamp-polaris-plugin/releases/download/v0.3.9/polaris-0.3.9.tar.gz"
|
||||
headlamp/plugin/archive-url: "https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/download/v0.5.1/polaris-0.5.1.tar.gz"
|
||||
headlamp/plugin/version-compat: ">=0.26"
|
||||
headlamp/plugin/archive-checksum: sha256:4447bff847623dbab0d0cde739f17e5b2888bf95e1f152fa217274004775823d
|
||||
headlamp/plugin/archive-checksum: sha256:6203461dccc978ae3f33f4feae102c4eb3169ea87c23dc407ef10ea76dd952db
|
||||
headlamp/plugin/distro-compat: in-cluster
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
repositoryID: fc3397f6-a75a-4950-ab50-da75c08a8089
|
||||
owners:
|
||||
- name: cpfarhood
|
||||
- name: privilegedescalation
|
||||
email: "chris@farhood.org"
|
||||
|
||||
@@ -1,109 +0,0 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Project Overview
|
||||
|
||||
Headlamp plugin that surfaces Fairwinds Polaris audit results inside the Headlamp UI. Queries the Polaris dashboard API via the Kubernetes service proxy (`/api/v1/namespaces/polaris/services/polaris-dashboard/proxy/results.json`). Target Headlamp ≥ v0.26.
|
||||
|
||||
## Build & Development Commands
|
||||
|
||||
```bash
|
||||
# Install dependencies
|
||||
npm install
|
||||
|
||||
# Build the plugin (standard Headlamp plugin build)
|
||||
npx @kinvolk/headlamp-plugin build
|
||||
|
||||
# Start development mode with hot reload
|
||||
npx @kinvolk/headlamp-plugin start
|
||||
|
||||
# Type-check without emitting
|
||||
npx tsc --noEmit
|
||||
|
||||
# Lint
|
||||
npx eslint src/
|
||||
|
||||
# Run tests
|
||||
npm test
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
src/
|
||||
├── index.tsx # Entry point: registers sidebar entries + routes
|
||||
├── api/
|
||||
│ ├── polaris.ts # Types (AuditData schema), usePolarisData hook, countResults utilities, refresh settings
|
||||
│ ├── polaris.test.ts # Unit tests for utility functions (vitest)
|
||||
│ └── PolarisDataContext.tsx # React context provider for shared data fetch
|
||||
└── components/
|
||||
├── DashboardView.tsx # Overview page (score, check summary with skipped count, cluster info)
|
||||
├── NamespacesListView.tsx # Namespace list with scores and links to detail views
|
||||
├── NamespaceDetailView.tsx # Per-namespace drill-down with resource table
|
||||
└── PolarisSettings.tsx # Plugin settings (refresh interval selector)
|
||||
```
|
||||
|
||||
Top-level sidebar section at `/polaris` with sub-routes for namespaces list (`/polaris/namespaces`) and per-namespace views (`/polaris/ns/:namespace`). Data is fetched via `ApiProxy.request` to the Polaris dashboard service proxy and refreshed on a user-configurable interval (stored in localStorage under `polaris-plugin-refresh-interval`, default 5 minutes). Score is computed from result counts (pass/total). Skipped checks are always displayed in summaries.
|
||||
|
||||
**Sidebar limitation**: Headlamp's sidebar only supports 2-level nesting (parent → children). The `Collapse` component is driven by route-based selection, not click-to-toggle, so 3-level hierarchies don't expand properly. Namespace navigation is handled via the in-content table on the Namespaces page instead.
|
||||
|
||||
## Security / RBAC Requirements
|
||||
|
||||
The plugin reaches Polaris through the Kubernetes API server's service proxy sub-resource (`/api/v1/namespaces/polaris/services/polaris-dashboard/proxy/...`). The Headlamp service account (or the user's bearer token when Headlamp runs in token-auth mode) must be granted:
|
||||
|
||||
| Verb | API Group | Resource | Resource Name | Namespace |
|
||||
|------|-----------|----------|---------------|-----------|
|
||||
| `get` | `""` (core) | `services/proxy` | `polaris-dashboard` | `polaris` |
|
||||
|
||||
Minimal RBAC example:
|
||||
|
||||
```yaml
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: polaris-proxy-reader
|
||||
namespace: polaris
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["services/proxy"]
|
||||
resourceNames: ["polaris-dashboard"]
|
||||
verbs: ["get"]
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: headlamp-polaris-proxy
|
||||
namespace: polaris
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: headlamp # adjust to match your Headlamp SA
|
||||
namespace: kube-system
|
||||
roleRef:
|
||||
kind: Role
|
||||
name: polaris-proxy-reader
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
```
|
||||
|
||||
Additional considerations:
|
||||
|
||||
- **NetworkPolicy**: If the `polaris` namespace enforces network policies, allow ingress from the Headlamp pod (or the API server, since it performs the proxy hop) to `polaris-dashboard` on port 80.
|
||||
- **Polaris dashboard listen address**: The Polaris Helm chart exposes the dashboard on a ClusterIP service (`polaris-dashboard:80`). If the chart is installed with `dashboard.enabled: false`, the service will not be created, resulting in a 404 error for proxy requests.
|
||||
- **No write operations**: The plugin only performs `GET` requests through the proxy. No `create`, `update`, or `delete` verbs are required. Do not grant broader service proxy access than `get`.
|
||||
- **Token-auth mode**: When Headlamp is configured for user-supplied tokens (rather than a fixed service account), each user's own RBAC bindings must include the role above. A 403 from the plugin means the logged-in user lacks the binding.
|
||||
- **Audit logging**: Kubernetes API audit logs will record every proxied request as a `get` on `services/proxy` in the `polaris` namespace. Set an appropriate audit policy level if request volume from the auto-refresh interval is a concern.
|
||||
|
||||
## Key Constraints
|
||||
|
||||
- **Data source**: Polaris dashboard API via K8s service proxy. Requires Polaris deployed in the `polaris` namespace with a `polaris-dashboard` service. No CRDs, no cluster write operations.
|
||||
- **UI components**: Use only Headlamp-provided components (`@kinvolk/headlamp-plugin/lib/CommonComponents`). Do not import raw MUI packages. No custom theming.
|
||||
- **Error handling**: Must handle 403 (RBAC denied), 404 (Polaris not installed), malformed JSON, and loading states with distinct visual states.
|
||||
- **TypeScript strictness**: No `any`, no implicit `unknown` casting, no dead code, no unused imports.
|
||||
- **Packaging**: `@kinvolk/headlamp-plugin` is a peer dependency. Do not bundle React or MUI.
|
||||
|
||||
## MCP Servers
|
||||
|
||||
The project has MCP server integrations configured in `.mcp.json`:
|
||||
- **Gitea** (git.farh.net): Source control via `gitea-mcp-server`
|
||||
- **Kubernetes** (local): Cluster access via `kubernetes-mcp-server`
|
||||
- **Flux** (local): Flux Operator access via `flux-operator-mcp`
|
||||
+47
-10
@@ -18,6 +18,7 @@ This document describes the architecture, design decisions, and data flow of the
|
||||
The Headlamp Polaris Plugin is a **read-only dashboard** that surfaces Fairwinds Polaris audit results within the Headlamp UI. It fetches data from the Polaris dashboard API via the Kubernetes service proxy and presents it in a hierarchical navigation structure.
|
||||
|
||||
**Key Characteristics:**
|
||||
|
||||
- **Read-only:** No write operations to cluster or Polaris
|
||||
- **Service proxy based:** Uses K8s API server proxy to reach Polaris
|
||||
- **React Context for state:** Shared data fetch across components
|
||||
@@ -43,7 +44,7 @@ The Headlamp Polaris Plugin is a **read-only dashboard** that surfaces Fairwinds
|
||||
│ └────────┬────────┘ │
|
||||
│ │ │
|
||||
│ ┌─────────────▼──────────────┐ │
|
||||
│ │ Polaris Plugin (This!) │ │
|
||||
│ │ Polaris Plugin │ │
|
||||
│ ├────────────────────────────┤ │
|
||||
│ │ • registerSidebarEntry │ │
|
||||
│ │ • registerRoute │ │
|
||||
@@ -170,6 +171,7 @@ Display namespace score + resource table
|
||||
### Plugin Entry Point
|
||||
|
||||
**`src/index.tsx`**
|
||||
|
||||
- Registers sidebar entries (Polaris → Overview, Namespaces)
|
||||
- Registers routes (`/polaris`, `/polaris/namespaces`)
|
||||
- Registers app bar action (score badge)
|
||||
@@ -179,22 +181,26 @@ Display namespace score + resource table
|
||||
### Data Layer
|
||||
|
||||
**`src/api/PolarisDataContext.tsx`**
|
||||
|
||||
- React Context Provider for shared data
|
||||
- Fetches AuditData from Polaris dashboard
|
||||
- Handles auto-refresh based on user settings
|
||||
- Provides `{ data, loading, error, refresh }` to consumers
|
||||
|
||||
**`src/api/polaris.ts`**
|
||||
|
||||
- TypeScript types for AuditData schema
|
||||
- Utility functions: `countResults()`, `computeScore()`
|
||||
- Settings management: `getRefreshInterval()`, `setRefreshInterval()`
|
||||
- Constants: `DASHBOARD_URL_DEFAULT`, `INTERVAL_OPTIONS`
|
||||
|
||||
**`src/api/checkMapping.ts`**
|
||||
|
||||
- Maps Polaris check IDs to human-readable names
|
||||
- Used for display in UI (e.g., "hostIPCSet" → "Host IPC")
|
||||
|
||||
**`src/api/topIssues.ts`**
|
||||
|
||||
- Aggregates failing checks across cluster
|
||||
- Groups by check ID and severity
|
||||
- Used for top issues dashboard
|
||||
@@ -202,6 +208,7 @@ Display namespace score + resource table
|
||||
### View Components
|
||||
|
||||
**`src/components/DashboardView.tsx`**
|
||||
|
||||
- **Route:** `/polaris`
|
||||
- **Purpose:** Cluster-wide overview
|
||||
- **Features:**
|
||||
@@ -212,6 +219,7 @@ Display namespace score + resource table
|
||||
- **Data:** Uses `usePolarisDataContext()`
|
||||
|
||||
**`src/components/NamespacesListView.tsx`**
|
||||
|
||||
- **Route:** `/polaris/namespaces`
|
||||
- **Purpose:** List all namespaces with scores
|
||||
- **Features:**
|
||||
@@ -221,6 +229,7 @@ Display namespace score + resource table
|
||||
- **Data:** Uses `usePolarisDataContext()`, aggregates by namespace
|
||||
|
||||
**`src/components/NamespaceDetailView.tsx`**
|
||||
|
||||
- **Route:** Drawer on `/polaris/namespaces#<namespace>`
|
||||
- **Purpose:** Namespace-level drill-down
|
||||
- **Features:**
|
||||
@@ -233,6 +242,7 @@ Display namespace score + resource table
|
||||
### UI Components
|
||||
|
||||
**`src/components/AppBarScoreBadge.tsx`**
|
||||
|
||||
- **Location:** Headlamp app bar (top-right)
|
||||
- **Purpose:** Quick cluster score visibility
|
||||
- **Features:**
|
||||
@@ -242,6 +252,7 @@ Display namespace score + resource table
|
||||
- **Data:** Uses `usePolarisDataContext()`
|
||||
|
||||
**`src/components/PolarisSettings.tsx`**
|
||||
|
||||
- **Location:** Settings → Plugins → Polaris
|
||||
- **Purpose:** Plugin configuration
|
||||
- **Features:**
|
||||
@@ -251,6 +262,7 @@ Display namespace score + resource table
|
||||
- **Data:** localStorage for persistence
|
||||
|
||||
**`src/components/InlineAuditSection.tsx`**
|
||||
|
||||
- **Location:** Resource detail pages (Deployment, StatefulSet, etc.)
|
||||
- **Purpose:** Show Polaris audit inline
|
||||
- **Features:**
|
||||
@@ -260,6 +272,7 @@ Display namespace score + resource table
|
||||
- **Data:** Uses `usePolarisDataContext()`, filters by resource
|
||||
|
||||
**`src/components/ExemptionManager.tsx`**
|
||||
|
||||
- **Location:** (Planned feature, UI exists but not fully integrated)
|
||||
- **Purpose:** Manage Polaris exemptions via annotations
|
||||
- **Features:**
|
||||
@@ -274,6 +287,7 @@ Display namespace score + resource table
|
||||
**Decision:** Use React Context instead of Redux/Zustand
|
||||
|
||||
**Rationale:**
|
||||
|
||||
1. **Simple state:** Single AuditData object shared across views
|
||||
2. **Read-only:** No complex mutations or transactions
|
||||
3. **Headlamp constraints:** Plugin cannot add dependencies (Redux not bundled)
|
||||
@@ -283,10 +297,10 @@ Display namespace score + resource table
|
||||
|
||||
```typescript
|
||||
interface PolarisDataContextValue {
|
||||
data: AuditData | null; // Audit results or null if loading/error
|
||||
loading: boolean; // True during initial fetch
|
||||
error: string | null; // Error message if fetch failed
|
||||
refresh: () => void; // Manual refresh function
|
||||
data: AuditData | null; // Audit results or null if loading/error
|
||||
loading: boolean; // True during initial fetch
|
||||
error: string | null; // Error message if fetch failed
|
||||
refresh: () => void; // Manual refresh function
|
||||
}
|
||||
```
|
||||
|
||||
@@ -300,6 +314,7 @@ interface PolarisDataContextValue {
|
||||
### localStorage Usage
|
||||
|
||||
Settings persisted in localStorage:
|
||||
|
||||
- **`polaris-plugin-refresh-interval`**: Number (seconds), default 300
|
||||
- **`polaris-plugin-dashboard-url`**: String, default service proxy path
|
||||
|
||||
@@ -312,12 +327,14 @@ No sensitive data stored in localStorage.
|
||||
**Decision:** Use Kubernetes service proxy, not direct ClusterIP access
|
||||
|
||||
**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)
|
||||
|
||||
**Trade-off:**
|
||||
|
||||
- Requires `get` permission on `services/proxy` resource
|
||||
- Path is longer: `/api/v1/namespaces/polaris/services/polaris-dashboard:80/proxy/results.json`
|
||||
|
||||
@@ -326,14 +343,17 @@ No sensitive data stored in localStorage.
|
||||
**Decision:** Sidebar has "Polaris" → "Overview" and "Namespaces" (2 levels max)
|
||||
|
||||
**Rationale:**
|
||||
|
||||
- Headlamp sidebar supports 2-level nesting maximum
|
||||
- Deeper nesting (e.g., Polaris → Namespaces → <each namespace>) doesn't work
|
||||
- Sidebar Collapse component is route-based, not click-to-toggle
|
||||
|
||||
**Alternative Considered:**
|
||||
|
||||
- Dynamic sidebar with namespace entries → rejected (Headlamp limitation)
|
||||
|
||||
**Current Solution:**
|
||||
|
||||
- Use table in NamespacesListView with clickable namespace buttons
|
||||
- Namespace detail opens in drawer (not new route)
|
||||
|
||||
@@ -342,12 +362,14 @@ No sensitive data stored in localStorage.
|
||||
**Decision:** Namespace detail uses drawer, not dedicated route
|
||||
|
||||
**Rationale:**
|
||||
|
||||
- Better UX (drawer overlays table, no navigation loss)
|
||||
- URL hash preserves navigation state (`#namespace-name`)
|
||||
- Keyboard shortcuts (Escape to close)
|
||||
- Sidebar doesn't support 3-level nesting for per-namespace routes
|
||||
|
||||
**Implementation:**
|
||||
|
||||
- URL: `/polaris/namespaces#kube-system`
|
||||
- Drawer controlled by hash presence
|
||||
- `useEffect` watches hash changes
|
||||
@@ -357,11 +379,13 @@ No sensitive data stored in localStorage.
|
||||
**Decision:** Never import from `@mui/material` or `@mui/icons-material`
|
||||
|
||||
**Rationale:**
|
||||
|
||||
- Headlamp plugin environment doesn't provide full MUI library
|
||||
- Importing MUI causes `createSvgIcon undefined` error
|
||||
- Plugins must use Headlamp CommonComponents only
|
||||
|
||||
**Alternative:**
|
||||
|
||||
- Use standard HTML elements with inline styles
|
||||
- Use theme-aware CSS variables (`--mui-palette-*`)
|
||||
|
||||
@@ -370,11 +394,13 @@ No sensitive data stored in localStorage.
|
||||
**Decision:** Enable all TypeScript strict checks
|
||||
|
||||
**Rationale:**
|
||||
|
||||
- Catch errors at compile time
|
||||
- Better IDE support and autocomplete
|
||||
- Enforces type safety (no `any`, no implicit unknowns)
|
||||
|
||||
**Impact:**
|
||||
|
||||
- More verbose code (explicit types required)
|
||||
- Better maintainability and refactorability
|
||||
|
||||
@@ -383,11 +409,13 @@ No sensitive data stored in localStorage.
|
||||
**Decision:** Default refresh interval is 5 minutes (configurable)
|
||||
|
||||
**Rationale:**
|
||||
|
||||
- Polaris audits typically run every 10-30 minutes
|
||||
- Balance between data freshness and API load
|
||||
- User can configure from 1 minute to 30 minutes
|
||||
|
||||
**Considered:**
|
||||
|
||||
- WebSocket/SSE for real-time updates → rejected (Polaris dashboard doesn't support)
|
||||
- Shorter default → rejected (unnecessary API calls)
|
||||
|
||||
@@ -401,28 +429,30 @@ No sensitive data stored in localStorage.
|
||||
|
||||
```typescript
|
||||
// Sidebar navigation
|
||||
registerSidebarEntry({ parent, name, label, url, icon })
|
||||
registerSidebarEntry({ parent, name, label, url, icon });
|
||||
|
||||
// Routes
|
||||
registerRoute({ path, sidebar, name, exact, component })
|
||||
registerRoute({ path, sidebar, name, exact, component });
|
||||
|
||||
// App bar actions
|
||||
registerAppBarAction(component)
|
||||
registerAppBarAction(component);
|
||||
|
||||
// Plugin settings
|
||||
registerPluginSettings(name, component, displaySaveButton)
|
||||
registerPluginSettings(name, component, displaySaveButton);
|
||||
|
||||
// Resource detail sections
|
||||
registerDetailsViewSection(component)
|
||||
registerDetailsViewSection(component);
|
||||
```
|
||||
|
||||
**Key Changes in v0.13.0:**
|
||||
|
||||
- `registerDetailsViewSection` now takes 1 argument (component), not 2 (name, component)
|
||||
- `registerAppBarAction` now takes 1 argument (component), not 2 (name, component)
|
||||
|
||||
### Headlamp CommonComponents
|
||||
|
||||
**Used Components:**
|
||||
|
||||
- `SectionBox` - Card-like container with title
|
||||
- `SectionHeader` - Page header with title
|
||||
- `StatusLabel` - Color-coded status badges
|
||||
@@ -432,16 +462,19 @@ registerDetailsViewSection(component)
|
||||
- `Loader` - Loading spinner
|
||||
|
||||
**Router:**
|
||||
|
||||
- `Router.createRouteURL()` - Generate plugin route URLs
|
||||
- React Router's `useHistory()`, `useParams()`, `useLocation()`
|
||||
|
||||
### Kubernetes API (via ApiProxy)
|
||||
|
||||
**Used for:**
|
||||
|
||||
- Fetching Polaris results: `ApiProxy.request(dashboardUrl + 'results.json')`
|
||||
- No direct K8s API calls (all data from Polaris dashboard)
|
||||
|
||||
**RBAC Required:**
|
||||
|
||||
- `get` on `services/proxy` for `polaris-dashboard` in `polaris` namespace
|
||||
|
||||
## Known Limitations
|
||||
@@ -529,18 +562,22 @@ registerDetailsViewSection(component)
|
||||
### Potential Improvements
|
||||
|
||||
1. **WebWorker for data processing**
|
||||
|
||||
- Offload `countResults()` aggregation for large clusters
|
||||
- Keep UI responsive during heavy computation
|
||||
|
||||
2. **IndexedDB caching**
|
||||
|
||||
- Cache audit data offline
|
||||
- Show stale data + "refresh available" indicator
|
||||
|
||||
3. **GraphQL/REST API abstraction**
|
||||
|
||||
- Decouple from Polaris dashboard JSON format
|
||||
- Support multiple backend sources
|
||||
|
||||
4. **Plugin-to-plugin communication**
|
||||
|
||||
- Integrate with other Headlamp plugins (e.g., policy enforcement)
|
||||
- Shared state between plugins
|
||||
|
||||
|
||||
+43
-60
@@ -47,9 +47,9 @@ kubectl -n kube-system get pods -l app.kubernetes.io/name=headlamp
|
||||
```yaml
|
||||
# headlamp-values.yaml
|
||||
config:
|
||||
pluginsDir: "/headlamp/plugins"
|
||||
pluginsDir: /headlamp/plugins
|
||||
|
||||
pluginsManager:
|
||||
pluginsManager:
|
||||
enabled: true
|
||||
repositories:
|
||||
- https://artifacthub.io/packages/search?kind=4
|
||||
@@ -76,8 +76,7 @@ pluginsManager:
|
||||
```yaml
|
||||
# headlamp-values.yaml
|
||||
config:
|
||||
pluginsDir: "/headlamp/plugins"
|
||||
watchPlugins: false # CRITICAL: Must be false for plugin manager
|
||||
pluginsDir: /headlamp/plugins
|
||||
|
||||
replicaCount: 1
|
||||
|
||||
@@ -113,7 +112,7 @@ data:
|
||||
plugin.yml: |
|
||||
- name: headlamp-polaris-plugin
|
||||
version: 0.3.4
|
||||
url: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/download/v0.3.4/headlamp-polaris-plugin-0.3.4.tar.gz
|
||||
url: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/download/v0.3.10/polaris-0.3.10.tar.gz
|
||||
```
|
||||
|
||||
### Method 3: Volume Mount (Development)
|
||||
@@ -123,7 +122,7 @@ data:
|
||||
```yaml
|
||||
# headlamp-values.yaml
|
||||
config:
|
||||
pluginsDir: "/plugins"
|
||||
pluginsDir: '/plugins'
|
||||
|
||||
volumes:
|
||||
- name: plugins
|
||||
@@ -152,9 +151,8 @@ image:
|
||||
tag: v0.39.0
|
||||
|
||||
config:
|
||||
baseURL: ""
|
||||
pluginsDir: "/headlamp/plugins"
|
||||
watchPlugins: false # MUST be false for plugin manager
|
||||
baseURL: ''
|
||||
pluginsDir: /headlamp/plugins
|
||||
|
||||
pluginsManager:
|
||||
enabled: true
|
||||
@@ -195,16 +193,16 @@ resources:
|
||||
# OIDC Authentication (optional)
|
||||
env:
|
||||
- name: HEADLAMP_CONFIG_OIDC_CLIENT_ID
|
||||
value: "headlamp"
|
||||
value: 'headlamp'
|
||||
- name: HEADLAMP_CONFIG_OIDC_CLIENT_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: headlamp-oidc
|
||||
key: client-secret
|
||||
- name: HEADLAMP_CONFIG_OIDC_ISSUER_URL
|
||||
value: "https://auth.example.com/realms/kubernetes"
|
||||
value: 'https://auth.example.com/realms/kubernetes'
|
||||
- name: HEADLAMP_CONFIG_OIDC_SCOPES
|
||||
value: "openid,profile,email,groups"
|
||||
value: 'openid,profile,email,groups'
|
||||
```
|
||||
|
||||
### FluxCD HelmRelease Example
|
||||
@@ -230,8 +228,7 @@ spec:
|
||||
|
||||
values:
|
||||
config:
|
||||
pluginsDir: "/headlamp/plugins"
|
||||
watchPlugins: false
|
||||
pluginsDir: /headlamp/plugins
|
||||
|
||||
pluginsManager:
|
||||
enabled: true
|
||||
@@ -265,10 +262,10 @@ metadata:
|
||||
name: polaris-proxy-reader
|
||||
namespace: polaris
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["services/proxy"]
|
||||
resourceNames: ["polaris-dashboard"]
|
||||
verbs: ["get"]
|
||||
- apiGroups: ['']
|
||||
resources: ['services/proxy']
|
||||
resourceNames: ['polaris-dashboard']
|
||||
verbs: ['get']
|
||||
```
|
||||
|
||||
### RoleBinding Options
|
||||
@@ -303,7 +300,7 @@ metadata:
|
||||
namespace: polaris
|
||||
subjects:
|
||||
- kind: Group
|
||||
name: system:authenticated # All authenticated users
|
||||
name: system:authenticated # All authenticated users
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
roleRef:
|
||||
kind: Role
|
||||
@@ -350,10 +347,10 @@ metadata:
|
||||
app.kubernetes.io/name: headlamp-polaris-plugin
|
||||
app.kubernetes.io/component: rbac
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["services/proxy"]
|
||||
resourceNames: ["polaris-dashboard"]
|
||||
verbs: ["get"]
|
||||
- apiGroups: ['']
|
||||
resources: ['services/proxy']
|
||||
resourceNames: ['polaris-dashboard']
|
||||
verbs: ['get']
|
||||
|
||||
---
|
||||
# RoleBinding: Grant Headlamp service account access
|
||||
@@ -376,6 +373,7 @@ roleRef:
|
||||
```
|
||||
|
||||
Apply with:
|
||||
|
||||
```bash
|
||||
kubectl apply -f polaris-plugin-rbac.yaml
|
||||
```
|
||||
@@ -385,6 +383,7 @@ kubectl apply -f polaris-plugin-rbac.yaml
|
||||
### Required Network Access
|
||||
|
||||
The plugin requires network connectivity:
|
||||
|
||||
- **Headlamp pod** → **Kubernetes API server** (service proxy)
|
||||
- **Kubernetes API server** → **Polaris dashboard service** (port 80)
|
||||
|
||||
@@ -424,36 +423,9 @@ spec:
|
||||
|
||||
## Plugin Manager Setup
|
||||
|
||||
### Critical Configuration
|
||||
|
||||
**❌ WRONG (Will not load plugins):**
|
||||
```yaml
|
||||
config:
|
||||
watchPlugins: true # Default, treats catalog plugins as dev plugins
|
||||
```
|
||||
|
||||
**✅ CORRECT:**
|
||||
```yaml
|
||||
config:
|
||||
watchPlugins: false # Required for plugin manager catalog plugins
|
||||
```
|
||||
|
||||
### Why `watchPlugins: false` is Required
|
||||
|
||||
- **With `watchPlugins: true`:** Headlamp backend serves plugin metadata, but frontend never executes the JavaScript (treated as development directory plugin)
|
||||
- **Result:** Plugins appear in Settings but no sidebar/routes/settings work
|
||||
- **Fix:** Set `watchPlugins: false` in Headlamp configuration
|
||||
- **Documentation:** See `deployment/PLUGIN_LOADING_FIX.md` for root cause analysis
|
||||
|
||||
### Plugin Manager Verification
|
||||
|
||||
```bash
|
||||
# Check Headlamp config
|
||||
kubectl -n kube-system get configmap headlamp -o yaml | grep watchPlugins
|
||||
|
||||
# Expected output:
|
||||
# watchPlugins: "false"
|
||||
|
||||
# Check plugin is installed
|
||||
kubectl -n kube-system exec -it deployment/headlamp -- ls -la /headlamp/plugins/
|
||||
|
||||
@@ -469,7 +441,6 @@ kubectl -n kube-system exec -it deployment/headlamp -- ls -la /headlamp/plugins/
|
||||
- [ ] Polaris dashboard service exists (`polaris-dashboard` in `polaris` namespace)
|
||||
- [ ] RBAC Role and RoleBinding created
|
||||
- [ ] Headlamp v0.26+ deployed
|
||||
- [ ] `watchPlugins: false` set in Headlamp config
|
||||
|
||||
### Deployment
|
||||
|
||||
@@ -518,14 +489,16 @@ kubectl -n kube-system exec -it deployment/headlamp -- ls -la /headlamp/plugins/
|
||||
**Symptom:** Plugin listed in Settings → Plugins but no sidebar entry
|
||||
|
||||
**Causes:**
|
||||
1. `watchPlugins: true` (should be `false`)
|
||||
2. Browser cache not cleared
|
||||
|
||||
1. Browser cache not cleared
|
||||
2. Plugin files not properly installed
|
||||
|
||||
**Solution:**
|
||||
|
||||
```bash
|
||||
# Fix Headlamp config
|
||||
kubectl -n kube-system edit configmap headlamp
|
||||
# Set watchPlugins: false
|
||||
# Verify plugin files exist
|
||||
kubectl -n kube-system exec deployment/headlamp -c headlamp -- \
|
||||
ls -la /headlamp/plugins/headlamp-polaris-plugin/
|
||||
|
||||
# Restart Headlamp
|
||||
kubectl -n kube-system rollout restart deployment/headlamp
|
||||
@@ -541,6 +514,7 @@ kubectl -n kube-system rollout restart deployment/headlamp
|
||||
**Cause:** RBAC missing or incorrect
|
||||
|
||||
**Solution:**
|
||||
|
||||
```bash
|
||||
# Verify RBAC exists
|
||||
kubectl -n polaris get role polaris-proxy-reader
|
||||
@@ -557,11 +531,13 @@ kubectl auth can-i get services/proxy --as=system:serviceaccount:kube-system:hea
|
||||
**Symptom:** Error loading Polaris data, 404 in console
|
||||
|
||||
**Causes:**
|
||||
|
||||
1. Polaris not deployed
|
||||
2. Polaris service name wrong
|
||||
3. Polaris namespace wrong
|
||||
|
||||
**Solution:**
|
||||
|
||||
```bash
|
||||
# Check Polaris deployment
|
||||
kubectl -n polaris get pods
|
||||
@@ -579,11 +555,13 @@ helm install polaris fairwinds-stable/polaris \
|
||||
**Symptom:** Error when using custom Polaris URL in settings
|
||||
|
||||
**Causes:**
|
||||
|
||||
1. URL format incorrect
|
||||
2. CORS not configured on external Polaris
|
||||
3. Network policy blocking external access
|
||||
|
||||
**Solution:**
|
||||
|
||||
```bash
|
||||
# Test URL manually
|
||||
curl -v https://my-polaris.example.com/results.json
|
||||
@@ -599,6 +577,7 @@ curl -v https://my-polaris.example.com/results.json
|
||||
**Cause:** Plugin manager hasn't synced from ArtifactHub
|
||||
|
||||
**Solution:**
|
||||
|
||||
```bash
|
||||
# Wait 30 minutes (ArtifactHub sync interval)
|
||||
# Or manually refresh plugin list in Headlamp UI
|
||||
@@ -614,6 +593,7 @@ kubectl -n kube-system rollout restart deployment/headlamp
|
||||
**Cause:** NetworkPolicy in `polaris` namespace blocking API server
|
||||
|
||||
**Solution:**
|
||||
|
||||
```bash
|
||||
# Check NetworkPolicies
|
||||
kubectl -n polaris get networkpolicy
|
||||
@@ -633,25 +613,28 @@ kubectl -n polaris get networkpolicy
|
||||
### Audit Logging
|
||||
|
||||
Kubernetes audit logs will record:
|
||||
|
||||
- User/service account accessing service proxy
|
||||
- Timestamp and response code
|
||||
|
||||
Configure audit policy if needed:
|
||||
|
||||
```yaml
|
||||
apiVersion: audit.k8s.io/v1
|
||||
kind: Policy
|
||||
rules:
|
||||
- level: Metadata
|
||||
verbs: ["get"]
|
||||
verbs: ['get']
|
||||
resources:
|
||||
- group: ""
|
||||
resources: ["services/proxy"]
|
||||
namespaces: ["polaris"]
|
||||
- group: ''
|
||||
resources: ['services/proxy']
|
||||
namespaces: ['polaris']
|
||||
```
|
||||
|
||||
### Data Sensitivity
|
||||
|
||||
Polaris audit data may contain:
|
||||
|
||||
- Resource names and namespaces
|
||||
- Configuration details
|
||||
- Potential security vulnerabilities
|
||||
|
||||
@@ -11,8 +11,10 @@ This plan standardizes documentation structure, formatting, and content across t
|
||||
## 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
|
||||
@@ -21,6 +23,7 @@ This plan standardizes documentation structure, formatting, and content across t
|
||||
- Well-organized TROUBLESHOOTING.md with common issues
|
||||
|
||||
**Gaps**:
|
||||
|
||||
- No user journey-based organization
|
||||
- No Architecture Decision Records
|
||||
- Limited quick-start tutorials
|
||||
@@ -28,8 +31,10 @@ This plan standardizes documentation structure, formatting, and content across t
|
||||
- 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
|
||||
@@ -38,6 +43,7 @@ This plan standardizes documentation structure, formatting, and content across t
|
||||
- Visual hierarchy with strategic emoji use
|
||||
|
||||
**Gaps**:
|
||||
|
||||
- No dedicated CONTRIBUTING.md (content in README)
|
||||
- No SECURITY.md for vulnerability reporting
|
||||
- Incomplete tutorial placeholders
|
||||
@@ -49,16 +55,18 @@ This plan standardizes documentation structure, formatting, and content across t
|
||||
### 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
|
||||
LICENSE # Apache-2.0 License
|
||||
package.json # Plugin metadata
|
||||
```
|
||||
|
||||
**Documentation Directory** (Organized by User Journey):
|
||||
|
||||
```
|
||||
docs/
|
||||
├── README.md # Documentation hub with quick links
|
||||
@@ -94,6 +102,7 @@ docs/
|
||||
### 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)
|
||||
@@ -111,6 +120,7 @@ docs/
|
||||
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)
|
||||
@@ -122,6 +132,7 @@ docs/
|
||||
**Format**: Keep a Changelog (https://keepachangelog.com/)
|
||||
|
||||
**Structure**:
|
||||
|
||||
```markdown
|
||||
# Changelog
|
||||
|
||||
@@ -135,21 +146,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
## [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
|
||||
@@ -157,6 +174,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
```
|
||||
|
||||
**Standards**:
|
||||
|
||||
- One entry per version, newest first
|
||||
- Date in ISO 8601 format (YYYY-MM-DD)
|
||||
- Link to GitHub release
|
||||
@@ -166,6 +184,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
### 4. CONTRIBUTING.md Standard
|
||||
|
||||
**Required Sections**:
|
||||
|
||||
1. Code of Conduct (brief, respectful)
|
||||
2. Getting Started (prerequisites, setup)
|
||||
3. Development Workflow (feature development, testing)
|
||||
@@ -178,6 +197,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
10. Release Process (version numbering, creating releases)
|
||||
|
||||
**Formatting**:
|
||||
|
||||
- Use tables for branch naming conventions
|
||||
- Code blocks for commit message examples
|
||||
- Checklists for PR requirements
|
||||
@@ -186,6 +206,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
### 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)
|
||||
@@ -198,6 +219,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
10. Compliance Considerations (audit trail, GDPR/privacy)
|
||||
|
||||
**Formatting**:
|
||||
|
||||
- Tables for permissions and supported versions
|
||||
- YAML examples for RBAC manifests
|
||||
- Bash commands for security verification
|
||||
@@ -208,6 +230,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
**Purpose**: Central navigation for all documentation
|
||||
|
||||
**Structure**:
|
||||
|
||||
```markdown
|
||||
# Documentation
|
||||
|
||||
@@ -222,31 +245,40 @@ Central hub for [Plugin Name] documentation.
|
||||
- 💻 [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)
|
||||
@@ -254,12 +286,14 @@ Link to JSDoc or generated API docs
|
||||
### 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
|
||||
|
||||
@@ -280,17 +314,21 @@ What is the change that we're proposing and/or doing?
|
||||
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...
|
||||
@@ -303,11 +341,12 @@ What becomes easier or more difficult to do because of this change?
|
||||
**Numbering**: ADR-001, ADR-002, etc. (zero-padded 3 digits)
|
||||
|
||||
**Index File** (architecture/adr/README.md):
|
||||
|
||||
```markdown
|
||||
# Architecture Decision Records
|
||||
|
||||
| ADR | Title | Status | Date |
|
||||
|-----|-------|--------|------|
|
||||
| ADR | Title | Status | Date |
|
||||
| ------------------- | ----- | -------- | ---------- |
|
||||
| [001](001-title.md) | Title | Accepted | 2026-01-01 |
|
||||
```
|
||||
|
||||
@@ -316,6 +355,7 @@ What becomes easier or more difficult to do because of this change?
|
||||
**Structure**:
|
||||
|
||||
**troubleshooting/README.md** (Quick Diagnosis):
|
||||
|
||||
```markdown
|
||||
# Troubleshooting
|
||||
|
||||
@@ -324,8 +364,8 @@ Quick diagnosis guide for common issues.
|
||||
## Quick Reference
|
||||
|
||||
| Symptom | Likely Cause | Quick Fix |
|
||||
|---------|-------------|-----------|
|
||||
| ... | ... | ... |
|
||||
| ------- | ------------ | --------- |
|
||||
| ... | ... | ... |
|
||||
|
||||
## Detailed Guides
|
||||
|
||||
@@ -335,6 +375,7 @@ Quick diagnosis guide for common issues.
|
||||
```
|
||||
|
||||
**Individual Issue Files**:
|
||||
|
||||
- Symptom-based organization
|
||||
- Step-by-step resolution
|
||||
- Bash commands for verification
|
||||
@@ -346,6 +387,7 @@ Quick diagnosis guide for common issues.
|
||||
**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)
|
||||
@@ -355,6 +397,7 @@ Quick diagnosis guide for common issues.
|
||||
7. Debugging (common issues, useful commands)
|
||||
|
||||
**Formatting**:
|
||||
|
||||
- Tables for test types and coverage goals
|
||||
- Code blocks for examples
|
||||
- Bash commands for running tests
|
||||
@@ -363,6 +406,7 @@ Quick diagnosis guide for common issues.
|
||||
### 10. Visual Formatting Standards
|
||||
|
||||
**Emoji Usage** (Strategic, Not Excessive):
|
||||
|
||||
- 📚 Documentation
|
||||
- 🚀 Installation/Quick Start
|
||||
- 🔒 Security
|
||||
@@ -375,6 +419,7 @@ Quick diagnosis guide for common issues.
|
||||
- 💻 Code/Technical
|
||||
|
||||
**Code Block Languages**:
|
||||
|
||||
- `bash` for shell commands
|
||||
- `yaml` for Kubernetes/Helm manifests
|
||||
- `typescript` for TypeScript code
|
||||
@@ -382,11 +427,13 @@ Quick diagnosis guide for common issues.
|
||||
- `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
|
||||
@@ -397,6 +444,7 @@ Quick diagnosis guide for common issues.
|
||||
### 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
|
||||
@@ -414,6 +462,7 @@ Quick diagnosis guide for common issues.
|
||||
- [ ] 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
|
||||
@@ -421,6 +470,7 @@ Quick diagnosis guide for common issues.
|
||||
- [ ] 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
|
||||
@@ -429,18 +479,21 @@ Quick diagnosis guide for common issues.
|
||||
### 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
|
||||
@@ -449,12 +502,14 @@ Quick diagnosis guide for common issues.
|
||||
### 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
|
||||
@@ -463,21 +518,25 @@ Quick diagnosis guide for common issues.
|
||||
## 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
|
||||
@@ -485,6 +544,7 @@ Quick diagnosis guide for common issues.
|
||||
## 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
|
||||
@@ -493,6 +553,7 @@ Quick diagnosis guide for common issues.
|
||||
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
|
||||
@@ -502,6 +563,7 @@ Quick diagnosis guide for common issues.
|
||||
- [ ] Version numbers current
|
||||
|
||||
**Annual Documentation Audit**:
|
||||
|
||||
- Review all docs for accuracy (especially version numbers, screenshots)
|
||||
- Check for outdated information
|
||||
- Update ADR status if superseded
|
||||
@@ -512,30 +574,30 @@ Quick diagnosis guide for common issues.
|
||||
|
||||
### 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/ |
|
||||
| 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) |
|
||||
| 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) |
|
||||
|
||||
---
|
||||
|
||||
|
||||
+6
-6
@@ -4,11 +4,11 @@ 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)
|
||||
- [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
|
||||
|
||||
@@ -68,4 +68,4 @@ Production deployment guides:
|
||||
|
||||
---
|
||||
|
||||
**Need help?** Open an issue on [GitHub](https://github.com/cpfarhood/headlamp-polaris-plugin/issues) or check [CONTRIBUTING.md](../CONTRIBUTING.md) for development guidelines.
|
||||
**Need help?** Open an issue on [GitHub](https://github.com/privilegedescalation/headlamp-polaris-plugin/issues) or check [CONTRIBUTING.md](../CONTRIBUTING.md) for development guidelines.
|
||||
|
||||
+60
-40
@@ -18,13 +18,13 @@ Comprehensive guide to testing the Headlamp Polaris Plugin, covering unit tests,
|
||||
|
||||
The Headlamp Polaris Plugin uses a multi-layered testing approach:
|
||||
|
||||
| Test Type | Framework | Purpose | Location |
|
||||
|-----------|-----------|---------|----------|
|
||||
| **Unit Tests** | Vitest | Test individual functions and components in isolation | `src/**/*.test.ts(x)` |
|
||||
| **E2E Tests** | Playwright | Test complete user flows against live Headlamp instance | `e2e/*.spec.ts` |
|
||||
| **Type Checking** | TypeScript | Ensure type safety across codebase | `tsc --noEmit` |
|
||||
| **Linting** | ESLint | Enforce code style and catch common errors | `eslint src/` |
|
||||
| **Formatting** | Prettier | Maintain consistent code formatting | `prettier --check src/` |
|
||||
| Test Type | Framework | Purpose | Location |
|
||||
| ----------------- | ---------- | ------------------------------------------------------- | ----------------------- |
|
||||
| **Unit Tests** | Vitest | Test individual functions and components in isolation | `src/**/*.test.ts(x)` |
|
||||
| **E2E Tests** | Playwright | Test complete user flows against live Headlamp instance | `e2e/*.spec.ts` |
|
||||
| **Type Checking** | TypeScript | Ensure type safety across codebase | `tsc --noEmit` |
|
||||
| **Linting** | ESLint | Enforce code style and catch common errors | `eslint src/` |
|
||||
| **Formatting** | Prettier | Maintain consistent code formatting | `prettier --check src/` |
|
||||
|
||||
### Test Philosophy
|
||||
|
||||
@@ -178,7 +178,9 @@ describe('DashboardView', () => {
|
||||
const mockData = {
|
||||
DisplayName: 'test-cluster',
|
||||
ClusterInfo: { Version: '1.27', Nodes: 3, Pods: 100, Namespaces: 10, Controllers: 50 },
|
||||
Results: [/* ... */],
|
||||
Results: [
|
||||
/* ... */
|
||||
],
|
||||
};
|
||||
|
||||
vi.spyOn(PolarisDataContext, 'usePolarisDataContext').mockReturnValue({
|
||||
@@ -197,6 +199,7 @@ describe('DashboardView', () => {
|
||||
### What to Unit Test
|
||||
|
||||
✅ **Do test:**
|
||||
|
||||
- Pure functions (score calculation, filtering, data transformation)
|
||||
- Data parsing and validation
|
||||
- Utility functions
|
||||
@@ -204,6 +207,7 @@ describe('DashboardView', () => {
|
||||
- Edge cases (empty arrays, null values, invalid input)
|
||||
|
||||
❌ **Don't test:**
|
||||
|
||||
- Third-party libraries (Headlamp, React)
|
||||
- Simple prop passing
|
||||
- Trivial getters/setters
|
||||
@@ -242,6 +246,7 @@ npx playwright show-trace test-results/<test-name>/trace.zip
|
||||
**1. Headlamp Instance**
|
||||
|
||||
E2E tests require a running Headlamp instance with:
|
||||
|
||||
- Polaris plugin installed (version being tested)
|
||||
- Polaris dashboard deployed and accessible
|
||||
- RBAC configured (service proxy permissions)
|
||||
@@ -296,32 +301,32 @@ AUTHENTIK_PASSWORD=secret
|
||||
|
||||
**File:** `e2e/polaris.spec.ts`
|
||||
|
||||
| Test | Description | Validates |
|
||||
|------|-------------|-----------|
|
||||
| `sidebar contains Polaris entry` | Polaris appears in sidebar | Plugin registration |
|
||||
| `overview page renders cluster score` | Score displayed on overview | Data fetching, rendering |
|
||||
| `namespaces page renders table` | Namespace table loads | Data parsing, table rendering |
|
||||
| `namespace detail drawer opens` | Clicking namespace shows drawer | Navigation, drawer UI |
|
||||
| `namespace detail drawer closes with Escape` | Keyboard shortcut works | Keyboard navigation |
|
||||
| `namespace detail drawer opens from URL hash` | Direct URL navigation | URL routing, deep linking |
|
||||
| Test | Description | Validates |
|
||||
| --------------------------------------------- | ------------------------------- | ----------------------------- |
|
||||
| `sidebar contains Polaris entry` | Polaris appears in sidebar | Plugin registration |
|
||||
| `overview page renders cluster score` | Score displayed on overview | Data fetching, rendering |
|
||||
| `namespaces page renders table` | Namespace table loads | Data parsing, table rendering |
|
||||
| `namespace detail drawer opens` | Clicking namespace shows drawer | Navigation, drawer UI |
|
||||
| `namespace detail drawer closes with Escape` | Keyboard shortcut works | Keyboard navigation |
|
||||
| `namespace detail drawer opens from URL hash` | Direct URL navigation | URL routing, deep linking |
|
||||
|
||||
**File:** `e2e/settings.spec.ts`
|
||||
|
||||
| Test | Description | Validates |
|
||||
|------|-------------|-----------|
|
||||
| `plugin settings page is accessible` | Settings page loads | Settings registration |
|
||||
| `refresh interval can be changed` | Dropdown works | User preference persistence |
|
||||
| `dashboard URL can be customized` | Input field works | URL configuration |
|
||||
| `connection test button works` | Test functionality | API connectivity validation |
|
||||
| Test | Description | Validates |
|
||||
| ------------------------------------ | ------------------- | --------------------------- |
|
||||
| `plugin settings page is accessible` | Settings page loads | Settings registration |
|
||||
| `refresh interval can be changed` | Dropdown works | User preference persistence |
|
||||
| `dashboard URL can be customized` | Input field works | URL configuration |
|
||||
| `connection test button works` | Test functionality | API connectivity validation |
|
||||
|
||||
**File:** `e2e/appbar.spec.ts`
|
||||
|
||||
| Test | Description | Validates |
|
||||
|------|-------------|-----------|
|
||||
| `app bar displays Polaris badge` | Badge visible in header | App bar integration |
|
||||
| `badge shows cluster score` | Score matches dashboard | Data consistency |
|
||||
| `clicking badge navigates to overview` | Navigation works | App bar action |
|
||||
| `badge color reflects score` | Red/yellow/green based on score | Visual feedback |
|
||||
| Test | Description | Validates |
|
||||
| -------------------------------------- | ------------------------------- | ------------------- |
|
||||
| `app bar displays Polaris badge` | Badge visible in header | App bar integration |
|
||||
| `badge shows cluster score` | Score matches dashboard | Data consistency |
|
||||
| `clicking badge navigates to overview` | Navigation works | App bar action |
|
||||
| `badge color reflects score` | Red/yellow/green based on score | Visual feedback |
|
||||
|
||||
### Writing E2E Tests
|
||||
|
||||
@@ -385,6 +390,7 @@ npx playwright test --debug
|
||||
```
|
||||
|
||||
This opens Playwright Inspector where you can:
|
||||
|
||||
- Step through each test action
|
||||
- Inspect page state
|
||||
- Edit test selectors live
|
||||
@@ -455,12 +461,12 @@ jobs:
|
||||
|
||||
Configure in GitHub repository settings (Settings → Secrets and variables → Actions):
|
||||
|
||||
| Secret | Required | Description |
|
||||
|--------|----------|-------------|
|
||||
| `HEADLAMP_URL` | Optional | Headlamp instance URL (defaults to configured instance) |
|
||||
| `AUTHENTIK_USERNAME` | OIDC | Authentik username/email for CI user |
|
||||
| `AUTHENTIK_PASSWORD` | OIDC | Authentik password |
|
||||
| `HEADLAMP_TOKEN` | Token | Kubernetes service account token (alternative to OIDC) |
|
||||
| Secret | Required | Description |
|
||||
| -------------------- | -------- | ------------------------------------------------------- |
|
||||
| `HEADLAMP_URL` | Optional | Headlamp instance URL (defaults to configured instance) |
|
||||
| `AUTHENTIK_USERNAME` | OIDC | Authentik username/email for CI user |
|
||||
| `AUTHENTIK_PASSWORD` | OIDC | Authentik password |
|
||||
| `HEADLAMP_TOKEN` | Token | Kubernetes service account token (alternative to OIDC) |
|
||||
|
||||
Set either `AUTHENTIK_USERNAME` + `AUTHENTIK_PASSWORD` **or** `HEADLAMP_TOKEN`. OIDC takes priority if both are set.
|
||||
|
||||
@@ -478,11 +484,11 @@ Trigger workflows manually from GitHub Actions UI:
|
||||
|
||||
### Current Coverage
|
||||
|
||||
| Category | Coverage | Notes |
|
||||
|----------|----------|-------|
|
||||
| **API Functions** | 95% | Core utilities fully tested |
|
||||
| **React Components** | 60% | Focus on critical render paths |
|
||||
| **E2E User Flows** | 80% | Main features covered |
|
||||
| Category | Coverage | Notes |
|
||||
| -------------------- | -------- | ------------------------------ |
|
||||
| **API Functions** | 95% | Core utilities fully tested |
|
||||
| **React Components** | 60% | Focus on critical render paths |
|
||||
| **E2E User Flows** | 80% | Main features covered |
|
||||
|
||||
### Coverage Goals
|
||||
|
||||
@@ -507,18 +513,22 @@ open coverage/index.html
|
||||
### Unit Testing
|
||||
|
||||
1. **Test behavior, not implementation**
|
||||
|
||||
- ✅ `expect(computeScore({ total: 100, pass: 75 })).toBe(75)`
|
||||
- ❌ `expect(mockInternalFunction).toHaveBeenCalled()`
|
||||
|
||||
2. **Use descriptive test names**
|
||||
|
||||
- ✅ `it('returns 0 when total checks is zero')`
|
||||
- ❌ `it('works')`
|
||||
|
||||
3. **One assertion per test (when possible)**
|
||||
|
||||
- Makes failures easier to debug
|
||||
- Exceptions: testing multiple properties of same object
|
||||
|
||||
4. **Mock external dependencies**
|
||||
|
||||
- Mock API calls, context providers, external libraries
|
||||
- Don't mock the code you're testing
|
||||
|
||||
@@ -529,27 +539,33 @@ open coverage/index.html
|
||||
### E2E Testing
|
||||
|
||||
1. **Use semantic selectors**
|
||||
|
||||
- ✅ `page.getByRole('button', { name: 'Close' })`
|
||||
- ✅ `page.getByText('Polaris — Overview')`
|
||||
- ❌ `page.locator('.MuiButton-root')`
|
||||
|
||||
2. **Wait for visibility, not arbitrary timeouts**
|
||||
|
||||
- ✅ `await expect(element).toBeVisible()`
|
||||
- ❌ `await page.waitForTimeout(5000)`
|
||||
|
||||
3. **Keep tests independent**
|
||||
|
||||
- Each test should work in isolation
|
||||
- Don't rely on previous tests' state
|
||||
|
||||
4. **Test complete user flows**
|
||||
|
||||
- Navigate → Interact → Verify outcome
|
||||
- Don't just test page loads
|
||||
|
||||
5. **Clean up after tests**
|
||||
|
||||
- Close drawers/modals
|
||||
- Reset state if needed
|
||||
|
||||
6. **Use storage state for auth**
|
||||
|
||||
- Reuse authenticated session across tests
|
||||
- Faster than logging in for every test
|
||||
|
||||
@@ -560,15 +576,18 @@ open coverage/index.html
|
||||
### General
|
||||
|
||||
1. **Run tests before committing**
|
||||
|
||||
```bash
|
||||
npm run build && npm run lint && npm test
|
||||
```
|
||||
|
||||
2. **Fix failing tests immediately**
|
||||
|
||||
- Don't commit failing tests
|
||||
- Don't skip tests to "fix later"
|
||||
|
||||
3. **Update tests when changing code**
|
||||
|
||||
- Tests are documentation
|
||||
- Keep them in sync with implementation
|
||||
|
||||
@@ -604,7 +623,7 @@ Check mocks are returning expected structure:
|
||||
|
||||
```typescript
|
||||
vi.spyOn(PolarisDataContext, 'usePolarisDataContext').mockReturnValue({
|
||||
data: mockData, // Ensure mockData has all required fields
|
||||
data: mockData, // Ensure mockData has all required fields
|
||||
loading: false,
|
||||
error: null,
|
||||
refresh: vi.fn(),
|
||||
@@ -624,6 +643,7 @@ npm run e2e:headed
|
||||
```
|
||||
|
||||
Common causes:
|
||||
|
||||
- Element hasn't rendered yet (use `toBeVisible()` instead of `toBeDefined()`)
|
||||
- Wrong selector (use Playwright Inspector to verify)
|
||||
- Authentication failed (check token/credentials)
|
||||
|
||||
+68
-31
@@ -20,34 +20,17 @@ This guide covers common issues encountered when using the Headlamp Polaris Plug
|
||||
## Plugin Not Showing in Sidebar
|
||||
|
||||
### Symptoms
|
||||
|
||||
- Plugin appears in Settings → Plugins but sidebar entry is missing
|
||||
- No "Polaris" section in navigation
|
||||
- Routes like `/polaris` return 404 or blank page
|
||||
|
||||
### Common Causes
|
||||
|
||||
**1. Headlamp v0.39.0+ Plugin Loading Issue**
|
||||
|
||||
**Root Cause**: Headlamp v0.39.0+ changed plugin loading behavior. With `config.watchPlugins: true` (default), catalog-managed plugins are treated as "development directory" plugins, causing the backend to serve metadata but frontend to never execute the JavaScript.
|
||||
|
||||
**Solution**: Set `config.watchPlugins: false` in Headlamp configuration.
|
||||
|
||||
```yaml
|
||||
# HelmRelease values
|
||||
config:
|
||||
watchPlugins: false # CRITICAL for plugin manager
|
||||
```
|
||||
|
||||
After applying this change:
|
||||
1. Restart Headlamp pod
|
||||
2. Hard refresh browser (Cmd+Shift+R or Ctrl+Shift+R)
|
||||
3. Clear browser cache if needed
|
||||
|
||||
**References**: See `deployment/PLUGIN_LOADING_FIX.md` for complete root cause analysis.
|
||||
|
||||
**2. Plugin Not Installed**
|
||||
**1. Plugin Not Installed**
|
||||
|
||||
**Check plugin installation**:
|
||||
|
||||
```bash
|
||||
# View Headlamp pod logs (plugin sidecar)
|
||||
kubectl logs -n kube-system deployment/headlamp -c headlamp-plugin
|
||||
@@ -58,23 +41,26 @@ kubectl logs -n kube-system deployment/headlamp -c headlamp-plugin
|
||||
```
|
||||
|
||||
**Verify plugin files exist**:
|
||||
|
||||
```bash
|
||||
kubectl exec -n kube-system deployment/headlamp -c headlamp -- ls -la /headlamp/plugins/
|
||||
# Should show: headlamp-polaris-plugin/
|
||||
```
|
||||
|
||||
**3. JavaScript Cached by Browser**
|
||||
**2. JavaScript Cached by Browser**
|
||||
|
||||
After upgrading the plugin, old JavaScript may be cached.
|
||||
|
||||
**Solution**:
|
||||
|
||||
- Hard refresh: Cmd+Shift+R (macOS) or Ctrl+Shift+R (Linux/Windows)
|
||||
- Clear browser cache for Headlamp domain
|
||||
- Open DevTools → Application → Clear Storage → Clear all
|
||||
|
||||
**4. Plugin Disabled in Settings**
|
||||
**3. Plugin Disabled in Settings**
|
||||
|
||||
**Check Settings → Plugins**:
|
||||
|
||||
- Navigate to Headlamp Settings → Plugins
|
||||
- Ensure "Polaris" plugin is enabled (toggle should be ON)
|
||||
- If disabled, enable it and refresh the page
|
||||
@@ -84,11 +70,13 @@ After upgrading the plugin, old JavaScript may be cached.
|
||||
## 403 Forbidden Error
|
||||
|
||||
### Symptoms
|
||||
|
||||
- Error message: "Error loading Polaris audit data: 403 Forbidden"
|
||||
- Browser console shows 403 response from API proxy
|
||||
- Plugin sidebar shows but data fails to load
|
||||
|
||||
### Root Cause
|
||||
|
||||
User or service account lacks `services/proxy` permission on `polaris-dashboard` service in the `polaris` namespace.
|
||||
|
||||
### Solution
|
||||
@@ -96,11 +84,13 @@ User or service account lacks `services/proxy` permission on `polaris-dashboard`
|
||||
**1. Verify RBAC Configuration**
|
||||
|
||||
Check if Role exists:
|
||||
|
||||
```bash
|
||||
kubectl get role polaris-proxy-reader -n polaris -o yaml
|
||||
```
|
||||
|
||||
Expected output:
|
||||
|
||||
```yaml
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
@@ -108,20 +98,22 @@ metadata:
|
||||
name: polaris-proxy-reader
|
||||
namespace: polaris
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["services/proxy"]
|
||||
resourceNames: ["polaris-dashboard"]
|
||||
verbs: ["get"]
|
||||
- apiGroups: ['']
|
||||
resources: ['services/proxy']
|
||||
resourceNames: ['polaris-dashboard']
|
||||
verbs: ['get']
|
||||
```
|
||||
|
||||
**2. Verify RoleBinding**
|
||||
|
||||
For service account mode:
|
||||
|
||||
```bash
|
||||
kubectl get rolebinding headlamp-polaris-proxy -n polaris -o yaml
|
||||
```
|
||||
|
||||
Expected subjects:
|
||||
|
||||
```yaml
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
@@ -130,6 +122,7 @@ subjects:
|
||||
```
|
||||
|
||||
For OIDC mode:
|
||||
|
||||
```bash
|
||||
kubectl get rolebinding -n polaris -o yaml | grep -A 5 polaris-proxy-reader
|
||||
```
|
||||
@@ -172,6 +165,7 @@ EOF
|
||||
**4. Test RBAC Permissions**
|
||||
|
||||
Service account mode:
|
||||
|
||||
```bash
|
||||
# Impersonate Headlamp service account
|
||||
kubectl auth can-i get services/proxy \
|
||||
@@ -182,6 +176,7 @@ kubectl auth can-i get services/proxy \
|
||||
```
|
||||
|
||||
OIDC mode (test as yourself):
|
||||
|
||||
```bash
|
||||
kubectl auth can-i get services/proxy \
|
||||
--resource-name=polaris-dashboard \
|
||||
@@ -192,6 +187,7 @@ kubectl auth can-i get services/proxy \
|
||||
**5. Restart Headlamp**
|
||||
|
||||
After applying RBAC changes:
|
||||
|
||||
```bash
|
||||
kubectl rollout restart deployment headlamp -n kube-system
|
||||
```
|
||||
@@ -201,11 +197,13 @@ kubectl rollout restart deployment headlamp -n kube-system
|
||||
## 404 Not Found Error
|
||||
|
||||
### Symptoms
|
||||
|
||||
- Error message: "Error loading Polaris audit data: 404 Not Found"
|
||||
- Service proxy request returns 404
|
||||
- Polaris dashboard not reachable
|
||||
|
||||
### Root Cause
|
||||
|
||||
Polaris dashboard service doesn't exist or is in a different namespace.
|
||||
|
||||
### Solution
|
||||
@@ -213,12 +211,14 @@ Polaris dashboard service doesn't exist or is in a different namespace.
|
||||
**1. Verify Polaris Installation**
|
||||
|
||||
Check if Polaris is installed:
|
||||
|
||||
```bash
|
||||
kubectl get pods -n polaris
|
||||
# Expected: polaris-dashboard-* pod running
|
||||
```
|
||||
|
||||
Check if service exists:
|
||||
|
||||
```bash
|
||||
kubectl get service polaris-dashboard -n polaris
|
||||
# Expected: ClusterIP service on port 80
|
||||
@@ -227,6 +227,7 @@ kubectl get service polaris-dashboard -n polaris
|
||||
**2. Verify Service Name and Port**
|
||||
|
||||
The plugin expects:
|
||||
|
||||
- **Namespace**: `polaris`
|
||||
- **Service Name**: `polaris-dashboard`
|
||||
- **Port**: `80` (or named port `dashboard`)
|
||||
@@ -246,11 +247,13 @@ If this returns 404, Polaris service is not configured correctly.
|
||||
**4. Check Polaris Dashboard Configuration**
|
||||
|
||||
Verify Polaris is running with dashboard enabled:
|
||||
|
||||
```bash
|
||||
kubectl get deployment polaris-dashboard -n polaris -o yaml | grep -A 5 dashboard
|
||||
```
|
||||
|
||||
If `dashboard.enabled: false` in Helm values, enable it:
|
||||
|
||||
```yaml
|
||||
# values.yaml
|
||||
dashboard:
|
||||
@@ -260,6 +263,7 @@ dashboard:
|
||||
**5. Reinstall Polaris**
|
||||
|
||||
If Polaris is missing or misconfigured:
|
||||
|
||||
```bash
|
||||
helm repo add fairwinds-stable https://charts.fairwinds.com/stable
|
||||
helm upgrade --install polaris fairwinds-stable/polaris \
|
||||
@@ -273,21 +277,25 @@ helm upgrade --install polaris fairwinds-stable/polaris \
|
||||
## Plugin Settings Page Empty
|
||||
|
||||
### Symptoms
|
||||
|
||||
- Settings → Polaris shows title but no content
|
||||
- Refresh interval and dashboard URL fields not visible
|
||||
|
||||
### Root Cause (Fixed in v0.3.3)
|
||||
|
||||
Plugin settings registration name didn't match `package.json` name.
|
||||
|
||||
### Solution
|
||||
|
||||
Upgrade to v0.3.3 or later:
|
||||
|
||||
```bash
|
||||
# Via Headlamp UI: Settings → Plugins → Update
|
||||
# Or redeploy with latest version
|
||||
```
|
||||
|
||||
If manually installing, ensure plugin name matches `package.json`:
|
||||
|
||||
```typescript
|
||||
registerPluginSettings('headlamp-polaris-plugin', PolarisSettings, true);
|
||||
// NOT 'polaris' — must match package.json name
|
||||
@@ -298,6 +306,7 @@ registerPluginSettings('headlamp-polaris-plugin', PolarisSettings, true);
|
||||
## Dark Mode Issues
|
||||
|
||||
### Symptoms
|
||||
|
||||
- Drawer background remains white in dark mode
|
||||
- Text is hard to read in dark mode
|
||||
- Theme colors don't match Headlamp UI
|
||||
@@ -308,6 +317,7 @@ Upgrade to v0.3.5 or later for complete dark mode support.
|
||||
|
||||
**Verify CSS Variables**:
|
||||
The plugin uses MUI CSS variables for theming:
|
||||
|
||||
- `--mui-palette-background-default` (drawer background)
|
||||
- `--mui-palette-text-primary` (text color)
|
||||
- `--mui-palette-primary-main` (links, buttons)
|
||||
@@ -317,6 +327,7 @@ These automatically adapt to Headlamp's theme (light/dark/system).
|
||||
|
||||
**Hard Refresh Required**:
|
||||
After upgrading from v0.3.4 or earlier, hard refresh your browser:
|
||||
|
||||
- macOS: Cmd+Shift+R
|
||||
- Linux/Windows: Ctrl+Shift+R
|
||||
|
||||
@@ -328,6 +339,7 @@ If hard refresh doesn't help, clear cache for Headlamp domain.
|
||||
## Data Not Loading / Infinite Spinner
|
||||
|
||||
### Symptoms
|
||||
|
||||
- Plugin shows "Loading Polaris audit data..." forever
|
||||
- No error message in UI
|
||||
- Data never appears
|
||||
@@ -339,6 +351,7 @@ If hard refresh doesn't help, clear cache for Headlamp domain.
|
||||
Open DevTools (F12) → Console tab.
|
||||
|
||||
Look for:
|
||||
|
||||
- Network errors (CORS, timeouts, 5xx responses)
|
||||
- JavaScript errors
|
||||
- Failed API requests
|
||||
@@ -348,6 +361,7 @@ Look for:
|
||||
Open DevTools → Network tab → Filter by "results.json"
|
||||
|
||||
Expected request:
|
||||
|
||||
```
|
||||
GET /api/v1/namespaces/polaris/services/polaris-dashboard:80/proxy/results.json
|
||||
Status: 200
|
||||
@@ -355,6 +369,7 @@ Response: JSON data
|
||||
```
|
||||
|
||||
Common issues:
|
||||
|
||||
- **Status 0 / Failed**: Network policy blocking request
|
||||
- **Status 403**: RBAC issue (see [403 Forbidden Error](#403-forbidden-error))
|
||||
- **Status 404**: Service not found (see [404 Not Found Error](#404-not-found-error))
|
||||
@@ -378,6 +393,7 @@ curl http://localhost:8080/results.json
|
||||
**4. Check Network Policies**
|
||||
|
||||
If your cluster uses NetworkPolicies:
|
||||
|
||||
```bash
|
||||
kubectl get networkpolicy -n polaris
|
||||
```
|
||||
@@ -385,6 +401,7 @@ kubectl get networkpolicy -n polaris
|
||||
Ensure API server (or Headlamp pod) can reach Polaris dashboard.
|
||||
|
||||
**Example fix**:
|
||||
|
||||
```yaml
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
@@ -399,7 +416,7 @@ spec:
|
||||
- Ingress
|
||||
ingress:
|
||||
- from:
|
||||
- namespaceSelector: {} # Allow from all namespaces (API server)
|
||||
- namespaceSelector: {} # Allow from all namespaces (API server)
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 8080
|
||||
@@ -408,6 +425,7 @@ spec:
|
||||
**5. Increase Timeout / Disable Auto-Refresh**
|
||||
|
||||
If Polaris responds slowly:
|
||||
|
||||
- Open Settings → Polaris
|
||||
- Increase refresh interval to 10+ minutes
|
||||
- Or set to "Manual only" to disable auto-refresh
|
||||
@@ -423,6 +441,7 @@ If Polaris responds slowly:
|
||||
**Cause**: Network request failed (CORS, network policy, timeout)
|
||||
|
||||
**Solution**:
|
||||
|
||||
1. Check Network tab for actual HTTP status
|
||||
2. Verify network policies allow API server → Polaris
|
||||
3. Check Polaris pod is running
|
||||
@@ -434,6 +453,7 @@ If Polaris responds slowly:
|
||||
**Cause**: API returned HTML (error page) instead of JSON
|
||||
|
||||
**Solution**:
|
||||
|
||||
1. Check Network tab response body (likely 404 or 500 error page)
|
||||
2. Verify Polaris service exists and is healthy
|
||||
3. Check service proxy URL is correct
|
||||
@@ -453,6 +473,7 @@ If Polaris responds slowly:
|
||||
**Cause**: Polaris returned empty or malformed response
|
||||
|
||||
**Solution**:
|
||||
|
||||
1. Check Polaris logs for errors
|
||||
2. Verify Polaris is scanning the cluster (check audit timestamp)
|
||||
3. Test `/results.json` endpoint directly
|
||||
@@ -538,11 +559,13 @@ kubectl logs -n kube-system kube-apiserver-* | grep polaris-dashboard
|
||||
### Sidecar Fails to Install Plugin
|
||||
|
||||
**Symptoms**:
|
||||
|
||||
- Plugin sidecar logs show download errors
|
||||
- Plugin directory is empty
|
||||
- Settings → Plugins shows nothing
|
||||
|
||||
**Check sidecar logs**:
|
||||
|
||||
```bash
|
||||
kubectl logs -n kube-system deployment/headlamp -c headlamp-plugin
|
||||
```
|
||||
@@ -566,13 +589,15 @@ Error: 404 Not Found
|
||||
```
|
||||
|
||||
**Solution**: Verify `archive-url` in plugin config matches GitHub release:
|
||||
|
||||
```bash
|
||||
kubectl get configmap headlamp-plugin-config -n kube-system -o yaml
|
||||
```
|
||||
|
||||
Expected format:
|
||||
|
||||
```
|
||||
https://github.com/cpfarhood/headlamp-polaris-plugin/releases/download/v0.3.5/headlamp-polaris-plugin-0.3.5.tar.gz
|
||||
https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/download/v0.3.10/polaris-0.3.10.tar.gz
|
||||
```
|
||||
|
||||
---
|
||||
@@ -580,6 +605,7 @@ https://github.com/cpfarhood/headlamp-polaris-plugin/releases/download/v0.3.5/he
|
||||
**3. Permission denied writing to /headlamp/plugins**
|
||||
|
||||
**Solution**: Ensure volume mount is writable:
|
||||
|
||||
```yaml
|
||||
volumeMounts:
|
||||
- name: plugins
|
||||
@@ -591,17 +617,18 @@ volumeMounts:
|
||||
### Plugin Manager Not Working
|
||||
|
||||
**Symptoms**:
|
||||
|
||||
- Headlamp → Settings → Plugins shows "Catalog" tab but plugins don't install
|
||||
- "Install" button does nothing
|
||||
|
||||
**Root Cause**: Plugin manager requires `config.pluginsDir` to be set.
|
||||
|
||||
**Solution**: Configure Headlamp for plugin manager:
|
||||
|
||||
```yaml
|
||||
# HelmRelease values
|
||||
config:
|
||||
pluginsDir: /headlamp/plugins
|
||||
watchPlugins: false # CRITICAL for v0.39.0+
|
||||
```
|
||||
|
||||
---
|
||||
@@ -609,25 +636,30 @@ config:
|
||||
## ArtifactHub Sync Delays
|
||||
|
||||
### Symptoms
|
||||
|
||||
- New version released on GitHub but not showing in ArtifactHub
|
||||
- Headlamp plugin catalog shows old version
|
||||
|
||||
### Root Cause
|
||||
|
||||
ArtifactHub pulls metadata every 30 minutes. There is no webhook or push mechanism.
|
||||
|
||||
### Solution
|
||||
|
||||
**Wait 30 minutes** after pushing a GitHub release, then check:
|
||||
|
||||
```
|
||||
https://artifacthub.io/packages/headlamp/headlamp-polaris-plugin/headlamp-polaris-plugin
|
||||
```
|
||||
|
||||
**Verify metadata**:
|
||||
|
||||
1. Check `artifacthub-pkg.yml` is in repository root
|
||||
2. Check `headlamp/plugin/archive-url` points to GitHub release
|
||||
3. Check `headlamp/plugin/archive-checksum` matches tarball SHA256
|
||||
|
||||
**Force sync** (ArtifactHub UI):
|
||||
|
||||
- Log in to ArtifactHub as package maintainer
|
||||
- Go to package settings
|
||||
- Click "Reindex now"
|
||||
@@ -643,23 +675,28 @@ If none of these solutions work, gather debugging information and open an issue:
|
||||
### Required Information
|
||||
|
||||
1. **Version Information**:
|
||||
|
||||
```bash
|
||||
kubectl get pods -n kube-system -l app.kubernetes.io/name=headlamp -o yaml | grep image:
|
||||
```
|
||||
|
||||
2. **Plugin Version**:
|
||||
|
||||
- Check Settings → Plugins in Headlamp UI
|
||||
- Or: `kubectl exec -n kube-system deployment/headlamp -c headlamp -- cat /headlamp/plugins/headlamp-polaris-plugin/package.json`
|
||||
|
||||
3. **Browser Console Output**:
|
||||
|
||||
- Open DevTools (F12) → Console
|
||||
- Screenshot or copy errors
|
||||
|
||||
4. **Network Tab**:
|
||||
|
||||
- Open DevTools → Network
|
||||
- Screenshot failed requests to `results.json`
|
||||
|
||||
5. **Pod Logs**:
|
||||
|
||||
```bash
|
||||
kubectl logs -n kube-system deployment/headlamp -c headlamp --tail=100
|
||||
kubectl logs -n polaris deployment/polaris-dashboard --tail=100
|
||||
@@ -672,7 +709,7 @@ If none of these solutions work, gather debugging information and open an issue:
|
||||
|
||||
### Where to Get Help
|
||||
|
||||
- **GitHub Issues**: [https://github.com/cpfarhood/headlamp-polaris-plugin/issues](https://github.com/cpfarhood/headlamp-polaris-plugin/issues)
|
||||
- **GitHub Discussions**: [https://github.com/cpfarhood/headlamp-polaris-plugin/discussions](https://github.com/cpfarhood/headlamp-polaris-plugin/discussions)
|
||||
- **GitHub Issues**: [https://github.com/privilegedescalation/headlamp-polaris-plugin/issues](https://github.com/privilegedescalation/headlamp-polaris-plugin/issues)
|
||||
- **GitHub Discussions**: [https://github.com/privilegedescalation/headlamp-polaris-plugin/discussions](https://github.com/privilegedescalation/headlamp-polaris-plugin/discussions)
|
||||
|
||||
Include the debugging information above when opening an issue.
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
## 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)
|
||||
@@ -16,12 +17,14 @@ The Headlamp Polaris Plugin needs to fetch Polaris audit data once and share it
|
||||
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
|
||||
@@ -32,6 +35,7 @@ Multiple state management approaches are available: Redux, Zustand, Jotai, Recoi
|
||||
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
|
||||
@@ -67,12 +71,14 @@ Use **React Context API** (built-in, no dependencies) for shared state managemen
|
||||
### 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)
|
||||
@@ -83,11 +89,13 @@ Use **React Context API** (built-in, no dependencies) for shared state managemen
|
||||
### 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
|
||||
@@ -97,11 +105,13 @@ Use **React Context API** (built-in, no dependencies) for shared state managemen
|
||||
### 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
|
||||
@@ -112,10 +122,12 @@ Use **React Context API** (built-in, no dependencies) for shared state managemen
|
||||
### 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
|
||||
@@ -126,6 +138,7 @@ Use **React Context API** (built-in, no dependencies) for shared state managemen
|
||||
## Implementation Details
|
||||
|
||||
**Context Definition:**
|
||||
|
||||
```typescript
|
||||
interface PolarisDataContextValue {
|
||||
data: AuditData | null;
|
||||
@@ -138,6 +151,7 @@ const PolarisDataContext = React.createContext<PolarisDataContextValue | undefin
|
||||
```
|
||||
|
||||
**Provider Implementation:**
|
||||
|
||||
```typescript
|
||||
export function PolarisDataProvider({ children }: { children: React.ReactNode }) {
|
||||
const [data, setData] = useState<AuditData | null>(null);
|
||||
@@ -163,6 +177,7 @@ export function PolarisDataProvider({ children }: { children: React.ReactNode })
|
||||
```
|
||||
|
||||
**Consumer Hook:**
|
||||
|
||||
```typescript
|
||||
export function usePolarisDataContext() {
|
||||
const context = useContext(PolarisDataContext);
|
||||
@@ -176,6 +191,7 @@ export function usePolarisDataContext() {
|
||||
## 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)
|
||||
@@ -184,6 +200,7 @@ export function usePolarisDataContext() {
|
||||
- ✅ 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
|
||||
@@ -200,6 +217,6 @@ export function usePolarisDataContext() {
|
||||
|
||||
## Revision History
|
||||
|
||||
| Date | Author | Change |
|
||||
|------|--------|--------|
|
||||
| Date | Author | Change |
|
||||
| ---------- | ----------- | ---------------- |
|
||||
| 2026-02-12 | Plugin Team | Initial decision |
|
||||
|
||||
@@ -41,17 +41,21 @@ What is the change that we're proposing and/or doing?
|
||||
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...
|
||||
@@ -63,8 +67,8 @@ What becomes easier or more difficult to do because of this change?
|
||||
|
||||
## ADR Index
|
||||
|
||||
| ADR | Title | Status | Date |
|
||||
|-----|-------|--------|------|
|
||||
| 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.
|
||||
|
||||
@@ -212,46 +212,46 @@ If no match found:
|
||||
|
||||
```typescript
|
||||
interface AuditData {
|
||||
PolarisOutputVersion: string; // "1.0"
|
||||
AuditTime: string; // ISO 8601 timestamp
|
||||
SourceType: string; // "Cluster"
|
||||
SourceName: string; // Cluster identifier
|
||||
DisplayName: string; // Human-readable name
|
||||
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
|
||||
Version: string; // K8s version
|
||||
Nodes: number;
|
||||
Pods: number;
|
||||
Namespaces: number;
|
||||
Controllers: number;
|
||||
};
|
||||
Results: Result[]; // Array of resource audit results
|
||||
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
|
||||
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
|
||||
Results: ResultSet; // Pod-level checks
|
||||
ContainerResults: {
|
||||
Name: string;
|
||||
Results: ResultSet; // Container-level checks
|
||||
Results: ResultSet; // Container-level checks
|
||||
}[];
|
||||
};
|
||||
CreatedTime: string; // ISO 8601 timestamp
|
||||
CreatedTime: string; // ISO 8601 timestamp
|
||||
}
|
||||
|
||||
type ResultSet = Record<string, ResultMessage>;
|
||||
|
||||
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.
|
||||
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.
|
||||
}
|
||||
```
|
||||
|
||||
@@ -259,11 +259,11 @@ interface ResultMessage {
|
||||
|
||||
```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"
|
||||
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"
|
||||
}
|
||||
```
|
||||
|
||||
@@ -361,21 +361,25 @@ function getNamespaces(data: AuditData): string[] {
|
||||
## 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
|
||||
|
||||
@@ -7,14 +7,16 @@ Key architectural choices and their rationale for the Headlamp Polaris Plugin.
|
||||
**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
|
||||
-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
|
||||
@@ -22,10 +24,12 @@ Use service proxy path: `/api/v1/namespaces/polaris/services/polaris-dashboard:8
|
||||
- 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)
|
||||
|
||||
@@ -34,6 +38,7 @@ Use service proxy path: `/api/v1/namespaces/polaris/services/polaris-dashboard:8
|
||||
**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
|
||||
|
||||
@@ -41,16 +46,19 @@ Use service proxy path: `/api/v1/namespaces/polaris/services/polaris-dashboard:8
|
||||
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)
|
||||
@@ -60,6 +68,7 @@ Use React Context with `PolarisDataProvider`
|
||||
**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
|
||||
|
||||
@@ -67,16 +76,19 @@ Use React Context with `PolarisDataProvider`
|
||||
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)
|
||||
|
||||
@@ -85,6 +97,7 @@ Use drawer with URL hash (`/polaris/namespaces#kube-system`)
|
||||
**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
|
||||
|
||||
@@ -92,20 +105,24 @@ Use drawer with URL hash (`/polaris/namespaces#kube-system`)
|
||||
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 (`<button>`, `<div>`) with inline styles
|
||||
- Use theme-aware CSS variables (`--mui-palette-background-paper`)
|
||||
|
||||
**Trade-offs:**
|
||||
|
||||
- ✅ **Pros:** No runtime errors, smaller bundle, consistent with Headlamp
|
||||
- ❌ **Cons:** Limited component variety, inline styles verbose
|
||||
|
||||
**Alternatives Considered:**
|
||||
|
||||
- Bundle full MUI → Rejected (huge bundle size, version conflicts)
|
||||
- Use Headlamp's MUI exports → Rejected (incomplete, undocumented)
|
||||
|
||||
@@ -114,6 +131,7 @@ Use only Headlamp CommonComponents or HTML elements with inline styles
|
||||
**Decision:** Sidebar has "Polaris" → "Overview" and "Namespaces" (2 levels max)
|
||||
|
||||
**Context:**
|
||||
|
||||
- Plugin needs hierarchical navigation
|
||||
- Headlamp sidebar supports limited nesting depth
|
||||
|
||||
@@ -121,19 +139,23 @@ Use only Headlamp CommonComponents or HTML elements with inline styles
|
||||
Use 2-level sidebar: `Polaris` (parent) → `Overview`, `Namespaces` (children)
|
||||
|
||||
**Rationale:**
|
||||
|
||||
- Headlamp sidebar `Collapse` component only supports 2 levels
|
||||
- Deeper nesting (Polaris → Namespaces → <each namespace>) doesn't work
|
||||
- Sidebar collapse is route-based, not click-to-toggle
|
||||
|
||||
**Workaround:**
|
||||
|
||||
- Namespace navigation via table (NamespacesListView)
|
||||
- Clickable namespace buttons open drawer (not new route)
|
||||
|
||||
**Trade-offs:**
|
||||
|
||||
- ✅ **Pros:** Works within Headlamp constraints
|
||||
- ❌ **Cons:** Can't have dynamic per-namespace sidebar entries
|
||||
|
||||
**Alternatives Considered:**
|
||||
|
||||
- Dynamic sidebar with namespace entries → Rejected (Headlamp limitation)
|
||||
- Flat sidebar (no nesting) → Rejected (poor UX for plugin with multiple views)
|
||||
|
||||
@@ -142,6 +164,7 @@ Use 2-level sidebar: `Polaris` (parent) → `Overview`, `Namespaces` (children)
|
||||
**Decision:** Enable all TypeScript strict checks
|
||||
|
||||
**Configuration:**
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
@@ -155,12 +178,14 @@ Use 2-level sidebar: `Polaris` (parent) → `Overview`, `Namespaces` (children)
|
||||
```
|
||||
|
||||
**Rationale:**
|
||||
|
||||
- Catch errors at compile time (not runtime)
|
||||
- Better IDE support and autocomplete
|
||||
- Enforces type safety (no `any`, no implicit unknowns)
|
||||
- Easier refactoring (type errors surface immediately)
|
||||
|
||||
**Trade-offs:**
|
||||
|
||||
- ✅ **Pros:** Fewer runtime errors, better maintainability, self-documenting code
|
||||
- ❌ **Cons:** More verbose code, steeper learning curve
|
||||
|
||||
@@ -169,6 +194,7 @@ Use 2-level sidebar: `Polaris` (parent) → `Overview`, `Namespaces` (children)
|
||||
**Decision:** Default refresh interval is 5 minutes (configurable 1-30 min)
|
||||
|
||||
**Context:**
|
||||
|
||||
- Plugin needs to refresh Polaris data periodically
|
||||
- Polaris audits typically run every 10-30 minutes
|
||||
|
||||
@@ -176,15 +202,18 @@ Use 2-level sidebar: `Polaris` (parent) → `Overview`, `Namespaces` (children)
|
||||
Default to 5 minutes, allow user to configure (1 / 5 / 10 / 30 minutes)
|
||||
|
||||
**Rationale:**
|
||||
|
||||
- Balance between data freshness and API load
|
||||
- Polaris audits don't change frequently (10-30 min intervals)
|
||||
- 5 minutes provides reasonably fresh data without excessive API calls
|
||||
|
||||
**Trade-offs:**
|
||||
|
||||
- ✅ **Pros:** Reasonable default, user-configurable, low API load
|
||||
- ❌ **Cons:** Not real-time (acceptable for audit data)
|
||||
|
||||
**Alternatives Considered:**
|
||||
|
||||
- WebSocket/SSE for real-time → Rejected (Polaris dashboard doesn't support)
|
||||
- 1 minute default → Rejected (unnecessary API calls, audit data changes slowly)
|
||||
- 30 minute default → Rejected (too stale for interactive dashboard)
|
||||
@@ -194,6 +223,7 @@ Default to 5 minutes, allow user to configure (1 / 5 / 10 / 30 minutes)
|
||||
**Decision:** Plugin is read-only (no write operations)
|
||||
|
||||
**Context:**
|
||||
|
||||
- Plugin could potentially modify Polaris configuration or add exemptions
|
||||
- Write operations require additional RBAC permissions (PATCH, CREATE)
|
||||
|
||||
@@ -201,16 +231,19 @@ Default to 5 minutes, allow user to configure (1 / 5 / 10 / 30 minutes)
|
||||
Plugin only performs GET requests (read-only)
|
||||
|
||||
**Rationale:**
|
||||
|
||||
- **Security:** Minimal RBAC footprint (`get` on `services/proxy` only)
|
||||
- **Simplicity:** No mutation logic, error handling for writes, or rollback
|
||||
- **Polaris design:** Exemptions managed via annotations (outside plugin scope)
|
||||
- **Future:** Can add writes later if user demand exists
|
||||
|
||||
**Trade-offs:**
|
||||
|
||||
- ✅ **Pros:** Minimal permissions, simpler code, fewer failure modes
|
||||
- ❌ **Cons:** Cannot add exemptions via UI (must edit annotations manually)
|
||||
|
||||
**Future Enhancement:**
|
||||
|
||||
- Add PATCH permission for workload annotations
|
||||
- Implement `ExemptionManager` component (UI exists, not integrated)
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ High-level architecture of the Headlamp Polaris Plugin.
|
||||
The Headlamp Polaris Plugin is a **read-only dashboard** that surfaces Fairwinds Polaris audit results within the Headlamp UI. It fetches data from the Polaris dashboard API via the Kubernetes service proxy and presents it in a hierarchical navigation structure.
|
||||
|
||||
**Key Characteristics:**
|
||||
|
||||
- **Read-only:** No write operations to cluster or Polaris
|
||||
- **Service proxy based:** Uses K8s API server proxy to reach Polaris
|
||||
- **React Context for state:** Shared data fetch across components
|
||||
@@ -32,7 +33,7 @@ The Headlamp Polaris Plugin is a **read-only dashboard** that surfaces Fairwinds
|
||||
│ └────────┬────────┘ │
|
||||
│ │ │
|
||||
│ ┌─────────────▼──────────────┐ │
|
||||
│ │ Polaris Plugin (This!) │ │
|
||||
│ │ Polaris Plugin │ │
|
||||
│ ├────────────────────────────┤ │
|
||||
│ │ • registerSidebarEntry │ │
|
||||
│ │ • registerRoute │ │
|
||||
@@ -91,6 +92,7 @@ The Headlamp Polaris Plugin is a **read-only dashboard** that surfaces Fairwinds
|
||||
### Plugin Entry Point
|
||||
|
||||
**`src/index.tsx`**
|
||||
|
||||
- Registers sidebar entries (Polaris → Overview, Namespaces)
|
||||
- Registers routes (`/polaris`, `/polaris/namespaces`)
|
||||
- Registers app bar action (score badge)
|
||||
@@ -100,22 +102,26 @@ The Headlamp Polaris Plugin is a **read-only dashboard** that surfaces Fairwinds
|
||||
### Data Layer
|
||||
|
||||
**`src/api/PolarisDataContext.tsx`**
|
||||
|
||||
- React Context Provider for shared data
|
||||
- Fetches AuditData from Polaris dashboard
|
||||
- Handles auto-refresh based on user settings
|
||||
- Provides `{ data, loading, error, refresh }` to consumers
|
||||
|
||||
**`src/api/polaris.ts`**
|
||||
|
||||
- TypeScript types for AuditData schema
|
||||
- Utility functions: `countResults()`, `computeScore()`
|
||||
- Settings management: `getRefreshInterval()`, `setRefreshInterval()`
|
||||
- Constants: `DASHBOARD_URL_DEFAULT`, `INTERVAL_OPTIONS`
|
||||
|
||||
**`src/api/checkMapping.ts`**
|
||||
|
||||
- Maps Polaris check IDs to human-readable names
|
||||
- Used for display in UI (e.g., "hostIPCSet" → "Host IPC")
|
||||
|
||||
**`src/api/topIssues.ts`**
|
||||
|
||||
- Aggregates failing checks across cluster
|
||||
- Groups by check ID and severity
|
||||
- Used for top issues dashboard
|
||||
@@ -123,6 +129,7 @@ The Headlamp Polaris Plugin is a **read-only dashboard** that surfaces Fairwinds
|
||||
### View Components
|
||||
|
||||
**`src/components/DashboardView.tsx`**
|
||||
|
||||
- **Route:** `/polaris`
|
||||
- **Purpose:** Cluster-wide overview
|
||||
- **Features:**
|
||||
@@ -133,6 +140,7 @@ The Headlamp Polaris Plugin is a **read-only dashboard** that surfaces Fairwinds
|
||||
- **Data:** Uses `usePolarisDataContext()`
|
||||
|
||||
**`src/components/NamespacesListView.tsx`**
|
||||
|
||||
- **Route:** `/polaris/namespaces`
|
||||
- **Purpose:** List all namespaces with scores
|
||||
- **Features:**
|
||||
@@ -142,6 +150,7 @@ The Headlamp Polaris Plugin is a **read-only dashboard** that surfaces Fairwinds
|
||||
- **Data:** Uses `usePolarisDataContext()`, aggregates by namespace
|
||||
|
||||
**`src/components/NamespaceDetailView.tsx`**
|
||||
|
||||
- **Route:** Drawer on `/polaris/namespaces#<namespace>`
|
||||
- **Purpose:** Namespace-level drill-down
|
||||
- **Features:**
|
||||
@@ -154,6 +163,7 @@ The Headlamp Polaris Plugin is a **read-only dashboard** that surfaces Fairwinds
|
||||
### UI Components
|
||||
|
||||
**`src/components/AppBarScoreBadge.tsx`**
|
||||
|
||||
- **Location:** Headlamp app bar (top-right)
|
||||
- **Purpose:** Quick cluster score visibility
|
||||
- **Features:**
|
||||
@@ -163,6 +173,7 @@ The Headlamp Polaris Plugin is a **read-only dashboard** that surfaces Fairwinds
|
||||
- **Data:** Uses `usePolarisDataContext()`
|
||||
|
||||
**`src/components/PolarisSettings.tsx`**
|
||||
|
||||
- **Location:** Settings → Plugins → Polaris
|
||||
- **Purpose:** Plugin configuration
|
||||
- **Features:**
|
||||
@@ -172,6 +183,7 @@ The Headlamp Polaris Plugin is a **read-only dashboard** that surfaces Fairwinds
|
||||
- **Data:** localStorage for persistence
|
||||
|
||||
**`src/components/InlineAuditSection.tsx`**
|
||||
|
||||
- **Location:** Resource detail pages (Deployment, StatefulSet, etc.)
|
||||
- **Purpose:** Show Polaris audit inline
|
||||
- **Features:**
|
||||
@@ -181,6 +193,7 @@ The Headlamp Polaris Plugin is a **read-only dashboard** that surfaces Fairwinds
|
||||
- **Data:** Uses `usePolarisDataContext()`, filters by resource
|
||||
|
||||
**`src/components/ExemptionManager.tsx`**
|
||||
|
||||
- **Location:** (Planned feature, UI exists but not fully integrated)
|
||||
- **Purpose:** Manage Polaris exemptions via annotations
|
||||
- **Features:**
|
||||
@@ -195,6 +208,7 @@ The Headlamp Polaris Plugin is a **read-only dashboard** that surfaces Fairwinds
|
||||
**Decision:** Use React Context instead of Redux/Zustand
|
||||
|
||||
**Rationale:**
|
||||
|
||||
1. **Simple state:** Single AuditData object shared across views
|
||||
2. **Read-only:** No complex mutations or transactions
|
||||
3. **Headlamp constraints:** Plugin cannot add dependencies (Redux not bundled)
|
||||
@@ -204,10 +218,10 @@ The Headlamp Polaris Plugin is a **read-only dashboard** that surfaces Fairwinds
|
||||
|
||||
```typescript
|
||||
interface PolarisDataContextValue {
|
||||
data: AuditData | null; // Audit results or null if loading/error
|
||||
loading: boolean; // True during initial fetch
|
||||
error: string | null; // Error message if fetch failed
|
||||
refresh: () => void; // Manual refresh function
|
||||
data: AuditData | null; // Audit results or null if loading/error
|
||||
loading: boolean; // True during initial fetch
|
||||
error: string | null; // Error message if fetch failed
|
||||
refresh: () => void; // Manual refresh function
|
||||
}
|
||||
```
|
||||
|
||||
@@ -221,6 +235,7 @@ interface PolarisDataContextValue {
|
||||
### localStorage Usage
|
||||
|
||||
Settings persisted in localStorage:
|
||||
|
||||
- **`polaris-plugin-refresh-interval`**: Number (seconds), default 300
|
||||
- **`polaris-plugin-dashboard-url`**: String, default service proxy path
|
||||
|
||||
@@ -236,28 +251,30 @@ No sensitive data stored in localStorage.
|
||||
|
||||
```typescript
|
||||
// Sidebar navigation
|
||||
registerSidebarEntry({ parent, name, label, url, icon })
|
||||
registerSidebarEntry({ parent, name, label, url, icon });
|
||||
|
||||
// Routes
|
||||
registerRoute({ path, sidebar, name, exact, component })
|
||||
registerRoute({ path, sidebar, name, exact, component });
|
||||
|
||||
// App bar actions
|
||||
registerAppBarAction(component)
|
||||
registerAppBarAction(component);
|
||||
|
||||
// Plugin settings
|
||||
registerPluginSettings(name, component, displaySaveButton)
|
||||
registerPluginSettings(name, component, displaySaveButton);
|
||||
|
||||
// Resource detail sections
|
||||
registerDetailsViewSection(component)
|
||||
registerDetailsViewSection(component);
|
||||
```
|
||||
|
||||
**Key Changes in v0.13.0:**
|
||||
|
||||
- `registerDetailsViewSection` now takes 1 argument (component), not 2 (name, component)
|
||||
- `registerAppBarAction` now takes 1 argument (component), not 2 (name, component)
|
||||
|
||||
### Headlamp CommonComponents
|
||||
|
||||
**Used Components:**
|
||||
|
||||
- `SectionBox` - Card-like container with title
|
||||
- `SectionHeader` - Page header with title
|
||||
- `StatusLabel` - Color-coded status badges
|
||||
@@ -267,16 +284,19 @@ registerDetailsViewSection(component)
|
||||
- `Loader` - Loading spinner
|
||||
|
||||
**Router:**
|
||||
|
||||
- `Router.createRouteURL()` - Generate plugin route URLs
|
||||
- React Router's `useHistory()`, `useParams()`, `useLocation()`
|
||||
|
||||
### Kubernetes API (via ApiProxy)
|
||||
|
||||
**Used for:**
|
||||
|
||||
- Fetching Polaris results: `ApiProxy.request(dashboardUrl + 'results.json')`
|
||||
- No direct K8s API calls (all data from Polaris dashboard)
|
||||
|
||||
**RBAC Required:**
|
||||
|
||||
- `get` on `services/proxy` for `polaris-dashboard` in `polaris` namespace
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
+13
-20
@@ -31,7 +31,6 @@ helm repo update
|
||||
# headlamp-values.yaml
|
||||
config:
|
||||
pluginsDir: /headlamp/plugins
|
||||
watchPlugins: false # CRITICAL for v0.39.0+
|
||||
|
||||
pluginsManager:
|
||||
enabled: true
|
||||
@@ -63,9 +62,8 @@ image:
|
||||
pullPolicy: IfNotPresent
|
||||
|
||||
config:
|
||||
baseURL: ""
|
||||
baseURL: ''
|
||||
pluginsDir: /headlamp/plugins
|
||||
watchPlugins: false # MUST be false for plugin manager
|
||||
|
||||
pluginsManager:
|
||||
enabled: true
|
||||
@@ -81,7 +79,7 @@ ingress:
|
||||
className: nginx
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
|
||||
nginx.ingress.kubernetes.io/force-ssl-redirect: 'true'
|
||||
hosts:
|
||||
- host: headlamp.example.com
|
||||
paths:
|
||||
@@ -117,16 +115,16 @@ affinity:
|
||||
# OIDC Authentication (optional)
|
||||
env:
|
||||
- name: HEADLAMP_CONFIG_OIDC_CLIENT_ID
|
||||
value: "headlamp"
|
||||
value: 'headlamp'
|
||||
- name: HEADLAMP_CONFIG_OIDC_CLIENT_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: headlamp-oidc
|
||||
key: client-secret
|
||||
- name: HEADLAMP_CONFIG_OIDC_ISSUER_URL
|
||||
value: "https://auth.example.com/realms/kubernetes"
|
||||
value: 'https://auth.example.com/realms/kubernetes'
|
||||
- name: HEADLAMP_CONFIG_OIDC_SCOPES
|
||||
value: "openid,profile,email,groups"
|
||||
value: 'openid,profile,email,groups'
|
||||
```
|
||||
|
||||
Deploy:
|
||||
@@ -147,7 +145,6 @@ Alternative to Plugin Manager: use an init container to download the plugin.
|
||||
# headlamp-values.yaml
|
||||
config:
|
||||
pluginsDir: /headlamp/plugins
|
||||
watchPlugins: false
|
||||
|
||||
initContainers:
|
||||
- name: install-polaris-plugin
|
||||
@@ -185,7 +182,7 @@ data:
|
||||
plugin.yml: |
|
||||
- name: headlamp-polaris-plugin
|
||||
version: 0.3.5
|
||||
url: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/download/v0.3.5/headlamp-polaris-plugin-0.3.5.tar.gz
|
||||
url: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/download/v0.3.10/polaris-0.3.10.tar.gz
|
||||
```
|
||||
|
||||
Apply ConfigMap then deploy Headlamp:
|
||||
@@ -230,7 +227,7 @@ spec:
|
||||
chart:
|
||||
spec:
|
||||
chart: headlamp
|
||||
version: 0.26.x # Use semver range
|
||||
version: 0.26.x # Use semver range
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: headlamp
|
||||
@@ -252,7 +249,6 @@ spec:
|
||||
|
||||
config:
|
||||
pluginsDir: /headlamp/plugins
|
||||
watchPlugins: false
|
||||
|
||||
pluginsManager:
|
||||
enabled: true
|
||||
@@ -373,7 +369,7 @@ kubectl -n kube-system edit configmap headlamp-plugin-config
|
||||
|
||||
# Update version and URL:
|
||||
# version: 0.3.6
|
||||
# url: https://github.com/.../v0.3.6/headlamp-polaris-plugin-0.3.6.tar.gz
|
||||
# url: https://github.com/.../v0.3.6/polaris-0.3.10.tar.gz
|
||||
|
||||
# Restart deployment to trigger init container
|
||||
kubectl -n kube-system rollout restart deployment/headlamp
|
||||
@@ -388,15 +384,12 @@ kubectl -n kube-system rollout status deployment/headlamp
|
||||
# Check Headlamp values
|
||||
helm get values headlamp -n kube-system
|
||||
|
||||
# Verify watchPlugins is false:
|
||||
# config:
|
||||
# watchPlugins: false
|
||||
# Verify plugin files exist
|
||||
kubectl -n kube-system exec deployment/headlamp -c headlamp -- \
|
||||
ls -la /headlamp/plugins/headlamp-polaris-plugin/
|
||||
|
||||
# If incorrect, update values and upgrade:
|
||||
helm upgrade headlamp headlamp/headlamp \
|
||||
--namespace kube-system \
|
||||
--values headlamp-values.yaml \
|
||||
--set config.watchPlugins=false
|
||||
# If missing, reinstall plugin via UI or check init container logs
|
||||
kubectl -n kube-system logs deployment/headlamp -c install-polaris-plugin
|
||||
```
|
||||
|
||||
### Helm Release Stuck
|
||||
|
||||
@@ -29,10 +29,10 @@ metadata:
|
||||
app.kubernetes.io/name: headlamp-polaris-plugin
|
||||
app.kubernetes.io/component: rbac
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["services/proxy"]
|
||||
resourceNames: ["polaris-dashboard"]
|
||||
verbs: ["get"]
|
||||
- apiGroups: ['']
|
||||
resources: ['services/proxy']
|
||||
resourceNames: ['polaris-dashboard']
|
||||
verbs: ['get']
|
||||
|
||||
---
|
||||
# RoleBinding: Grant Headlamp service account access
|
||||
@@ -98,7 +98,7 @@ data:
|
||||
plugin.yml: |
|
||||
- name: headlamp-polaris-plugin
|
||||
version: 0.3.5
|
||||
url: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/download/v0.3.5/headlamp-polaris-plugin-0.3.5.tar.gz
|
||||
url: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/download/v0.3.10/polaris-0.3.10.tar.gz
|
||||
```
|
||||
|
||||
### Headlamp Deployment with Plugin Init Container
|
||||
@@ -145,11 +145,11 @@ spec:
|
||||
- name: headlamp
|
||||
image: ghcr.io/headlamp-k8s/headlamp:v0.39.0
|
||||
args:
|
||||
- "-in-cluster"
|
||||
- "-plugins-dir=/headlamp/plugins"
|
||||
- '-in-cluster'
|
||||
- '-plugins-dir=/headlamp/plugins'
|
||||
env:
|
||||
- name: HEADLAMP_CONFIG_WATCH_PLUGINS
|
||||
value: "false" # CRITICAL: Must be false for plugin manager
|
||||
value: 'false' # CRITICAL: Must be false for plugin manager
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 4466
|
||||
@@ -414,7 +414,7 @@ kubectl -n kube-system edit configmap headlamp-plugin-config
|
||||
|
||||
# Update version and URL:
|
||||
# version: 0.3.6
|
||||
# url: https://github.com/.../v0.3.6/headlamp-polaris-plugin-0.3.6.tar.gz
|
||||
# url: https://github.com/.../v0.3.6/polaris-0.3.10.tar.gz
|
||||
|
||||
# Restart deployment to trigger init container
|
||||
kubectl -n kube-system rollout restart deployment/headlamp
|
||||
|
||||
@@ -46,7 +46,6 @@ kubectl -n kube-system get svc headlamp
|
||||
### Deployment
|
||||
|
||||
- [ ] Plugin installed via Plugin Manager or sidecar init container
|
||||
- [ ] `config.watchPlugins: false` set in Headlamp configuration
|
||||
- [ ] RBAC Role and RoleBinding applied
|
||||
- [ ] NetworkPolicies configured (if using strict network policies)
|
||||
- [ ] Headlamp pods running with 2+ replicas (high availability)
|
||||
@@ -121,7 +120,7 @@ metadata:
|
||||
namespace: polaris
|
||||
subjects:
|
||||
- kind: Group
|
||||
name: system:authenticated # All authenticated users
|
||||
name: system:authenticated # All authenticated users
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
roleRef:
|
||||
kind: Role
|
||||
@@ -134,7 +133,7 @@ For fine-grained control, bind specific users or groups:
|
||||
```yaml
|
||||
subjects:
|
||||
- kind: Group
|
||||
name: sre-team # Only SRE team
|
||||
name: sre-team # Only SRE team
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
```
|
||||
|
||||
@@ -185,12 +184,12 @@ Kubernetes audit logs record every service proxy request:
|
||||
apiVersion: audit.k8s.io/v1
|
||||
kind: Policy
|
||||
rules:
|
||||
- level: Metadata # Log metadata only (not full request/response)
|
||||
verbs: ["get"]
|
||||
- level: Metadata # Log metadata only (not full request/response)
|
||||
verbs: ['get']
|
||||
resources:
|
||||
- group: ""
|
||||
resources: ["services/proxy"]
|
||||
namespaces: ["polaris"]
|
||||
- group: ''
|
||||
resources: ['services/proxy']
|
||||
namespaces: ['polaris']
|
||||
```
|
||||
|
||||
### Data Sensitivity
|
||||
@@ -354,8 +353,8 @@ spec:
|
||||
labels:
|
||||
severity: warning
|
||||
annotations:
|
||||
summary: "Headlamp pod not ready"
|
||||
description: "Pod {{ $labels.pod }} in namespace {{ $labels.namespace }} has been not ready for 5 minutes."
|
||||
summary: 'Headlamp pod not ready'
|
||||
description: 'Pod {{ $labels.pod }} in namespace {{ $labels.namespace }} has been not ready for 5 minutes.'
|
||||
```
|
||||
|
||||
## Performance Tuning
|
||||
@@ -414,12 +413,14 @@ Adjust based on cluster size and user count.
|
||||
If Headlamp or plugin becomes unavailable:
|
||||
|
||||
1. **Verify Polaris is running:**
|
||||
|
||||
```bash
|
||||
kubectl -n polaris get pods
|
||||
kubectl -n polaris get svc polaris-dashboard
|
||||
```
|
||||
|
||||
2. **Redeploy Headlamp:**
|
||||
|
||||
```bash
|
||||
helm upgrade --install headlamp headlamp/headlamp \
|
||||
--namespace kube-system \
|
||||
@@ -427,11 +428,13 @@ If Headlamp or plugin becomes unavailable:
|
||||
```
|
||||
|
||||
3. **Reapply RBAC:**
|
||||
|
||||
```bash
|
||||
kubectl apply -f polaris-plugin-rbac.yaml
|
||||
```
|
||||
|
||||
4. **Verify plugin files:**
|
||||
|
||||
```bash
|
||||
kubectl -n kube-system exec deployment/headlamp -- \
|
||||
ls /headlamp/plugins/headlamp-polaris-plugin/
|
||||
@@ -442,30 +445,6 @@ If Headlamp or plugin becomes unavailable:
|
||||
|
||||
## Known Issues
|
||||
|
||||
### Plugin Loading Issue (Headlamp v0.39.0+)
|
||||
|
||||
**Symptom:** Plugin appears in Settings but not in sidebar
|
||||
|
||||
**Cause:** `config.watchPlugins: true` (default) treats catalog plugins as development plugins
|
||||
|
||||
**Fix:**
|
||||
|
||||
```yaml
|
||||
config:
|
||||
watchPlugins: false # Required for plugin manager
|
||||
```
|
||||
|
||||
**Root Cause:**
|
||||
|
||||
With `watchPlugins: true`, Headlamp backend serves plugin metadata but frontend never executes the JavaScript. This causes plugins to appear in Settings but no sidebar/routes/settings work.
|
||||
|
||||
**Documentation:** See `deployment/PLUGIN_LOADING_FIX.md` in repository for full analysis.
|
||||
|
||||
**After Fix:**
|
||||
|
||||
- Restart Headlamp deployment
|
||||
- Hard refresh browser (**Cmd+Shift+R** / **Ctrl+Shift+R**)
|
||||
|
||||
### Skipped Count Limitation
|
||||
|
||||
**Symptom:** "Skipped" count in UI is lower than native Polaris dashboard
|
||||
|
||||
+60
-40
@@ -18,13 +18,13 @@ Comprehensive guide to testing the Headlamp Polaris Plugin, covering unit tests,
|
||||
|
||||
The Headlamp Polaris Plugin uses a multi-layered testing approach:
|
||||
|
||||
| Test Type | Framework | Purpose | Location |
|
||||
|-----------|-----------|---------|----------|
|
||||
| **Unit Tests** | Vitest | Test individual functions and components in isolation | `src/**/*.test.ts(x)` |
|
||||
| **E2E Tests** | Playwright | Test complete user flows against live Headlamp instance | `e2e/*.spec.ts` |
|
||||
| **Type Checking** | TypeScript | Ensure type safety across codebase | `tsc --noEmit` |
|
||||
| **Linting** | ESLint | Enforce code style and catch common errors | `eslint src/` |
|
||||
| **Formatting** | Prettier | Maintain consistent code formatting | `prettier --check src/` |
|
||||
| Test Type | Framework | Purpose | Location |
|
||||
| ----------------- | ---------- | ------------------------------------------------------- | ----------------------- |
|
||||
| **Unit Tests** | Vitest | Test individual functions and components in isolation | `src/**/*.test.ts(x)` |
|
||||
| **E2E Tests** | Playwright | Test complete user flows against live Headlamp instance | `e2e/*.spec.ts` |
|
||||
| **Type Checking** | TypeScript | Ensure type safety across codebase | `tsc --noEmit` |
|
||||
| **Linting** | ESLint | Enforce code style and catch common errors | `eslint src/` |
|
||||
| **Formatting** | Prettier | Maintain consistent code formatting | `prettier --check src/` |
|
||||
|
||||
### Test Philosophy
|
||||
|
||||
@@ -178,7 +178,9 @@ describe('DashboardView', () => {
|
||||
const mockData = {
|
||||
DisplayName: 'test-cluster',
|
||||
ClusterInfo: { Version: '1.27', Nodes: 3, Pods: 100, Namespaces: 10, Controllers: 50 },
|
||||
Results: [/* ... */],
|
||||
Results: [
|
||||
/* ... */
|
||||
],
|
||||
};
|
||||
|
||||
vi.spyOn(PolarisDataContext, 'usePolarisDataContext').mockReturnValue({
|
||||
@@ -197,6 +199,7 @@ describe('DashboardView', () => {
|
||||
### What to Unit Test
|
||||
|
||||
✅ **Do test:**
|
||||
|
||||
- Pure functions (score calculation, filtering, data transformation)
|
||||
- Data parsing and validation
|
||||
- Utility functions
|
||||
@@ -204,6 +207,7 @@ describe('DashboardView', () => {
|
||||
- Edge cases (empty arrays, null values, invalid input)
|
||||
|
||||
❌ **Don't test:**
|
||||
|
||||
- Third-party libraries (Headlamp, React)
|
||||
- Simple prop passing
|
||||
- Trivial getters/setters
|
||||
@@ -242,6 +246,7 @@ npx playwright show-trace test-results/<test-name>/trace.zip
|
||||
**1. Headlamp Instance**
|
||||
|
||||
E2E tests require a running Headlamp instance with:
|
||||
|
||||
- Polaris plugin installed (version being tested)
|
||||
- Polaris dashboard deployed and accessible
|
||||
- RBAC configured (service proxy permissions)
|
||||
@@ -296,32 +301,32 @@ AUTHENTIK_PASSWORD=secret
|
||||
|
||||
**File:** `e2e/polaris.spec.ts`
|
||||
|
||||
| Test | Description | Validates |
|
||||
|------|-------------|-----------|
|
||||
| `sidebar contains Polaris entry` | Polaris appears in sidebar | Plugin registration |
|
||||
| `overview page renders cluster score` | Score displayed on overview | Data fetching, rendering |
|
||||
| `namespaces page renders table` | Namespace table loads | Data parsing, table rendering |
|
||||
| `namespace detail drawer opens` | Clicking namespace shows drawer | Navigation, drawer UI |
|
||||
| `namespace detail drawer closes with Escape` | Keyboard shortcut works | Keyboard navigation |
|
||||
| `namespace detail drawer opens from URL hash` | Direct URL navigation | URL routing, deep linking |
|
||||
| Test | Description | Validates |
|
||||
| --------------------------------------------- | ------------------------------- | ----------------------------- |
|
||||
| `sidebar contains Polaris entry` | Polaris appears in sidebar | Plugin registration |
|
||||
| `overview page renders cluster score` | Score displayed on overview | Data fetching, rendering |
|
||||
| `namespaces page renders table` | Namespace table loads | Data parsing, table rendering |
|
||||
| `namespace detail drawer opens` | Clicking namespace shows drawer | Navigation, drawer UI |
|
||||
| `namespace detail drawer closes with Escape` | Keyboard shortcut works | Keyboard navigation |
|
||||
| `namespace detail drawer opens from URL hash` | Direct URL navigation | URL routing, deep linking |
|
||||
|
||||
**File:** `e2e/settings.spec.ts`
|
||||
|
||||
| Test | Description | Validates |
|
||||
|------|-------------|-----------|
|
||||
| `plugin settings page is accessible` | Settings page loads | Settings registration |
|
||||
| `refresh interval can be changed` | Dropdown works | User preference persistence |
|
||||
| `dashboard URL can be customized` | Input field works | URL configuration |
|
||||
| `connection test button works` | Test functionality | API connectivity validation |
|
||||
| Test | Description | Validates |
|
||||
| ------------------------------------ | ------------------- | --------------------------- |
|
||||
| `plugin settings page is accessible` | Settings page loads | Settings registration |
|
||||
| `refresh interval can be changed` | Dropdown works | User preference persistence |
|
||||
| `dashboard URL can be customized` | Input field works | URL configuration |
|
||||
| `connection test button works` | Test functionality | API connectivity validation |
|
||||
|
||||
**File:** `e2e/appbar.spec.ts`
|
||||
|
||||
| Test | Description | Validates |
|
||||
|------|-------------|-----------|
|
||||
| `app bar displays Polaris badge` | Badge visible in header | App bar integration |
|
||||
| `badge shows cluster score` | Score matches dashboard | Data consistency |
|
||||
| `clicking badge navigates to overview` | Navigation works | App bar action |
|
||||
| `badge color reflects score` | Red/yellow/green based on score | Visual feedback |
|
||||
| Test | Description | Validates |
|
||||
| -------------------------------------- | ------------------------------- | ------------------- |
|
||||
| `app bar displays Polaris badge` | Badge visible in header | App bar integration |
|
||||
| `badge shows cluster score` | Score matches dashboard | Data consistency |
|
||||
| `clicking badge navigates to overview` | Navigation works | App bar action |
|
||||
| `badge color reflects score` | Red/yellow/green based on score | Visual feedback |
|
||||
|
||||
### Writing E2E Tests
|
||||
|
||||
@@ -385,6 +390,7 @@ npx playwright test --debug
|
||||
```
|
||||
|
||||
This opens Playwright Inspector where you can:
|
||||
|
||||
- Step through each test action
|
||||
- Inspect page state
|
||||
- Edit test selectors live
|
||||
@@ -455,12 +461,12 @@ jobs:
|
||||
|
||||
Configure in GitHub repository settings (Settings → Secrets and variables → Actions):
|
||||
|
||||
| Secret | Required | Description |
|
||||
|--------|----------|-------------|
|
||||
| `HEADLAMP_URL` | Optional | Headlamp instance URL (defaults to configured instance) |
|
||||
| `AUTHENTIK_USERNAME` | OIDC | Authentik username/email for CI user |
|
||||
| `AUTHENTIK_PASSWORD` | OIDC | Authentik password |
|
||||
| `HEADLAMP_TOKEN` | Token | Kubernetes service account token (alternative to OIDC) |
|
||||
| Secret | Required | Description |
|
||||
| -------------------- | -------- | ------------------------------------------------------- |
|
||||
| `HEADLAMP_URL` | Optional | Headlamp instance URL (defaults to configured instance) |
|
||||
| `AUTHENTIK_USERNAME` | OIDC | Authentik username/email for CI user |
|
||||
| `AUTHENTIK_PASSWORD` | OIDC | Authentik password |
|
||||
| `HEADLAMP_TOKEN` | Token | Kubernetes service account token (alternative to OIDC) |
|
||||
|
||||
Set either `AUTHENTIK_USERNAME` + `AUTHENTIK_PASSWORD` **or** `HEADLAMP_TOKEN`. OIDC takes priority if both are set.
|
||||
|
||||
@@ -478,11 +484,11 @@ Trigger workflows manually from GitHub Actions UI:
|
||||
|
||||
### Current Coverage
|
||||
|
||||
| Category | Coverage | Notes |
|
||||
|----------|----------|-------|
|
||||
| **API Functions** | 95% | Core utilities fully tested |
|
||||
| **React Components** | 60% | Focus on critical render paths |
|
||||
| **E2E User Flows** | 80% | Main features covered |
|
||||
| Category | Coverage | Notes |
|
||||
| -------------------- | -------- | ------------------------------ |
|
||||
| **API Functions** | 95% | Core utilities fully tested |
|
||||
| **React Components** | 60% | Focus on critical render paths |
|
||||
| **E2E User Flows** | 80% | Main features covered |
|
||||
|
||||
### Coverage Goals
|
||||
|
||||
@@ -507,18 +513,22 @@ open coverage/index.html
|
||||
### Unit Testing
|
||||
|
||||
1. **Test behavior, not implementation**
|
||||
|
||||
- ✅ `expect(computeScore({ total: 100, pass: 75 })).toBe(75)`
|
||||
- ❌ `expect(mockInternalFunction).toHaveBeenCalled()`
|
||||
|
||||
2. **Use descriptive test names**
|
||||
|
||||
- ✅ `it('returns 0 when total checks is zero')`
|
||||
- ❌ `it('works')`
|
||||
|
||||
3. **One assertion per test (when possible)**
|
||||
|
||||
- Makes failures easier to debug
|
||||
- Exceptions: testing multiple properties of same object
|
||||
|
||||
4. **Mock external dependencies**
|
||||
|
||||
- Mock API calls, context providers, external libraries
|
||||
- Don't mock the code you're testing
|
||||
|
||||
@@ -529,27 +539,33 @@ open coverage/index.html
|
||||
### E2E Testing
|
||||
|
||||
1. **Use semantic selectors**
|
||||
|
||||
- ✅ `page.getByRole('button', { name: 'Close' })`
|
||||
- ✅ `page.getByText('Polaris — Overview')`
|
||||
- ❌ `page.locator('.MuiButton-root')`
|
||||
|
||||
2. **Wait for visibility, not arbitrary timeouts**
|
||||
|
||||
- ✅ `await expect(element).toBeVisible()`
|
||||
- ❌ `await page.waitForTimeout(5000)`
|
||||
|
||||
3. **Keep tests independent**
|
||||
|
||||
- Each test should work in isolation
|
||||
- Don't rely on previous tests' state
|
||||
|
||||
4. **Test complete user flows**
|
||||
|
||||
- Navigate → Interact → Verify outcome
|
||||
- Don't just test page loads
|
||||
|
||||
5. **Clean up after tests**
|
||||
|
||||
- Close drawers/modals
|
||||
- Reset state if needed
|
||||
|
||||
6. **Use storage state for auth**
|
||||
|
||||
- Reuse authenticated session across tests
|
||||
- Faster than logging in for every test
|
||||
|
||||
@@ -560,15 +576,18 @@ open coverage/index.html
|
||||
### General
|
||||
|
||||
1. **Run tests before committing**
|
||||
|
||||
```bash
|
||||
npm run build && npm run lint && npm test
|
||||
```
|
||||
|
||||
2. **Fix failing tests immediately**
|
||||
|
||||
- Don't commit failing tests
|
||||
- Don't skip tests to "fix later"
|
||||
|
||||
3. **Update tests when changing code**
|
||||
|
||||
- Tests are documentation
|
||||
- Keep them in sync with implementation
|
||||
|
||||
@@ -604,7 +623,7 @@ Check mocks are returning expected structure:
|
||||
|
||||
```typescript
|
||||
vi.spyOn(PolarisDataContext, 'usePolarisDataContext').mockReturnValue({
|
||||
data: mockData, // Ensure mockData has all required fields
|
||||
data: mockData, // Ensure mockData has all required fields
|
||||
loading: false,
|
||||
error: null,
|
||||
refresh: vi.fn(),
|
||||
@@ -624,6 +643,7 @@ npm run e2e:headed
|
||||
```
|
||||
|
||||
Common causes:
|
||||
|
||||
- Element hasn't rendered yet (use `toBeVisible()` instead of `toBeDefined()`)
|
||||
- Wrong selector (use Playwright Inspector to verify)
|
||||
- Authentication failed (check token/credentials)
|
||||
|
||||
@@ -33,16 +33,19 @@ The plugin is published on [Artifact Hub](https://artifacthub.io/packages/headla
|
||||
#### Via Headlamp UI
|
||||
|
||||
1. **Navigate to Plugin Settings:**
|
||||
|
||||
- Open Headlamp in your browser
|
||||
- Go to **Settings → Plugins**
|
||||
- Click the **Catalog** tab
|
||||
|
||||
2. **Search and Install:**
|
||||
|
||||
- Search for "Polaris"
|
||||
- Find "Headlamp Polaris Plugin"
|
||||
- Click **Install**
|
||||
|
||||
3. **Hard Refresh Browser:**
|
||||
|
||||
- **Mac:** Cmd+Shift+R
|
||||
- **Windows/Linux:** Ctrl+Shift+R
|
||||
|
||||
@@ -58,7 +61,6 @@ Add to your Headlamp Helm values:
|
||||
# headlamp-values.yaml
|
||||
config:
|
||||
pluginsDir: /headlamp/plugins
|
||||
watchPlugins: false # CRITICAL for v0.39.0+
|
||||
|
||||
pluginsManager:
|
||||
enabled: true
|
||||
@@ -76,23 +78,6 @@ helm upgrade --install headlamp headlamp/headlamp \
|
||||
|
||||
Then install the plugin via Headlamp UI as described above.
|
||||
|
||||
#### Critical Configuration for Headlamp v0.39.0+
|
||||
|
||||
**⚠️ IMPORTANT:** You **must** set `config.watchPlugins: false` or the plugin will not load.
|
||||
|
||||
**Why?**
|
||||
- With `watchPlugins: true` (default), catalog-managed plugins are treated as "development directory" plugins
|
||||
- This causes the backend to serve metadata but the frontend never executes the JavaScript
|
||||
- Result: Plugin appears in Settings but no sidebar/routes/settings work
|
||||
|
||||
**Fix:**
|
||||
```yaml
|
||||
config:
|
||||
watchPlugins: false # Required for plugin manager
|
||||
```
|
||||
|
||||
See [deployment/PLUGIN_LOADING_FIX.md](../deployment/production.md#plugin-loading-issue-headlamp-v0390) for full root cause analysis.
|
||||
|
||||
### Option 2: Sidecar Container
|
||||
|
||||
**Best for:** Controlled plugin versions, air-gapped environments, specific version pinning
|
||||
@@ -105,7 +90,6 @@ This method uses an init container to download and install the plugin from a tar
|
||||
# headlamp-values.yaml
|
||||
config:
|
||||
pluginsDir: /headlamp/plugins
|
||||
watchPlugins: false
|
||||
|
||||
initContainers:
|
||||
- name: install-polaris-plugin
|
||||
@@ -143,7 +127,7 @@ data:
|
||||
plugin.yml: |
|
||||
- name: headlamp-polaris-plugin
|
||||
version: 0.3.5
|
||||
url: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/download/v0.3.5/headlamp-polaris-plugin-0.3.5.tar.gz
|
||||
url: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/download/v0.3.10/polaris-0.3.10.tar.gz
|
||||
```
|
||||
|
||||
#### Apply Configuration
|
||||
@@ -179,7 +163,7 @@ Download the plugin tarball and extract it into Headlamp's plugin directory.
|
||||
```bash
|
||||
# Download latest release
|
||||
VERSION=0.3.5
|
||||
wget https://github.com/cpfarhood/headlamp-polaris-plugin/releases/download/v${VERSION}/headlamp-polaris-plugin-${VERSION}.tar.gz
|
||||
wget https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/download/v${VERSION}/headlamp-polaris-plugin-${VERSION}.tar.gz
|
||||
|
||||
# Extract to plugin directory
|
||||
tar xzf headlamp-polaris-plugin-${VERSION}.tar.gz -C /headlamp/plugins/
|
||||
@@ -204,7 +188,7 @@ config:
|
||||
volumes:
|
||||
- name: plugins
|
||||
hostPath:
|
||||
path: /path/to/plugins # Where you extracted the tarball
|
||||
path: /path/to/plugins # Where you extracted the tarball
|
||||
type: Directory
|
||||
|
||||
volumeMounts:
|
||||
@@ -225,7 +209,7 @@ Clone the repository and build the plugin from source.
|
||||
|
||||
```bash
|
||||
# Clone repository
|
||||
git clone https://github.com/cpfarhood/headlamp-polaris-plugin.git
|
||||
git clone https://github.com/privilegedescalation/headlamp-polaris-plugin.git
|
||||
cd headlamp-polaris-plugin
|
||||
|
||||
# Install dependencies
|
||||
@@ -316,6 +300,7 @@ kubectl -n kube-system wait --for=condition=ready pod -l app.kubernetes.io/name=
|
||||
### 4. Verify Installation
|
||||
|
||||
**UI Verification:**
|
||||
|
||||
1. Navigate to **Settings → Plugins**
|
||||
2. Verify "headlamp-polaris-plugin" is listed
|
||||
3. Check version matches installed version
|
||||
@@ -351,22 +336,22 @@ kubectl get --raw /api/v1/namespaces/polaris/services/polaris-dashboard:80/proxy
|
||||
**Symptom:** Plugin listed in Settings → Plugins but no "Polaris" entry in sidebar
|
||||
|
||||
**Causes:**
|
||||
1. `watchPlugins: true` (should be `false` for v0.39.0+)
|
||||
2. Browser cache not cleared
|
||||
3. Plugin JavaScript failed to load
|
||||
|
||||
1. Browser cache not cleared
|
||||
2. Plugin JavaScript failed to load
|
||||
3. Plugin files not properly installed
|
||||
|
||||
**Solution:**
|
||||
|
||||
```bash
|
||||
# 1. Check Headlamp config
|
||||
kubectl -n kube-system get configmap headlamp -o yaml | grep watchPlugins
|
||||
# 1. Verify plugin files exist
|
||||
kubectl -n kube-system exec deployment/headlamp -c headlamp -- \
|
||||
ls -la /headlamp/plugins/headlamp-polaris-plugin/
|
||||
|
||||
# If "true" or missing, fix it:
|
||||
kubectl -n kube-system edit configmap headlamp
|
||||
# Set: watchPlugins: "false"
|
||||
# Expected: dist/, package.json present
|
||||
|
||||
# 2. Restart Headlamp
|
||||
kubectl -n kube-system rollout restart deployment/headlamp
|
||||
# 2. Check Headlamp logs for plugin errors
|
||||
kubectl -n kube-system logs deployment/headlamp | grep -i polaris
|
||||
|
||||
# 3. Hard refresh browser (Cmd+Shift+R or Ctrl+Shift+R)
|
||||
|
||||
@@ -389,6 +374,7 @@ See [RBAC Issues](../troubleshooting/rbac-issues.md) for detailed debugging.
|
||||
**Symptom:** Error loading Polaris data, 404 in browser console
|
||||
|
||||
**Causes:**
|
||||
|
||||
1. Polaris not deployed
|
||||
2. Polaris service name incorrect
|
||||
3. Polaris namespace incorrect
|
||||
|
||||
@@ -4,12 +4,12 @@ Before installing the Headlamp Polaris Plugin, ensure your environment meets the
|
||||
|
||||
## Required Components
|
||||
|
||||
| Requirement | Minimum Version | Recommended Version |
|
||||
| -------------------------------- | ------------------ | ------------------- |
|
||||
| **Kubernetes** | v1.24+ | v1.28+ |
|
||||
| **Headlamp** | v0.26+ | v0.39+ |
|
||||
| **Polaris** (dashboard enabled) | Any recent release | Latest stable |
|
||||
| **Browser** | Modern (ES2020+) | Latest Chrome/Firefox/Safari/Edge |
|
||||
| Requirement | Minimum Version | Recommended Version |
|
||||
| ------------------------------- | ------------------ | --------------------------------- |
|
||||
| **Kubernetes** | v1.24+ | v1.28+ |
|
||||
| **Headlamp** | v0.26+ | v0.39+ |
|
||||
| **Polaris** (dashboard enabled) | Any recent release | Latest stable |
|
||||
| **Browser** | Modern (ES2020+) | Latest Chrome/Firefox/Safari/Edge |
|
||||
|
||||
## Polaris Requirements
|
||||
|
||||
@@ -91,7 +91,6 @@ helm repo update
|
||||
helm install headlamp headlamp/headlamp \
|
||||
--namespace kube-system \
|
||||
--set config.pluginsDir="/headlamp/plugins" \
|
||||
--set config.watchPlugins=false \
|
||||
--set pluginsManager.enabled=true
|
||||
|
||||
# Wait for pod to be ready
|
||||
@@ -133,6 +132,7 @@ Headlamp Pod → Kubernetes API Server → Polaris Dashboard Service
|
||||
```
|
||||
|
||||
**Required network paths:**
|
||||
|
||||
- Headlamp pod → Kubernetes API server (443)
|
||||
- Kubernetes API server → Polaris dashboard service (80)
|
||||
|
||||
@@ -161,12 +161,12 @@ The plugin uses modern JavaScript features and requires:
|
||||
|
||||
### Tested Browsers
|
||||
|
||||
| Browser | Minimum Version |
|
||||
| ---------------- | --------------- |
|
||||
| Chrome/Chromium | 80+ |
|
||||
| Firefox | 75+ |
|
||||
| Safari | 13.1+ |
|
||||
| Edge | 80+ |
|
||||
| Browser | Minimum Version |
|
||||
| --------------- | --------------- |
|
||||
| Chrome/Chromium | 80+ |
|
||||
| Firefox | 75+ |
|
||||
| Safari | 13.1+ |
|
||||
| Edge | 80+ |
|
||||
|
||||
## Optional Components
|
||||
|
||||
|
||||
@@ -6,9 +6,9 @@ Get the Headlamp Polaris Plugin up and running in 5 minutes.
|
||||
|
||||
Before starting, ensure:
|
||||
|
||||
- ✅ Kubernetes cluster is running
|
||||
- ✅ Headlamp v0.26+ is deployed
|
||||
- ✅ Polaris is installed with dashboard enabled
|
||||
- Kubernetes cluster is running
|
||||
- Headlamp v0.26+ is deployed
|
||||
- Polaris is installed with dashboard enabled
|
||||
|
||||
Don't have these? See [Prerequisites](prerequisites.md) for installation instructions.
|
||||
|
||||
@@ -29,7 +29,6 @@ Don't have these? See [Prerequisites](prerequisites.md) for installation instruc
|
||||
cat <<EOF > headlamp-values.yaml
|
||||
config:
|
||||
pluginsDir: /headlamp/plugins
|
||||
watchPlugins: false # CRITICAL for v0.39.0+
|
||||
|
||||
pluginsManager:
|
||||
enabled: true
|
||||
@@ -86,14 +85,17 @@ EOF
|
||||
### UI Verification
|
||||
|
||||
1. **Check Plugin is Loaded:**
|
||||
|
||||
- Go to **Settings → Plugins**
|
||||
- Verify "headlamp-polaris-plugin" is listed
|
||||
|
||||
2. **Check Sidebar:**
|
||||
|
||||
- Look for **Polaris** entry in the left sidebar
|
||||
- If not visible, hard refresh: **Cmd+Shift+R** / **Ctrl+Shift+R**
|
||||
|
||||
3. **View Overview Dashboard:**
|
||||
|
||||
- Click **Polaris** in sidebar
|
||||
- Overview page loads with:
|
||||
- Cluster score gauge
|
||||
@@ -137,6 +139,7 @@ kubectl get --raw /api/v1/namespaces/polaris/services/polaris-dashboard:80/proxy
|
||||
Navigate to **Polaris → Overview**:
|
||||
|
||||
- **Cluster Score Gauge:** Overall cluster health (0-100%)
|
||||
|
||||
- Green (≥80%): Excellent
|
||||
- Yellow (50-79%): Needs improvement
|
||||
- Red (<50%): Critical issues
|
||||
@@ -181,15 +184,11 @@ Cluster score badge in top navigation:
|
||||
### Plugin Not in Sidebar
|
||||
|
||||
```bash
|
||||
# Check Headlamp config
|
||||
kubectl -n kube-system get configmap headlamp -o yaml | grep watchPlugins
|
||||
# Verify plugin files exist
|
||||
kubectl -n kube-system exec -it deployment/headlamp -c headlamp -- \
|
||||
ls /headlamp/plugins/headlamp-polaris-plugin/
|
||||
|
||||
# If "true" or missing, set to false:
|
||||
kubectl -n kube-system edit configmap headlamp
|
||||
# Set: watchPlugins: "false"
|
||||
|
||||
# Restart Headlamp
|
||||
kubectl -n kube-system rollout restart deployment/headlamp
|
||||
# If missing, reinstall via Headlamp UI or sidecar method
|
||||
|
||||
# Hard refresh browser
|
||||
# Cmd+Shift+R (Mac) or Ctrl+Shift+R (Windows/Linux)
|
||||
@@ -276,6 +275,4 @@ If test fails, see [Troubleshooting](../troubleshooting/README.md).
|
||||
|
||||
---
|
||||
|
||||
**Congratulations!** You're now running the Headlamp Polaris Plugin. 🎉
|
||||
|
||||
Visit the **Polaris** section in Headlamp to explore your cluster's security, reliability, and efficiency audit results.
|
||||
You're now running the Headlamp Polaris Plugin. Visit the **Polaris** section in Headlamp to explore your cluster's security, reliability, and efficiency audit results.
|
||||
|
||||
@@ -4,17 +4,17 @@ Quick diagnosis guide and common issues for the Headlamp Polaris Plugin.
|
||||
|
||||
## Quick Diagnosis
|
||||
|
||||
| Symptom | Likely Cause | Quick Fix | Details |
|
||||
|---------|-------------|-----------|---------|
|
||||
| **Plugin not in sidebar** | Headlamp v0.39.0+ plugin loading issue | Set `config.watchPlugins: false` and hard refresh (Cmd+Shift+R) | [Common Issues](common-issues.md#plugin-not-in-sidebar) |
|
||||
| **403 Access Denied** | Missing RBAC binding for `services/proxy` | Apply Role + RoleBinding from RBAC section | [RBAC Issues](rbac-issues.md) |
|
||||
| **404 or 503** | Polaris not installed, or dashboard disabled | Install Polaris with `dashboard.enabled: true` in `polaris` namespace | [Common Issues](common-issues.md#404-not-found) |
|
||||
| **Dark mode white backgrounds** | Old plugin version | Upgrade to v0.3.5+ and hard refresh browser | [Common Issues](common-issues.md#dark-mode-issues) |
|
||||
| **Settings page empty** | Old plugin version | Upgrade to v0.3.3+ | [Common Issues](common-issues.md#settings-page-empty) |
|
||||
| **No data / infinite spinner** | Network policy or Polaris pod down | Check network policies and `kubectl get pods -n polaris` | [Network Problems](network-problems.md) |
|
||||
| **Namespace drawer white** | CSS variable issue | Update to v0.3.5+ with `--mui-palette-background-paper` | [Common Issues](common-issues.md#dark-mode-issues) |
|
||||
| **Cluster score not updating** | Auto-refresh disabled or interval too long | Check Settings → Plugins → Polaris refresh interval | [Common Issues](common-issues.md#data-not-refreshing) |
|
||||
| **Custom URL not working** | CORS or incorrect URL format | Test with curl, check CORS headers | [Network Problems](network-problems.md#cors-issues) |
|
||||
| Symptom | Likely Cause | Quick Fix | Details |
|
||||
| ------------------------------- | -------------------------------------------- | --------------------------------------------------------------------- | ------------------------------------------------------- |
|
||||
| **Plugin not in sidebar** | Browser cache or plugin not installed | Hard refresh browser (Cmd+Shift+R) and verify plugin files exist | [Common Issues](common-issues.md#plugin-not-in-sidebar) |
|
||||
| **403 Access Denied** | Missing RBAC binding for `services/proxy` | Apply Role + RoleBinding from RBAC section | [RBAC Issues](rbac-issues.md) |
|
||||
| **404 or 503** | Polaris not installed, or dashboard disabled | Install Polaris with `dashboard.enabled: true` in `polaris` namespace | [Common Issues](common-issues.md#404-not-found) |
|
||||
| **Dark mode white backgrounds** | Old plugin version | Upgrade to v0.3.5+ and hard refresh browser | [Common Issues](common-issues.md#dark-mode-issues) |
|
||||
| **Settings page empty** | Old plugin version | Upgrade to v0.3.3+ | [Common Issues](common-issues.md#settings-page-empty) |
|
||||
| **No data / infinite spinner** | Network policy or Polaris pod down | Check network policies and `kubectl get pods -n polaris` | [Network Problems](network-problems.md) |
|
||||
| **Namespace drawer white** | CSS variable issue | Update to v0.3.5+ with `--mui-palette-background-paper` | [Common Issues](common-issues.md#dark-mode-issues) |
|
||||
| **Cluster score not updating** | Auto-refresh disabled or interval too long | Check Settings → Plugins → Polaris refresh interval | [Common Issues](common-issues.md#data-not-refreshing) |
|
||||
| **Custom URL not working** | CORS or incorrect URL format | Test with curl, check CORS headers | [Network Problems](network-problems.md#cors-issues) |
|
||||
|
||||
## Detailed Guides
|
||||
|
||||
@@ -56,11 +56,6 @@ kubectl -n kube-system logs deployment/headlamp | grep -i polaris
|
||||
### Plugin Loading Verification
|
||||
|
||||
```bash
|
||||
# Check Headlamp config
|
||||
kubectl -n kube-system get configmap headlamp -o yaml | grep watchPlugins
|
||||
|
||||
# Expected: watchPlugins: "false"
|
||||
|
||||
# Verify plugin files exist
|
||||
kubectl -n kube-system exec deployment/headlamp -c headlamp -- \
|
||||
ls -la /headlamp/plugins/headlamp-polaris-plugin/
|
||||
@@ -115,6 +110,7 @@ kubectl run -it --rm debug --image=curlimages/curl --restart=Never -- \
|
||||
3. Look for errors containing "polaris" or "plugin"
|
||||
|
||||
**Common errors:**
|
||||
|
||||
- `createSvgIcon is not defined` → MUI import issue (plugin bug)
|
||||
- `403 Forbidden` → RBAC permission denied
|
||||
- `404 Not Found` → Polaris not installed or wrong URL
|
||||
@@ -132,12 +128,12 @@ kubectl run -it --rm debug --image=curlimages/curl --restart=Never -- \
|
||||
|
||||
```javascript
|
||||
// Open browser console and run:
|
||||
localStorage.getItem('polaris-plugin-refresh-interval')
|
||||
localStorage.getItem('polaris-plugin-dashboard-url')
|
||||
localStorage.getItem('polaris-plugin-refresh-interval');
|
||||
localStorage.getItem('polaris-plugin-dashboard-url');
|
||||
|
||||
// Reset to defaults:
|
||||
localStorage.removeItem('polaris-plugin-refresh-interval')
|
||||
localStorage.removeItem('polaris-plugin-dashboard-url')
|
||||
localStorage.removeItem('polaris-plugin-refresh-interval');
|
||||
localStorage.removeItem('polaris-plugin-dashboard-url');
|
||||
```
|
||||
|
||||
## Still Having Issues?
|
||||
@@ -145,17 +141,19 @@ localStorage.removeItem('polaris-plugin-dashboard-url')
|
||||
If the quick diagnosis doesn't resolve your issue:
|
||||
|
||||
1. **Check detailed guides:**
|
||||
|
||||
- [Common Issues](common-issues.md)
|
||||
- [RBAC Issues](rbac-issues.md)
|
||||
- [Network Problems](network-problems.md)
|
||||
|
||||
2. **Review documentation:**
|
||||
|
||||
- [Installation Guide](../getting-started/installation.md)
|
||||
- [RBAC Permissions](../user-guide/rbac-permissions.md)
|
||||
- [Deployment Guide](../deployment/kubernetes.md)
|
||||
|
||||
3. **Open a GitHub issue:**
|
||||
- [GitHub Issues](https://github.com/cpfarhood/headlamp-polaris-plugin/issues)
|
||||
- [GitHub Issues](https://github.com/privilegedescalation/headlamp-polaris-plugin/issues)
|
||||
- Include: Headlamp version, plugin version, error messages, logs
|
||||
|
||||
## References
|
||||
|
||||
@@ -20,34 +20,17 @@ This guide covers common issues encountered when using the Headlamp Polaris Plug
|
||||
## Plugin Not Showing in Sidebar
|
||||
|
||||
### Symptoms
|
||||
|
||||
- Plugin appears in Settings → Plugins but sidebar entry is missing
|
||||
- No "Polaris" section in navigation
|
||||
- Routes like `/polaris` return 404 or blank page
|
||||
|
||||
### Common Causes
|
||||
|
||||
**1. Headlamp v0.39.0+ Plugin Loading Issue**
|
||||
|
||||
**Root Cause**: Headlamp v0.39.0+ changed plugin loading behavior. With `config.watchPlugins: true` (default), catalog-managed plugins are treated as "development directory" plugins, causing the backend to serve metadata but frontend to never execute the JavaScript.
|
||||
|
||||
**Solution**: Set `config.watchPlugins: false` in Headlamp configuration.
|
||||
|
||||
```yaml
|
||||
# HelmRelease values
|
||||
config:
|
||||
watchPlugins: false # CRITICAL for plugin manager
|
||||
```
|
||||
|
||||
After applying this change:
|
||||
1. Restart Headlamp pod
|
||||
2. Hard refresh browser (Cmd+Shift+R or Ctrl+Shift+R)
|
||||
3. Clear browser cache if needed
|
||||
|
||||
**References**: See `deployment/PLUGIN_LOADING_FIX.md` for complete root cause analysis.
|
||||
|
||||
**2. Plugin Not Installed**
|
||||
**1. Plugin Not Installed**
|
||||
|
||||
**Check plugin installation**:
|
||||
|
||||
```bash
|
||||
# View Headlamp pod logs (plugin sidecar)
|
||||
kubectl logs -n kube-system deployment/headlamp -c headlamp-plugin
|
||||
@@ -58,23 +41,26 @@ kubectl logs -n kube-system deployment/headlamp -c headlamp-plugin
|
||||
```
|
||||
|
||||
**Verify plugin files exist**:
|
||||
|
||||
```bash
|
||||
kubectl exec -n kube-system deployment/headlamp -c headlamp -- ls -la /headlamp/plugins/
|
||||
# Should show: headlamp-polaris-plugin/
|
||||
```
|
||||
|
||||
**3. JavaScript Cached by Browser**
|
||||
**2. JavaScript Cached by Browser**
|
||||
|
||||
After upgrading the plugin, old JavaScript may be cached.
|
||||
|
||||
**Solution**:
|
||||
|
||||
- Hard refresh: Cmd+Shift+R (macOS) or Ctrl+Shift+R (Linux/Windows)
|
||||
- Clear browser cache for Headlamp domain
|
||||
- Open DevTools → Application → Clear Storage → Clear all
|
||||
|
||||
**4. Plugin Disabled in Settings**
|
||||
**3. Plugin Disabled in Settings**
|
||||
|
||||
**Check Settings → Plugins**:
|
||||
|
||||
- Navigate to Headlamp Settings → Plugins
|
||||
- Ensure "Polaris" plugin is enabled (toggle should be ON)
|
||||
- If disabled, enable it and refresh the page
|
||||
@@ -84,11 +70,13 @@ After upgrading the plugin, old JavaScript may be cached.
|
||||
## 403 Forbidden Error
|
||||
|
||||
### Symptoms
|
||||
|
||||
- Error message: "Error loading Polaris audit data: 403 Forbidden"
|
||||
- Browser console shows 403 response from API proxy
|
||||
- Plugin sidebar shows but data fails to load
|
||||
|
||||
### Root Cause
|
||||
|
||||
User or service account lacks `services/proxy` permission on `polaris-dashboard` service in the `polaris` namespace.
|
||||
|
||||
### Solution
|
||||
@@ -96,11 +84,13 @@ User or service account lacks `services/proxy` permission on `polaris-dashboard`
|
||||
**1. Verify RBAC Configuration**
|
||||
|
||||
Check if Role exists:
|
||||
|
||||
```bash
|
||||
kubectl get role polaris-proxy-reader -n polaris -o yaml
|
||||
```
|
||||
|
||||
Expected output:
|
||||
|
||||
```yaml
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
@@ -108,20 +98,22 @@ metadata:
|
||||
name: polaris-proxy-reader
|
||||
namespace: polaris
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["services/proxy"]
|
||||
resourceNames: ["polaris-dashboard"]
|
||||
verbs: ["get"]
|
||||
- apiGroups: ['']
|
||||
resources: ['services/proxy']
|
||||
resourceNames: ['polaris-dashboard']
|
||||
verbs: ['get']
|
||||
```
|
||||
|
||||
**2. Verify RoleBinding**
|
||||
|
||||
For service account mode:
|
||||
|
||||
```bash
|
||||
kubectl get rolebinding headlamp-polaris-proxy -n polaris -o yaml
|
||||
```
|
||||
|
||||
Expected subjects:
|
||||
|
||||
```yaml
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
@@ -130,6 +122,7 @@ subjects:
|
||||
```
|
||||
|
||||
For OIDC mode:
|
||||
|
||||
```bash
|
||||
kubectl get rolebinding -n polaris -o yaml | grep -A 5 polaris-proxy-reader
|
||||
```
|
||||
@@ -172,6 +165,7 @@ EOF
|
||||
**4. Test RBAC Permissions**
|
||||
|
||||
Service account mode:
|
||||
|
||||
```bash
|
||||
# Impersonate Headlamp service account
|
||||
kubectl auth can-i get services/proxy \
|
||||
@@ -182,6 +176,7 @@ kubectl auth can-i get services/proxy \
|
||||
```
|
||||
|
||||
OIDC mode (test as yourself):
|
||||
|
||||
```bash
|
||||
kubectl auth can-i get services/proxy \
|
||||
--resource-name=polaris-dashboard \
|
||||
@@ -192,6 +187,7 @@ kubectl auth can-i get services/proxy \
|
||||
**5. Restart Headlamp**
|
||||
|
||||
After applying RBAC changes:
|
||||
|
||||
```bash
|
||||
kubectl rollout restart deployment headlamp -n kube-system
|
||||
```
|
||||
@@ -201,11 +197,13 @@ kubectl rollout restart deployment headlamp -n kube-system
|
||||
## 404 Not Found Error
|
||||
|
||||
### Symptoms
|
||||
|
||||
- Error message: "Error loading Polaris audit data: 404 Not Found"
|
||||
- Service proxy request returns 404
|
||||
- Polaris dashboard not reachable
|
||||
|
||||
### Root Cause
|
||||
|
||||
Polaris dashboard service doesn't exist or is in a different namespace.
|
||||
|
||||
### Solution
|
||||
@@ -213,12 +211,14 @@ Polaris dashboard service doesn't exist or is in a different namespace.
|
||||
**1. Verify Polaris Installation**
|
||||
|
||||
Check if Polaris is installed:
|
||||
|
||||
```bash
|
||||
kubectl get pods -n polaris
|
||||
# Expected: polaris-dashboard-* pod running
|
||||
```
|
||||
|
||||
Check if service exists:
|
||||
|
||||
```bash
|
||||
kubectl get service polaris-dashboard -n polaris
|
||||
# Expected: ClusterIP service on port 80
|
||||
@@ -227,6 +227,7 @@ kubectl get service polaris-dashboard -n polaris
|
||||
**2. Verify Service Name and Port**
|
||||
|
||||
The plugin expects:
|
||||
|
||||
- **Namespace**: `polaris`
|
||||
- **Service Name**: `polaris-dashboard`
|
||||
- **Port**: `80` (or named port `dashboard`)
|
||||
@@ -246,11 +247,13 @@ If this returns 404, Polaris service is not configured correctly.
|
||||
**4. Check Polaris Dashboard Configuration**
|
||||
|
||||
Verify Polaris is running with dashboard enabled:
|
||||
|
||||
```bash
|
||||
kubectl get deployment polaris-dashboard -n polaris -o yaml | grep -A 5 dashboard
|
||||
```
|
||||
|
||||
If `dashboard.enabled: false` in Helm values, enable it:
|
||||
|
||||
```yaml
|
||||
# values.yaml
|
||||
dashboard:
|
||||
@@ -260,6 +263,7 @@ dashboard:
|
||||
**5. Reinstall Polaris**
|
||||
|
||||
If Polaris is missing or misconfigured:
|
||||
|
||||
```bash
|
||||
helm repo add fairwinds-stable https://charts.fairwinds.com/stable
|
||||
helm upgrade --install polaris fairwinds-stable/polaris \
|
||||
@@ -273,21 +277,25 @@ helm upgrade --install polaris fairwinds-stable/polaris \
|
||||
## Plugin Settings Page Empty
|
||||
|
||||
### Symptoms
|
||||
|
||||
- Settings → Polaris shows title but no content
|
||||
- Refresh interval and dashboard URL fields not visible
|
||||
|
||||
### Root Cause (Fixed in v0.3.3)
|
||||
|
||||
Plugin settings registration name didn't match `package.json` name.
|
||||
|
||||
### Solution
|
||||
|
||||
Upgrade to v0.3.3 or later:
|
||||
|
||||
```bash
|
||||
# Via Headlamp UI: Settings → Plugins → Update
|
||||
# Or redeploy with latest version
|
||||
```
|
||||
|
||||
If manually installing, ensure plugin name matches `package.json`:
|
||||
|
||||
```typescript
|
||||
registerPluginSettings('headlamp-polaris-plugin', PolarisSettings, true);
|
||||
// NOT 'polaris' — must match package.json name
|
||||
@@ -298,6 +306,7 @@ registerPluginSettings('headlamp-polaris-plugin', PolarisSettings, true);
|
||||
## Dark Mode Issues
|
||||
|
||||
### Symptoms
|
||||
|
||||
- Drawer background remains white in dark mode
|
||||
- Text is hard to read in dark mode
|
||||
- Theme colors don't match Headlamp UI
|
||||
@@ -308,6 +317,7 @@ Upgrade to v0.3.5 or later for complete dark mode support.
|
||||
|
||||
**Verify CSS Variables**:
|
||||
The plugin uses MUI CSS variables for theming:
|
||||
|
||||
- `--mui-palette-background-default` (drawer background)
|
||||
- `--mui-palette-text-primary` (text color)
|
||||
- `--mui-palette-primary-main` (links, buttons)
|
||||
@@ -317,6 +327,7 @@ These automatically adapt to Headlamp's theme (light/dark/system).
|
||||
|
||||
**Hard Refresh Required**:
|
||||
After upgrading from v0.3.4 or earlier, hard refresh your browser:
|
||||
|
||||
- macOS: Cmd+Shift+R
|
||||
- Linux/Windows: Ctrl+Shift+R
|
||||
|
||||
@@ -328,6 +339,7 @@ If hard refresh doesn't help, clear cache for Headlamp domain.
|
||||
## Data Not Loading / Infinite Spinner
|
||||
|
||||
### Symptoms
|
||||
|
||||
- Plugin shows "Loading Polaris audit data..." forever
|
||||
- No error message in UI
|
||||
- Data never appears
|
||||
@@ -339,6 +351,7 @@ If hard refresh doesn't help, clear cache for Headlamp domain.
|
||||
Open DevTools (F12) → Console tab.
|
||||
|
||||
Look for:
|
||||
|
||||
- Network errors (CORS, timeouts, 5xx responses)
|
||||
- JavaScript errors
|
||||
- Failed API requests
|
||||
@@ -348,6 +361,7 @@ Look for:
|
||||
Open DevTools → Network tab → Filter by "results.json"
|
||||
|
||||
Expected request:
|
||||
|
||||
```
|
||||
GET /api/v1/namespaces/polaris/services/polaris-dashboard:80/proxy/results.json
|
||||
Status: 200
|
||||
@@ -355,6 +369,7 @@ Response: JSON data
|
||||
```
|
||||
|
||||
Common issues:
|
||||
|
||||
- **Status 0 / Failed**: Network policy blocking request
|
||||
- **Status 403**: RBAC issue (see [403 Forbidden Error](#403-forbidden-error))
|
||||
- **Status 404**: Service not found (see [404 Not Found Error](#404-not-found-error))
|
||||
@@ -378,6 +393,7 @@ curl http://localhost:8080/results.json
|
||||
**4. Check Network Policies**
|
||||
|
||||
If your cluster uses NetworkPolicies:
|
||||
|
||||
```bash
|
||||
kubectl get networkpolicy -n polaris
|
||||
```
|
||||
@@ -385,6 +401,7 @@ kubectl get networkpolicy -n polaris
|
||||
Ensure API server (or Headlamp pod) can reach Polaris dashboard.
|
||||
|
||||
**Example fix**:
|
||||
|
||||
```yaml
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
@@ -399,7 +416,7 @@ spec:
|
||||
- Ingress
|
||||
ingress:
|
||||
- from:
|
||||
- namespaceSelector: {} # Allow from all namespaces (API server)
|
||||
- namespaceSelector: {} # Allow from all namespaces (API server)
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 8080
|
||||
@@ -408,6 +425,7 @@ spec:
|
||||
**5. Increase Timeout / Disable Auto-Refresh**
|
||||
|
||||
If Polaris responds slowly:
|
||||
|
||||
- Open Settings → Polaris
|
||||
- Increase refresh interval to 10+ minutes
|
||||
- Or set to "Manual only" to disable auto-refresh
|
||||
@@ -423,6 +441,7 @@ If Polaris responds slowly:
|
||||
**Cause**: Network request failed (CORS, network policy, timeout)
|
||||
|
||||
**Solution**:
|
||||
|
||||
1. Check Network tab for actual HTTP status
|
||||
2. Verify network policies allow API server → Polaris
|
||||
3. Check Polaris pod is running
|
||||
@@ -434,6 +453,7 @@ If Polaris responds slowly:
|
||||
**Cause**: API returned HTML (error page) instead of JSON
|
||||
|
||||
**Solution**:
|
||||
|
||||
1. Check Network tab response body (likely 404 or 500 error page)
|
||||
2. Verify Polaris service exists and is healthy
|
||||
3. Check service proxy URL is correct
|
||||
@@ -453,6 +473,7 @@ If Polaris responds slowly:
|
||||
**Cause**: Polaris returned empty or malformed response
|
||||
|
||||
**Solution**:
|
||||
|
||||
1. Check Polaris logs for errors
|
||||
2. Verify Polaris is scanning the cluster (check audit timestamp)
|
||||
3. Test `/results.json` endpoint directly
|
||||
@@ -538,11 +559,13 @@ kubectl logs -n kube-system kube-apiserver-* | grep polaris-dashboard
|
||||
### Sidecar Fails to Install Plugin
|
||||
|
||||
**Symptoms**:
|
||||
|
||||
- Plugin sidecar logs show download errors
|
||||
- Plugin directory is empty
|
||||
- Settings → Plugins shows nothing
|
||||
|
||||
**Check sidecar logs**:
|
||||
|
||||
```bash
|
||||
kubectl logs -n kube-system deployment/headlamp -c headlamp-plugin
|
||||
```
|
||||
@@ -566,13 +589,15 @@ Error: 404 Not Found
|
||||
```
|
||||
|
||||
**Solution**: Verify `archive-url` in plugin config matches GitHub release:
|
||||
|
||||
```bash
|
||||
kubectl get configmap headlamp-plugin-config -n kube-system -o yaml
|
||||
```
|
||||
|
||||
Expected format:
|
||||
|
||||
```
|
||||
https://github.com/cpfarhood/headlamp-polaris-plugin/releases/download/v0.3.5/headlamp-polaris-plugin-0.3.5.tar.gz
|
||||
https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/download/v0.3.10/polaris-0.3.10.tar.gz
|
||||
```
|
||||
|
||||
---
|
||||
@@ -580,6 +605,7 @@ https://github.com/cpfarhood/headlamp-polaris-plugin/releases/download/v0.3.5/he
|
||||
**3. Permission denied writing to /headlamp/plugins**
|
||||
|
||||
**Solution**: Ensure volume mount is writable:
|
||||
|
||||
```yaml
|
||||
volumeMounts:
|
||||
- name: plugins
|
||||
@@ -591,17 +617,18 @@ volumeMounts:
|
||||
### Plugin Manager Not Working
|
||||
|
||||
**Symptoms**:
|
||||
|
||||
- Headlamp → Settings → Plugins shows "Catalog" tab but plugins don't install
|
||||
- "Install" button does nothing
|
||||
|
||||
**Root Cause**: Plugin manager requires `config.pluginsDir` to be set.
|
||||
|
||||
**Solution**: Configure Headlamp for plugin manager:
|
||||
|
||||
```yaml
|
||||
# HelmRelease values
|
||||
config:
|
||||
pluginsDir: /headlamp/plugins
|
||||
watchPlugins: false # CRITICAL for v0.39.0+
|
||||
```
|
||||
|
||||
---
|
||||
@@ -609,25 +636,30 @@ config:
|
||||
## ArtifactHub Sync Delays
|
||||
|
||||
### Symptoms
|
||||
|
||||
- New version released on GitHub but not showing in ArtifactHub
|
||||
- Headlamp plugin catalog shows old version
|
||||
|
||||
### Root Cause
|
||||
|
||||
ArtifactHub pulls metadata every 30 minutes. There is no webhook or push mechanism.
|
||||
|
||||
### Solution
|
||||
|
||||
**Wait 30 minutes** after pushing a GitHub release, then check:
|
||||
|
||||
```
|
||||
https://artifacthub.io/packages/headlamp/headlamp-polaris-plugin/headlamp-polaris-plugin
|
||||
```
|
||||
|
||||
**Verify metadata**:
|
||||
|
||||
1. Check `artifacthub-pkg.yml` is in repository root
|
||||
2. Check `headlamp/plugin/archive-url` points to GitHub release
|
||||
3. Check `headlamp/plugin/archive-checksum` matches tarball SHA256
|
||||
|
||||
**Force sync** (ArtifactHub UI):
|
||||
|
||||
- Log in to ArtifactHub as package maintainer
|
||||
- Go to package settings
|
||||
- Click "Reindex now"
|
||||
@@ -643,23 +675,28 @@ If none of these solutions work, gather debugging information and open an issue:
|
||||
### Required Information
|
||||
|
||||
1. **Version Information**:
|
||||
|
||||
```bash
|
||||
kubectl get pods -n kube-system -l app.kubernetes.io/name=headlamp -o yaml | grep image:
|
||||
```
|
||||
|
||||
2. **Plugin Version**:
|
||||
|
||||
- Check Settings → Plugins in Headlamp UI
|
||||
- Or: `kubectl exec -n kube-system deployment/headlamp -c headlamp -- cat /headlamp/plugins/headlamp-polaris-plugin/package.json`
|
||||
|
||||
3. **Browser Console Output**:
|
||||
|
||||
- Open DevTools (F12) → Console
|
||||
- Screenshot or copy errors
|
||||
|
||||
4. **Network Tab**:
|
||||
|
||||
- Open DevTools → Network
|
||||
- Screenshot failed requests to `results.json`
|
||||
|
||||
5. **Pod Logs**:
|
||||
|
||||
```bash
|
||||
kubectl logs -n kube-system deployment/headlamp -c headlamp --tail=100
|
||||
kubectl logs -n polaris deployment/polaris-dashboard --tail=100
|
||||
@@ -672,7 +709,7 @@ If none of these solutions work, gather debugging information and open an issue:
|
||||
|
||||
### Where to Get Help
|
||||
|
||||
- **GitHub Issues**: [https://github.com/cpfarhood/headlamp-polaris-plugin/issues](https://github.com/cpfarhood/headlamp-polaris-plugin/issues)
|
||||
- **GitHub Discussions**: [https://github.com/cpfarhood/headlamp-polaris-plugin/discussions](https://github.com/cpfarhood/headlamp-polaris-plugin/discussions)
|
||||
- **GitHub Issues**: [https://github.com/privilegedescalation/headlamp-polaris-plugin/issues](https://github.com/privilegedescalation/headlamp-polaris-plugin/issues)
|
||||
- **GitHub Discussions**: [https://github.com/privilegedescalation/headlamp-polaris-plugin/discussions](https://github.com/privilegedescalation/headlamp-polaris-plugin/discussions)
|
||||
|
||||
Include the debugging information above when opening an issue.
|
||||
|
||||
@@ -87,7 +87,7 @@ dashboard:
|
||||
enabled: true
|
||||
env:
|
||||
- name: CORS_ALLOWED_ORIGINS
|
||||
value: "https://headlamp.example.com"
|
||||
value: 'https://headlamp.example.com'
|
||||
```
|
||||
|
||||
Test CORS headers:
|
||||
|
||||
@@ -70,7 +70,7 @@ metadata:
|
||||
namespace: polaris
|
||||
subjects:
|
||||
- kind: Group
|
||||
name: system:authenticated # All authenticated users
|
||||
name: system:authenticated # All authenticated users
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
roleRef:
|
||||
kind: Role
|
||||
|
||||
@@ -28,12 +28,14 @@ Access plugin settings via **Settings → Plugins → Polaris** in the Headlamp
|
||||
### Impact
|
||||
|
||||
**Affects:**
|
||||
|
||||
- Dashboard overview page
|
||||
- Namespace list and detail views
|
||||
- Inline audit sections on resource pages
|
||||
- App bar score badge
|
||||
|
||||
**API Load:**
|
||||
|
||||
- Each refresh triggers one HTTP GET to Polaris dashboard
|
||||
- Each request is logged in Kubernetes audit logs
|
||||
- Longer intervals reduce API server and audit log pressure
|
||||
@@ -41,16 +43,19 @@ Access plugin settings via **Settings → Plugins → Polaris** in the Headlamp
|
||||
### Performance Considerations
|
||||
|
||||
**For small clusters (<100 pods):**
|
||||
|
||||
- Recommended: 5 minutes (default)
|
||||
- Acceptable: 1 minute (if real-time data is critical)
|
||||
|
||||
**For large clusters (>1000 pods):**
|
||||
|
||||
- Recommended: 10-30 minutes
|
||||
- Reason: Reduces audit log volume and API server load
|
||||
- Example: 10 users × 1-minute refresh = ~14,400 audit logs/day
|
||||
- Example: 10 users × 30-minute refresh = ~480 audit logs/day
|
||||
|
||||
**For production environments:**
|
||||
|
||||
- Start with 5 minutes
|
||||
- Monitor API server metrics and audit log volume
|
||||
- Increase interval if needed
|
||||
@@ -62,6 +67,7 @@ Access plugin settings via **Settings → Plugins → Polaris** in the Headlamp
|
||||
### Default Configuration
|
||||
|
||||
**Service proxy path (default):**
|
||||
|
||||
```
|
||||
/api/v1/namespaces/polaris/services/polaris-dashboard:80/proxy/
|
||||
```
|
||||
@@ -69,6 +75,7 @@ Access plugin settings via **Settings → Plugins → Polaris** in the Headlamp
|
||||
This uses the Kubernetes API server to proxy requests to the Polaris dashboard service in the `polaris` namespace.
|
||||
|
||||
**Advantages:**
|
||||
|
||||
- Uses existing Headlamp authentication (service account or user token)
|
||||
- Works with Headlamp's OIDC and token-auth modes
|
||||
- No additional RBAC or network configuration needed
|
||||
@@ -85,6 +92,7 @@ https://polaris.example.com/
|
||||
```
|
||||
|
||||
**Requirements:**
|
||||
|
||||
- Polaris dashboard must be accessible from browser
|
||||
- CORS must be configured on Polaris to allow Headlamp origin
|
||||
- HTTPS recommended for production
|
||||
@@ -98,6 +106,7 @@ If Polaris is deployed in a different namespace:
|
||||
```
|
||||
|
||||
**Requirements:**
|
||||
|
||||
- Update RBAC Role namespace to match
|
||||
- Service name must still be `polaris-dashboard` (or adjust in URL)
|
||||
|
||||
@@ -131,39 +140,43 @@ http://localhost:8080/
|
||||
**What it does:** Verifies the plugin can reach the Polaris dashboard and fetch audit data.
|
||||
|
||||
**To test:**
|
||||
|
||||
1. Enter Dashboard URL in settings
|
||||
2. Click **Test Connection**
|
||||
3. Wait for response (2-5 seconds)
|
||||
|
||||
**Success Response:**
|
||||
|
||||
```
|
||||
✓ Connected to Polaris v4.2.0
|
||||
```
|
||||
|
||||
**Error Responses:**
|
||||
|
||||
| Error | Meaning | Solution |
|
||||
|-------|---------|----------|
|
||||
| **403 Forbidden** | RBAC permission denied | Check RBAC bindings (see [RBAC Guide](rbac-permissions.md)) |
|
||||
| **404 Not Found** | Polaris service not found | Verify Polaris is running: `kubectl get svc -n polaris` |
|
||||
| **503 Service Unavailable** | Polaris pod not ready | Check pod status: `kubectl get pods -n polaris` |
|
||||
| **Network Error** | Cannot reach URL | Check URL format, CORS (for external), NetworkPolicies |
|
||||
| **CORS Error** | Cross-origin blocked | Configure Polaris dashboard CORS headers |
|
||||
| Error | Meaning | Solution |
|
||||
| --------------------------- | ------------------------- | ----------------------------------------------------------- |
|
||||
| **403 Forbidden** | RBAC permission denied | Check RBAC bindings (see [RBAC Guide](rbac-permissions.md)) |
|
||||
| **404 Not Found** | Polaris service not found | Verify Polaris is running: `kubectl get svc -n polaris` |
|
||||
| **503 Service Unavailable** | Polaris pod not ready | Check pod status: `kubectl get pods -n polaris` |
|
||||
| **Network Error** | Cannot reach URL | Check URL format, CORS (for external), NetworkPolicies |
|
||||
| **CORS Error** | Cross-origin blocked | Configure Polaris dashboard CORS headers |
|
||||
|
||||
### CORS Configuration (External Polaris)
|
||||
|
||||
If using an external Polaris URL, configure CORS to allow Headlamp origin.
|
||||
|
||||
**Polaris Helm values:**
|
||||
|
||||
```yaml
|
||||
dashboard:
|
||||
enabled: true
|
||||
env:
|
||||
- name: CORS_ALLOWED_ORIGINS
|
||||
value: "https://headlamp.example.com"
|
||||
value: 'https://headlamp.example.com'
|
||||
```
|
||||
|
||||
**Test CORS:**
|
||||
|
||||
```bash
|
||||
curl -v -H "Origin: https://headlamp.example.com" \
|
||||
https://polaris.example.com/results.json \
|
||||
@@ -180,25 +193,29 @@ curl -v -H "Origin: https://headlamp.example.com" \
|
||||
Plugin settings are stored in browser **localStorage**:
|
||||
|
||||
**Keys:**
|
||||
|
||||
- `polaris-plugin-refresh-interval` - Refresh interval in seconds (number)
|
||||
- `polaris-plugin-dashboard-url` - Dashboard URL (string)
|
||||
|
||||
**View settings:**
|
||||
|
||||
```javascript
|
||||
// Open browser DevTools Console (F12)
|
||||
console.log('Refresh Interval:', localStorage.getItem('polaris-plugin-refresh-interval'))
|
||||
console.log('Dashboard URL:', localStorage.getItem('polaris-plugin-dashboard-url'))
|
||||
console.log('Refresh Interval:', localStorage.getItem('polaris-plugin-refresh-interval'));
|
||||
console.log('Dashboard URL:', localStorage.getItem('polaris-plugin-dashboard-url'));
|
||||
```
|
||||
|
||||
**Reset to defaults:**
|
||||
|
||||
```javascript
|
||||
// Open browser DevTools Console (F12)
|
||||
localStorage.removeItem('polaris-plugin-refresh-interval')
|
||||
localStorage.removeItem('polaris-plugin-dashboard-url')
|
||||
localStorage.removeItem('polaris-plugin-refresh-interval');
|
||||
localStorage.removeItem('polaris-plugin-dashboard-url');
|
||||
// Hard refresh browser: Cmd+Shift+R (Mac) or Ctrl+Shift+R (Windows/Linux)
|
||||
```
|
||||
|
||||
**Notes:**
|
||||
|
||||
- Settings are per-browser, per-user
|
||||
- Private/incognito mode may clear settings on browser close
|
||||
- Settings are NOT synced across devices
|
||||
@@ -208,6 +225,7 @@ localStorage.removeItem('polaris-plugin-dashboard-url')
|
||||
### For Development Clusters
|
||||
|
||||
**Recommended Settings:**
|
||||
|
||||
- **Refresh Interval:** 1-5 minutes (faster feedback loop)
|
||||
- **Dashboard URL:** Service proxy (default)
|
||||
|
||||
@@ -216,6 +234,7 @@ localStorage.removeItem('polaris-plugin-dashboard-url')
|
||||
### For Staging Clusters
|
||||
|
||||
**Recommended Settings:**
|
||||
|
||||
- **Refresh Interval:** 5-10 minutes (balanced)
|
||||
- **Dashboard URL:** Service proxy (default)
|
||||
|
||||
@@ -224,6 +243,7 @@ localStorage.removeItem('polaris-plugin-dashboard-url')
|
||||
### For Production Clusters
|
||||
|
||||
**Recommended Settings:**
|
||||
|
||||
- **Refresh Interval:** 10-30 minutes (reduce load)
|
||||
- **Dashboard URL:** Service proxy (default)
|
||||
|
||||
@@ -232,6 +252,7 @@ localStorage.removeItem('polaris-plugin-dashboard-url')
|
||||
### For Multi-Tenant Environments
|
||||
|
||||
**Recommended Settings:**
|
||||
|
||||
- **Refresh Interval:** 10-30 minutes (minimize per-user load)
|
||||
- **Dashboard URL:** Service proxy with per-namespace RBAC
|
||||
|
||||
@@ -240,6 +261,7 @@ localStorage.removeItem('polaris-plugin-dashboard-url')
|
||||
### For External Polaris
|
||||
|
||||
**Recommended Settings:**
|
||||
|
||||
- **Refresh Interval:** 5-10 minutes (depends on network latency)
|
||||
- **Dashboard URL:** `https://polaris.example.com/`
|
||||
- **CORS:** Must be configured on Polaris side
|
||||
@@ -253,17 +275,19 @@ localStorage.removeItem('polaris-plugin-dashboard-url')
|
||||
**Symptom:** Changes to settings revert after clicking Save
|
||||
|
||||
**Possible Causes:**
|
||||
|
||||
1. Browser blocks localStorage (privacy mode)
|
||||
2. Browser extension interfering
|
||||
3. JavaScript error in console
|
||||
|
||||
**Solution:**
|
||||
|
||||
1. Open browser DevTools Console (F12)
|
||||
2. Check for JavaScript errors
|
||||
3. Disable privacy mode or try different browser
|
||||
4. Check if localStorage is enabled:
|
||||
```javascript
|
||||
console.log('localStorage available:', typeof localStorage !== 'undefined')
|
||||
console.log('localStorage available:', typeof localStorage !== 'undefined');
|
||||
```
|
||||
|
||||
### Settings Lost After Browser Restart
|
||||
@@ -273,6 +297,7 @@ localStorage.removeItem('polaris-plugin-dashboard-url')
|
||||
**Cause:** Browser privacy settings clear localStorage on exit
|
||||
|
||||
**Solution:**
|
||||
|
||||
- Use normal browsing mode (not private/incognito)
|
||||
- Check browser settings for "Clear data on exit"
|
||||
- Consider requesting ConfigMap-based settings (future feature)
|
||||
@@ -284,6 +309,7 @@ localStorage.removeItem('polaris-plugin-dashboard-url')
|
||||
**Solutions by error type:**
|
||||
|
||||
**403 Forbidden:**
|
||||
|
||||
```bash
|
||||
# Verify RBAC exists
|
||||
kubectl -n polaris get role polaris-proxy-reader
|
||||
@@ -297,6 +323,7 @@ kubectl auth can-i get services/proxy \
|
||||
```
|
||||
|
||||
**404 Not Found:**
|
||||
|
||||
```bash
|
||||
# Verify Polaris is running
|
||||
kubectl -n polaris get pods
|
||||
@@ -310,6 +337,7 @@ helm install polaris fairwinds-stable/polaris \
|
||||
```
|
||||
|
||||
**503 Service Unavailable:**
|
||||
|
||||
```bash
|
||||
# Check pod status
|
||||
kubectl -n polaris get pods
|
||||
@@ -319,6 +347,7 @@ kubectl -n polaris logs deployment/polaris-dashboard
|
||||
```
|
||||
|
||||
**Network Error / CORS:**
|
||||
|
||||
```bash
|
||||
# For external Polaris, test CORS
|
||||
curl -v -H "Origin: https://headlamp.example.com" \
|
||||
@@ -332,15 +361,17 @@ curl -v -H "Origin: https://headlamp.example.com" \
|
||||
**Symptom:** Data doesn't refresh automatically
|
||||
|
||||
**Check:**
|
||||
|
||||
1. Verify setting is saved (localStorage key exists)
|
||||
2. Check browser console for errors
|
||||
3. Verify Polaris is returning data (manual refresh works)
|
||||
4. Ensure you're on a Polaris plugin page (not other Headlamp pages)
|
||||
|
||||
**Debug:**
|
||||
|
||||
```javascript
|
||||
// Check refresh interval
|
||||
console.log(localStorage.getItem('polaris-plugin-refresh-interval'))
|
||||
console.log(localStorage.getItem('polaris-plugin-refresh-interval'));
|
||||
|
||||
// Should return: "300" (5 minutes), "600" (10 minutes), etc.
|
||||
```
|
||||
@@ -361,6 +392,7 @@ Before going to production, verify:
|
||||
## Future Configuration Options
|
||||
|
||||
**Planned features:**
|
||||
|
||||
- ConfigMap-based settings (server-side, not localStorage)
|
||||
- Per-cluster settings (multi-cluster Headlamp support)
|
||||
- Webhook notifications for score changes
|
||||
|
||||
@@ -58,6 +58,7 @@ Click the refresh button to fetch the latest audit data immediately (bypasses au
|
||||
Navigate to **Polaris → Namespaces** to see all namespaces with audit results.
|
||||
|
||||
**Table Columns:**
|
||||
|
||||
- **Namespace** - Clickable namespace name (opens detail panel)
|
||||
- **Score** - Per-namespace score with color coding
|
||||
- **Pass** - Passing checks count
|
||||
@@ -72,6 +73,7 @@ Navigate to **Polaris → Namespaces** to see all namespaces with audit results.
|
||||
Click any namespace to open a 1000px-wide side panel with detailed information.
|
||||
|
||||
**Features:**
|
||||
|
||||
- **Namespace Score** - Color-coded score gauge
|
||||
- **Check Counts** - Pass/Warning/Danger/Skipped breakdown
|
||||
- **Resource Table** - Per-resource audit results:
|
||||
@@ -92,6 +94,7 @@ Polaris audit results automatically appear on resource detail pages.
|
||||
### Supported Resources
|
||||
|
||||
Inline audit sections appear on:
|
||||
|
||||
- Deployments
|
||||
- StatefulSets
|
||||
- DaemonSets
|
||||
@@ -101,6 +104,7 @@ Inline audit sections appear on:
|
||||
### What's Shown
|
||||
|
||||
**Compact Audit Section:**
|
||||
|
||||
- **Score Badge** - Color-coded score
|
||||
- **Check Counts** - Pass/Warning/Danger summary
|
||||
- **Failing Checks Table** - Only failed checks listed:
|
||||
@@ -116,14 +120,15 @@ Inline audit sections appear on:
|
||||
Top-right corner of Headlamp shows a persistent cluster score badge.
|
||||
|
||||
**Features:**
|
||||
|
||||
- **Color-Coded Chip** - Green/Yellow/Red based on score
|
||||
- **Shield Emoji (🛡️)** - Visual indicator
|
||||
- **Shield Icon** - Visual indicator
|
||||
- **Score Percentage** - e.g., "85%"
|
||||
- **Clickable** - Click to navigate to Polaris overview
|
||||
- **Real-Time Updates** - Updates on auto-refresh interval
|
||||
- **Always Visible** - Appears on all Headlamp pages
|
||||
|
||||
**Example:** `🛡️ 85%` (green chip)
|
||||
**Example:** Shield icon with "85%" (green chip)
|
||||
|
||||
## Settings & Configuration
|
||||
|
||||
@@ -134,12 +139,14 @@ Access plugin settings via **Settings → Plugins → Polaris**.
|
||||
Controls how often the plugin fetches new audit data.
|
||||
|
||||
**Options:**
|
||||
|
||||
- 1 minute - Most frequent (highest API load)
|
||||
- 5 minutes - **Default** (recommended)
|
||||
- 10 minutes - Moderate refresh rate
|
||||
- 30 minutes - Light load (large clusters)
|
||||
|
||||
**Impact:**
|
||||
|
||||
- Affects all views (dashboard, namespaces, inline audits, app bar badge)
|
||||
- Longer intervals reduce Kubernetes API audit logging
|
||||
- Changes take effect immediately (no restart required)
|
||||
@@ -151,11 +158,13 @@ See [Configuration Guide](configuration.md) for details.
|
||||
Specifies which Polaris instance to connect to.
|
||||
|
||||
**Default:** Kubernetes service proxy path
|
||||
|
||||
```
|
||||
/api/v1/namespaces/polaris/services/polaris-dashboard:80/proxy/
|
||||
```
|
||||
|
||||
**Custom Options:**
|
||||
|
||||
- External Polaris: `https://polaris.example.com/`
|
||||
- Different namespace: `/api/v1/namespaces/custom-ns/services/polaris-dashboard:80/proxy/`
|
||||
|
||||
@@ -168,6 +177,7 @@ See [Configuration Guide](configuration.md) for advanced setup.
|
||||
Full theme adaptation for Headlamp's light and dark modes.
|
||||
|
||||
**Features:**
|
||||
|
||||
- **Auto Dark Mode** - Respects system preference when Headlamp uses it
|
||||
- **Theme Toggle** - Adapts when you change Headlamp theme
|
||||
- **All UI Elements** - Drawer backgrounds, tables, buttons, badges, score gauge
|
||||
@@ -180,6 +190,7 @@ Full theme adaptation for Headlamp's light and dark modes.
|
||||
**Status:** Planned feature (UI components exist but not fully integrated)
|
||||
|
||||
**Future Capability:**
|
||||
|
||||
- View current exemptions on resources
|
||||
- Add exemptions for specific failing checks
|
||||
- Remove exemptions
|
||||
@@ -190,21 +201,25 @@ This feature requires additional RBAC permissions (PATCH on workload resources)
|
||||
## Data Refresh Behavior
|
||||
|
||||
**Initial Load:**
|
||||
|
||||
- Data fetched when you first navigate to any Polaris view
|
||||
- Shared across all views via React Context (no duplicate fetches)
|
||||
- Loading spinner displayed during initial fetch
|
||||
|
||||
**Auto-Refresh:**
|
||||
|
||||
- Configured via Settings → Plugins → Polaris
|
||||
- Default: 5 minutes
|
||||
- Triggers background fetch without disrupting UI
|
||||
|
||||
**Manual Refresh:**
|
||||
|
||||
- Click refresh button on overview dashboard
|
||||
- Forces immediate data fetch
|
||||
- Updates all views simultaneously
|
||||
|
||||
**Error Handling:**
|
||||
|
||||
- 403 errors show RBAC permission guidance
|
||||
- 404/503 errors indicate Polaris not installed
|
||||
- Network errors show generic failure with retry suggestion
|
||||
@@ -212,12 +227,14 @@ This feature requires additional RBAC permissions (PATCH on workload resources)
|
||||
## Browser Requirements
|
||||
|
||||
**Supported Browsers:**
|
||||
|
||||
- Chrome/Chromium 80+
|
||||
- Firefox 75+
|
||||
- Safari 13.1+
|
||||
- Edge 80+
|
||||
|
||||
**Required:**
|
||||
|
||||
- JavaScript enabled
|
||||
- localStorage enabled (for settings persistence)
|
||||
- Cookies enabled (for Headlamp session)
|
||||
@@ -227,11 +244,13 @@ This feature requires additional RBAC permissions (PATCH on workload resources)
|
||||
**Bundle Size:** ~27 KB minified (gzip: ~7.6 KB)
|
||||
|
||||
**Data Volume:** Depends on cluster size. Example:
|
||||
|
||||
- Small cluster (50 resources): ~100 KB JSON
|
||||
- Medium cluster (500 resources): ~1 MB JSON
|
||||
- Large cluster (5000 resources): ~10 MB JSON
|
||||
|
||||
**Rendering Performance:**
|
||||
|
||||
- Handles up to 100 namespaces without virtual scrolling
|
||||
- Namespace detail drawer renders instantly for up to 500 resources
|
||||
- React Context prevents unnecessary re-fetches
|
||||
|
||||
@@ -13,6 +13,7 @@ The plugin requires **one permission** to function:
|
||||
This allows the plugin to fetch audit results via the Kubernetes service proxy.
|
||||
|
||||
**Why this permission?**
|
||||
|
||||
- Plugin accesses Polaris through Kubernetes API server's service proxy
|
||||
- Service proxy requires `get` verb on `services/proxy` resource
|
||||
- Scoped to specific service (`polaris-dashboard`) for security
|
||||
@@ -37,13 +38,14 @@ metadata:
|
||||
app.kubernetes.io/name: headlamp-polaris-plugin
|
||||
app.kubernetes.io/component: rbac
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["services/proxy"]
|
||||
resourceNames: ["polaris-dashboard"]
|
||||
verbs: ["get"]
|
||||
- apiGroups: ['']
|
||||
resources: ['services/proxy']
|
||||
resourceNames: ['polaris-dashboard']
|
||||
verbs: ['get']
|
||||
```
|
||||
|
||||
**Key points:**
|
||||
|
||||
- **Role** (not ClusterRole) - Scoped to `polaris` namespace only
|
||||
- **resourceNames** - Restricts access to `polaris-dashboard` service only
|
||||
- **verbs: ["get"]** - Read-only permission
|
||||
@@ -62,8 +64,8 @@ metadata:
|
||||
app.kubernetes.io/component: rbac
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: headlamp # Adjust to your Headlamp SA name
|
||||
namespace: kube-system # Adjust to Headlamp's namespace
|
||||
name: headlamp # Adjust to your Headlamp SA name
|
||||
namespace: kube-system # Adjust to Headlamp's namespace
|
||||
roleRef:
|
||||
kind: Role
|
||||
name: polaris-proxy-reader
|
||||
@@ -71,6 +73,7 @@ roleRef:
|
||||
```
|
||||
|
||||
**Adjust for your environment:**
|
||||
|
||||
- `subjects[0].name` - Your Headlamp service account name (often `headlamp`)
|
||||
- `subjects[0].namespace` - Namespace where Headlamp runs (often `kube-system`)
|
||||
|
||||
@@ -104,10 +107,12 @@ In token-auth mode, **each user's own identity** is used for Kubernetes API requ
|
||||
### Why Per-User RBAC?
|
||||
|
||||
With service account mode:
|
||||
|
||||
- Single RoleBinding grants access to all Headlamp users
|
||||
- Kubernetes sees all requests as `system:serviceaccount:kube-system:headlamp`
|
||||
|
||||
With token-auth mode:
|
||||
|
||||
- Each user's own token (OIDC, kubeconfig) is used
|
||||
- Kubernetes sees requests as `user@example.com` or `system:serviceaccount:team-ns:user-sa`
|
||||
- **Each user needs individual RBAC permissions**
|
||||
@@ -125,7 +130,7 @@ metadata:
|
||||
namespace: polaris
|
||||
subjects:
|
||||
- kind: Group
|
||||
name: system:authenticated # All authenticated users
|
||||
name: system:authenticated # All authenticated users
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
roleRef:
|
||||
kind: Role
|
||||
@@ -174,7 +179,7 @@ metadata:
|
||||
namespace: polaris
|
||||
subjects:
|
||||
- kind: Group
|
||||
name: sre-team # OIDC group claim
|
||||
name: sre-team # OIDC group claim
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
- kind: Group
|
||||
name: devops-team
|
||||
@@ -186,11 +191,13 @@ roleRef:
|
||||
```
|
||||
|
||||
**Requirements:**
|
||||
|
||||
- OIDC provider must include group claims in token
|
||||
- Headlamp must be configured to extract groups from OIDC token
|
||||
- Group names must match exactly (case-sensitive)
|
||||
|
||||
**Example OIDC group claim:**
|
||||
|
||||
```json
|
||||
{
|
||||
"sub": "user@example.com",
|
||||
@@ -229,23 +236,23 @@ apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: polaris-proxy-reader
|
||||
namespace: team-a-polaris # First Polaris instance
|
||||
namespace: team-a-polaris # First Polaris instance
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["services/proxy"]
|
||||
resourceNames: ["polaris-dashboard"]
|
||||
verbs: ["get"]
|
||||
- apiGroups: ['']
|
||||
resources: ['services/proxy']
|
||||
resourceNames: ['polaris-dashboard']
|
||||
verbs: ['get']
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: polaris-proxy-reader
|
||||
namespace: team-b-polaris # Second Polaris instance
|
||||
namespace: team-b-polaris # Second Polaris instance
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["services/proxy"]
|
||||
resourceNames: ["polaris-dashboard"]
|
||||
verbs: ["get"]
|
||||
- apiGroups: ['']
|
||||
resources: ['services/proxy']
|
||||
resourceNames: ['polaris-dashboard']
|
||||
verbs: ['get']
|
||||
```
|
||||
|
||||
### Create RoleBindings per Namespace
|
||||
@@ -343,22 +350,24 @@ When using OAuth2/OIDC authentication with Headlamp:
|
||||
### Required Configuration
|
||||
|
||||
**Headlamp Helm values:**
|
||||
|
||||
```yaml
|
||||
env:
|
||||
- name: HEADLAMP_CONFIG_OIDC_CLIENT_ID
|
||||
value: "headlamp"
|
||||
value: 'headlamp'
|
||||
- name: HEADLAMP_CONFIG_OIDC_CLIENT_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: headlamp-oidc
|
||||
key: client-secret
|
||||
- name: HEADLAMP_CONFIG_OIDC_ISSUER_URL
|
||||
value: "https://auth.example.com/realms/kubernetes"
|
||||
value: 'https://auth.example.com/realms/kubernetes'
|
||||
- name: HEADLAMP_CONFIG_OIDC_SCOPES
|
||||
value: "openid,profile,email,groups"
|
||||
value: 'openid,profile,email,groups'
|
||||
```
|
||||
|
||||
**RBAC for OIDC users:**
|
||||
|
||||
```yaml
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
@@ -368,7 +377,7 @@ metadata:
|
||||
namespace: polaris
|
||||
subjects:
|
||||
- kind: Group
|
||||
name: kubernetes-admins # OIDC group claim
|
||||
name: kubernetes-admins # OIDC group claim
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
roleRef:
|
||||
kind: Role
|
||||
@@ -421,32 +430,36 @@ Every plugin data fetch creates a Kubernetes API audit log entry.
|
||||
### Volume Estimates
|
||||
|
||||
**Per user:**
|
||||
|
||||
- 1 refresh per 5 minutes = 288 requests/day
|
||||
- 1 refresh per 30 minutes = 48 requests/day
|
||||
|
||||
**Cluster-wide:**
|
||||
|
||||
- 10 concurrent users × 5-minute refresh = 2,880 audit logs/day
|
||||
- 100 concurrent users × 30-minute refresh = 4,800 audit logs/day
|
||||
|
||||
### Reducing Audit Volume
|
||||
|
||||
**Option 1: Increase refresh interval**
|
||||
|
||||
```
|
||||
Settings → Plugins → Polaris → Refresh Interval → 30 minutes
|
||||
```
|
||||
|
||||
**Option 2: Adjust audit policy level**
|
||||
|
||||
```yaml
|
||||
# kube-apiserver audit policy
|
||||
apiVersion: audit.k8s.io/v1
|
||||
kind: Policy
|
||||
rules:
|
||||
- level: Metadata # Log metadata only, not full request/response
|
||||
verbs: ["get"]
|
||||
- level: Metadata # Log metadata only, not full request/response
|
||||
verbs: ['get']
|
||||
resources:
|
||||
- group: ""
|
||||
resources: ["services/proxy"]
|
||||
namespaces: ["polaris"]
|
||||
- group: ''
|
||||
resources: ['services/proxy']
|
||||
namespaces: ['polaris']
|
||||
```
|
||||
|
||||
**Option 3: Filter audit logs**
|
||||
@@ -461,18 +474,23 @@ If using a log aggregator (e.g., Elasticsearch), create filters to exclude or do
|
||||
**Diagnosis:**
|
||||
|
||||
1. **Check Role exists:**
|
||||
|
||||
```bash
|
||||
kubectl -n polaris get role polaris-proxy-reader
|
||||
```
|
||||
|
||||
If missing: Apply Role manifest
|
||||
|
||||
2. **Check RoleBinding exists:**
|
||||
|
||||
```bash
|
||||
kubectl -n polaris get rolebinding headlamp-polaris-proxy
|
||||
```
|
||||
|
||||
If missing: Apply RoleBinding manifest
|
||||
|
||||
3. **Test permission:**
|
||||
|
||||
```bash
|
||||
# Service account mode
|
||||
kubectl auth can-i get services/proxy \
|
||||
@@ -486,6 +504,7 @@ If using a log aggregator (e.g., Elasticsearch), create filters to exclude or do
|
||||
-n polaris \
|
||||
--resource-name=polaris-dashboard
|
||||
```
|
||||
|
||||
Expected: `yes`
|
||||
|
||||
4. **Verify RoleBinding subjects match:**
|
||||
@@ -499,6 +518,7 @@ If using a log aggregator (e.g., Elasticsearch), create filters to exclude or do
|
||||
**This is NOT an RBAC issue.** 404 means Polaris service doesn't exist.
|
||||
|
||||
**Check:**
|
||||
|
||||
```bash
|
||||
kubectl -n polaris get svc polaris-dashboard
|
||||
```
|
||||
@@ -510,14 +530,17 @@ If missing, install Polaris with dashboard enabled.
|
||||
**Possible causes:**
|
||||
|
||||
1. **Wrong namespace in RoleBinding:**
|
||||
|
||||
- RoleBinding must be in `polaris` namespace (where the service is)
|
||||
- Common mistake: Creating RoleBinding in `kube-system`
|
||||
|
||||
2. **Wrong resourceName:**
|
||||
|
||||
- Must match service name exactly: `polaris-dashboard`
|
||||
- Check: `kubectl -n polaris get svc`
|
||||
|
||||
3. **Browser caching old 403:**
|
||||
|
||||
- Hard refresh browser: Cmd+Shift+R (Mac) or Ctrl+Shift+R (Windows/Linux)
|
||||
|
||||
4. **Token expired (OIDC mode):**
|
||||
@@ -529,6 +552,7 @@ If missing, install Polaris with dashboard enabled.
|
||||
### 1. Use Namespaced Roles (Not ClusterRoles)
|
||||
|
||||
✅ **Good:**
|
||||
|
||||
```yaml
|
||||
kind: Role
|
||||
metadata:
|
||||
@@ -536,6 +560,7 @@ metadata:
|
||||
```
|
||||
|
||||
❌ **Bad:**
|
||||
|
||||
```yaml
|
||||
kind: ClusterRole
|
||||
# Grants access to all namespaces
|
||||
@@ -546,13 +571,15 @@ kind: ClusterRole
|
||||
### 2. Always Specify resourceNames
|
||||
|
||||
✅ **Good:**
|
||||
|
||||
```yaml
|
||||
resourceNames: ["polaris-dashboard"]
|
||||
resourceNames: ['polaris-dashboard']
|
||||
```
|
||||
|
||||
❌ **Bad:**
|
||||
|
||||
```yaml
|
||||
resourceNames: [] # Allows access to ALL services
|
||||
resourceNames: [] # Allows access to ALL services
|
||||
```
|
||||
|
||||
**Why:** `resourceNames` restricts permission to a specific service. Without it, the binding grants access to proxy all services in the namespace.
|
||||
@@ -560,13 +587,15 @@ resourceNames: [] # Allows access to ALL services
|
||||
### 3. Use Read-Only Verb
|
||||
|
||||
✅ **Good:**
|
||||
|
||||
```yaml
|
||||
verbs: ["get"]
|
||||
verbs: ['get']
|
||||
```
|
||||
|
||||
❌ **Bad:**
|
||||
|
||||
```yaml
|
||||
verbs: ["get", "create", "update", "delete"]
|
||||
verbs: ['get', 'create', 'update', 'delete']
|
||||
```
|
||||
|
||||
**Why:** Plugin only needs `get` to fetch audit results. Additional verbs violate principle of least privilege.
|
||||
@@ -580,6 +609,7 @@ verbs: ["get", "create", "update", "delete"]
|
||||
### 5. Monitor Audit Logs
|
||||
|
||||
Set alerts for:
|
||||
|
||||
- Unusual access patterns (e.g., 403 spikes = permission issues)
|
||||
- High request volume (e.g., misconfigured refresh interval)
|
||||
- Access from unexpected users (security monitoring)
|
||||
@@ -587,11 +617,12 @@ Set alerts for:
|
||||
### 6. Avoid Wildcard Permissions
|
||||
|
||||
❌ **Never do this:**
|
||||
|
||||
```yaml
|
||||
rules:
|
||||
- apiGroups: ["*"]
|
||||
resources: ["*"]
|
||||
verbs: ["*"]
|
||||
- apiGroups: ['*']
|
||||
resources: ['*']
|
||||
verbs: ['*']
|
||||
```
|
||||
|
||||
This grants cluster-admin equivalent permissions. Always use specific resources and verbs.
|
||||
|
||||
Generated
+5
-4
@@ -1,12 +1,13 @@
|
||||
{
|
||||
"name": "headlamp-polaris-plugin",
|
||||
"version": "0.2.0",
|
||||
"name": "polaris",
|
||||
"version": "0.5.1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "headlamp-polaris-plugin",
|
||||
"version": "0.2.0",
|
||||
"name": "polaris",
|
||||
"version": "0.5.1",
|
||||
"license": "Apache-2.0",
|
||||
"devDependencies": {
|
||||
"@kinvolk/headlamp-plugin": "^0.13.0",
|
||||
"@playwright/test": "^1.58.2"
|
||||
|
||||
+5
-5
@@ -1,16 +1,16 @@
|
||||
{
|
||||
"name": "polaris",
|
||||
"version": "0.3.9",
|
||||
"version": "0.5.1",
|
||||
"description": "Headlamp plugin for Fairwinds Polaris audit results",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/cpfarhood/headlamp-polaris-plugin.git"
|
||||
"url": "https://github.com/privilegedescalation/headlamp-polaris-plugin.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/cpfarhood/headlamp-polaris-plugin/issues"
|
||||
"url": "https://github.com/privilegedescalation/headlamp-polaris-plugin/issues"
|
||||
},
|
||||
"homepage": "https://github.com/cpfarhood/headlamp-polaris-plugin#readme",
|
||||
"author": "cpfarhood",
|
||||
"homepage": "https://github.com/privilegedescalation/headlamp-polaris-plugin#readme",
|
||||
"author": "privilegedescalation",
|
||||
"license": "Apache-2.0",
|
||||
"scripts": {
|
||||
"start": "headlamp-plugin start",
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": ["config:recommended"]
|
||||
}
|
||||
@@ -35,8 +35,20 @@ const PolarisDataContext = React.createContext<PolarisDataContextValue | null>(n
|
||||
* ```
|
||||
*/
|
||||
export function PolarisDataProvider(props: { children: React.ReactNode }) {
|
||||
const interval = getRefreshInterval();
|
||||
const state = usePolarisData(interval);
|
||||
// Re-read interval on every render to pick up changes from settings
|
||||
const [refreshInterval, setRefreshInterval] = React.useState(getRefreshInterval());
|
||||
|
||||
// Poll for interval changes (localStorage changes from settings)
|
||||
React.useEffect(() => {
|
||||
const intervalId = window.setInterval(() => {
|
||||
const newInterval = getRefreshInterval();
|
||||
setRefreshInterval(prev => (prev !== newInterval ? newInterval : prev));
|
||||
}, 1000); // Check every second
|
||||
|
||||
return () => window.clearInterval(intervalId);
|
||||
}, []);
|
||||
|
||||
const state = usePolarisData(refreshInterval);
|
||||
|
||||
// Rename triggerRefresh to refresh for consistency
|
||||
const value = React.useMemo(
|
||||
|
||||
+3
-1
@@ -373,7 +373,9 @@ export function usePolarisData(refreshIntervalSeconds: number): PolarisDataState
|
||||
result = await response.json();
|
||||
} else {
|
||||
// Kubernetes proxy for relative URLs
|
||||
result = await ApiProxy.request(apiPath);
|
||||
result = await ApiProxy.request(apiPath, {
|
||||
method: 'GET',
|
||||
});
|
||||
}
|
||||
|
||||
if (!cancelled) {
|
||||
|
||||
@@ -44,6 +44,7 @@ interface NamespaceDetailPanelProps {
|
||||
}
|
||||
|
||||
function NamespaceDetailPanel({ namespace, onClose }: NamespaceDetailPanelProps) {
|
||||
const [isMaximized, setIsMaximized] = React.useState(false);
|
||||
const { data, loading, error } = usePolarisDataContext();
|
||||
|
||||
if (loading) {
|
||||
@@ -107,13 +108,14 @@ function NamespaceDetailPanel({ namespace, onClose }: NamespaceDetailPanelProps)
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 1000px;
|
||||
width: ${isMaximized ? 'calc(100vw - 240px)' : '1000px'};
|
||||
background-color: var(--mui-palette-background-default, #fafafa);
|
||||
color: var(--mui-palette-text-primary);
|
||||
box-shadow: -2px 0 8px rgba(0,0,0,0.15);
|
||||
overflow-y: auto;
|
||||
z-index: 1200;
|
||||
padding: 20px;
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
@@ -129,20 +131,54 @@ function NamespaceDetailPanel({ namespace, onClose }: NamespaceDetailPanelProps)
|
||||
<h2 style={{ margin: 0, color: 'var(--mui-palette-text-primary)' }}>
|
||||
Polaris — {namespace}
|
||||
</h2>
|
||||
<button
|
||||
onClick={onClose}
|
||||
style={{
|
||||
border: 'none',
|
||||
background: 'transparent',
|
||||
fontSize: '24px',
|
||||
cursor: 'pointer',
|
||||
padding: '0 8px',
|
||||
color: 'var(--mui-palette-text-primary)',
|
||||
}}
|
||||
aria-label="Close panel"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
<div style={{ display: 'flex', gap: '8px', alignItems: 'center' }}>
|
||||
<button
|
||||
onClick={() => setIsMaximized(!isMaximized)}
|
||||
style={{
|
||||
border: 'none',
|
||||
background: 'transparent',
|
||||
fontSize: '20px',
|
||||
cursor: 'pointer',
|
||||
padding: '4px 8px',
|
||||
color: 'var(--mui-palette-text-secondary, #666)',
|
||||
borderRadius: '4px',
|
||||
}}
|
||||
onMouseEnter={e => {
|
||||
e.currentTarget.style.backgroundColor =
|
||||
'var(--mui-palette-action-hover, rgba(0, 0, 0, 0.04))';
|
||||
}}
|
||||
onMouseLeave={e => {
|
||||
e.currentTarget.style.backgroundColor = 'transparent';
|
||||
}}
|
||||
aria-label={isMaximized ? 'Minimize panel' : 'Maximize panel'}
|
||||
title={isMaximized ? 'Minimize' : 'Maximize'}
|
||||
>
|
||||
{isMaximized ? '⊟' : '⊡'}
|
||||
</button>
|
||||
<button
|
||||
onClick={onClose}
|
||||
style={{
|
||||
border: 'none',
|
||||
background: 'transparent',
|
||||
fontSize: '24px',
|
||||
cursor: 'pointer',
|
||||
padding: '4px 8px',
|
||||
color: 'var(--mui-palette-text-secondary, #666)',
|
||||
borderRadius: '4px',
|
||||
}}
|
||||
onMouseEnter={e => {
|
||||
e.currentTarget.style.backgroundColor =
|
||||
'var(--mui-palette-action-hover, rgba(0, 0, 0, 0.04))';
|
||||
}}
|
||||
onMouseLeave={e => {
|
||||
e.currentTarget.style.backgroundColor = 'transparent';
|
||||
}}
|
||||
aria-label="Close panel"
|
||||
title="Close"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<SectionBox title="External">
|
||||
|
||||
@@ -58,7 +58,9 @@ export default function PolarisSettings(props: PluginSettingsProps) {
|
||||
}
|
||||
result = await response.json();
|
||||
} else {
|
||||
result = await ApiProxy.request(apiPath);
|
||||
result = await ApiProxy.request(apiPath, {
|
||||
method: 'GET',
|
||||
});
|
||||
}
|
||||
|
||||
setTestResult({
|
||||
|
||||
+1
-1
@@ -66,7 +66,7 @@ registerRoute({
|
||||
});
|
||||
|
||||
// Register plugin settings
|
||||
registerPluginSettings('headlamp-polaris-plugin', PolarisSettings, true);
|
||||
registerPluginSettings('polaris', PolarisSettings, true);
|
||||
|
||||
// Register details view section for supported controller types
|
||||
registerDetailsViewSection(({ resource }) => {
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"extends": "@kinvolk/headlamp-plugin/config/plugins-tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"types": ["vite/client", "vite-plugin-svgr/client", "vitest/globals", "lodash", "@testing-library/jest-dom"]
|
||||
"types": ["vite/client", "vite-plugin-svgr/client", "vitest/globals", "@testing-library/jest-dom"]
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user