Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9b9052243f | |||
| b772209b65 | |||
| f2b0e4c66f | |||
| 4f937efe26 | |||
| d23ccf3a84 | |||
| 13bdb9901a | |||
| f575623b93 | |||
| a46d0e7519 | |||
| 2da1fb3099 | |||
| 28f432f2bf | |||
| 23148bfaff | |||
| ed38df7215 | |||
| 40a4b8accc | |||
| 86f959486a | |||
| c621bd1384 | |||
| e574ea66e2 | |||
| 49bcbe24af | |||
| fdad1a6da2 | |||
| 7bf00593ef | |||
| 1ca90a7570 | |||
| dbc69fb41f | |||
| 24033ca977 |
@@ -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,9 +5,10 @@ on:
|
|||||||
branches: [main]
|
branches: [main]
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [main]
|
branches: [main]
|
||||||
|
workflow_call:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
lint-and-test:
|
ci:
|
||||||
runs-on: local-ubuntu-latest
|
runs-on: local-ubuntu-latest
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
|
|
||||||
@@ -18,7 +19,7 @@ jobs:
|
|||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: '20'
|
node-version: '22'
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
@@ -28,13 +29,13 @@ jobs:
|
|||||||
run: npx @kinvolk/headlamp-plugin build
|
run: npx @kinvolk/headlamp-plugin build
|
||||||
|
|
||||||
- name: Lint
|
- name: Lint
|
||||||
run: npx eslint --ext .ts,.tsx src/
|
run: npm run lint
|
||||||
|
|
||||||
- name: Type-check
|
- name: Type-check
|
||||||
run: npx tsc --noEmit
|
run: npm run tsc
|
||||||
|
|
||||||
- name: Format check
|
- name: Format check
|
||||||
run: npx prettier --check src/
|
run: npm run format:check
|
||||||
|
|
||||||
- name: Run unit tests
|
- name: Run tests
|
||||||
run: npm test
|
run: npm test
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
e2e:
|
e2e:
|
||||||
runs-on: k3s-animaniacs
|
runs-on: local-ubuntu-latest
|
||||||
timeout-minutes: 15
|
timeout-minutes: 15
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@@ -31,7 +31,7 @@ jobs:
|
|||||||
- name: Run E2E tests
|
- name: Run E2E tests
|
||||||
run: npm run e2e
|
run: npm run e2e
|
||||||
env:
|
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 }}
|
HEADLAMP_TOKEN: ${{ secrets.HEADLAMP_TOKEN }}
|
||||||
AUTHENTIK_USERNAME: ${{ secrets.AUTHENTIK_USERNAME }}
|
AUTHENTIK_USERNAME: ${{ secrets.AUTHENTIK_USERNAME }}
|
||||||
AUTHENTIK_PASSWORD: ${{ secrets.AUTHENTIK_PASSWORD }}
|
AUTHENTIK_PASSWORD: ${{ secrets.AUTHENTIK_PASSWORD }}
|
||||||
|
|||||||
@@ -4,50 +4,59 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
version:
|
version:
|
||||||
description: 'Version to release (without v prefix, e.g., 0.4.0)'
|
description: 'Release version (e.g. 1.0.0)'
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: release
|
||||||
|
cancel-in-progress: false
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
ci:
|
||||||
|
uses: ./.github/workflows/ci.yaml
|
||||||
|
|
||||||
release:
|
release:
|
||||||
|
needs: ci
|
||||||
runs-on: local-ubuntu-latest
|
runs-on: local-ubuntu-latest
|
||||||
permissions:
|
timeout-minutes: 10
|
||||||
contents: write
|
|
||||||
steps:
|
steps:
|
||||||
- name: Validate version format
|
- name: Validate version format
|
||||||
run: |
|
run: |
|
||||||
if ! echo "${{ inputs.version }}" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then
|
if [[ ! "${{ inputs.version }}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||||
echo "::error::Version must be in format X.Y.Z (e.g., 0.4.0)"
|
echo "Error: Version must be in X.Y.Z format"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Configure git
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '22'
|
||||||
|
cache: 'npm'
|
||||||
|
|
||||||
|
- name: Configure Git
|
||||||
run: |
|
run: |
|
||||||
git config user.name "github-actions[bot]"
|
git config user.name "github-actions[bot]"
|
||||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||||
|
|
||||||
- name: Update package.json version
|
- name: Update version in package.json
|
||||||
run: |
|
run: npm version ${{ inputs.version }} --no-git-tag-version --allow-same-version
|
||||||
jq --arg version "${{ inputs.version }}" '.version = $version' package.json > package.json.tmp
|
|
||||||
mv package.json.tmp package.json
|
|
||||||
|
|
||||||
- name: Update artifacthub-pkg.yml version
|
- name: Update artifacthub-pkg.yml
|
||||||
run: |
|
run: |
|
||||||
VERSION="${{ inputs.version }}"
|
VERSION="${{ inputs.version }}"
|
||||||
RELEASE_URL="https://github.com/${{ github.repository }}/releases/download/v${VERSION}/polaris-${VERSION}.tar.gz"
|
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/^version:.*/version: \"${VERSION}\"/" artifacthub-pkg.yml
|
||||||
sed -i "s|headlamp/plugin/archive-url:.*|headlamp/plugin/archive-url: \"${RELEASE_URL}\"|" artifacthub-pkg.yml
|
sed -i "s|headlamp/plugin/archive-url:.*|headlamp/plugin/archive-url: \"${RELEASE_URL}\"|" artifacthub-pkg.yml
|
||||||
|
|
||||||
- name: Setup Node.js
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: '20'
|
|
||||||
cache: 'npm'
|
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: npm ci
|
run: npm ci
|
||||||
|
|
||||||
@@ -57,55 +66,41 @@ jobs:
|
|||||||
- name: Package plugin
|
- name: Package plugin
|
||||||
run: npx @kinvolk/headlamp-plugin package
|
run: npx @kinvolk/headlamp-plugin package
|
||||||
|
|
||||||
- name: Validate tarball name
|
- name: Prepare release tarball
|
||||||
run: |
|
run: |
|
||||||
EXPECTED="polaris-${{ inputs.version }}.tar.gz"
|
VERSION="${{ inputs.version }}"
|
||||||
ACTUAL=$(ls *.tar.gz)
|
PKG_NAME=$(jq -r .name package.json)
|
||||||
if [ "$EXPECTED" != "$ACTUAL" ]; then
|
TARBALL="${PKG_NAME}-${VERSION}.tar.gz"
|
||||||
echo "::error::Tarball name mismatch! Expected: $EXPECTED, Got: $ACTUAL"
|
echo "TARBALL=$TARBALL" >> $GITHUB_ENV
|
||||||
exit 1
|
echo "PKG_NAME=$PKG_NAME" >> $GITHUB_ENV
|
||||||
fi
|
|
||||||
echo "✓ Tarball name validated: $ACTUAL"
|
- 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
|
- name: Compute checksum
|
||||||
id: compute_checksum
|
|
||||||
run: |
|
run: |
|
||||||
TARBALL="polaris-${{ inputs.version }}.tar.gz"
|
CHECKSUM=$(sha256sum "${{ env.TARBALL }}" | awk '{print $1}')
|
||||||
CHECKSUM=$(sha256sum "$TARBALL" | awk '{print $1}')
|
echo "CHECKSUM=$CHECKSUM" >> $GITHUB_ENV
|
||||||
echo "checksum=${CHECKSUM}" >> $GITHUB_OUTPUT
|
|
||||||
echo "Checksum: sha256:${CHECKSUM}"
|
|
||||||
|
|
||||||
- name: Update checksum in metadata
|
|
||||||
run: |
|
|
||||||
CHECKSUM="${{ steps.compute_checksum.outputs.checksum }}"
|
|
||||||
sed -i "s|headlamp/plugin/archive-checksum:.*|headlamp/plugin/archive-checksum: sha256:${CHECKSUM}|" artifacthub-pkg.yml
|
sed -i "s|headlamp/plugin/archive-checksum:.*|headlamp/plugin/archive-checksum: sha256:${CHECKSUM}|" artifacthub-pkg.yml
|
||||||
|
|
||||||
- name: Commit version bump and metadata
|
- name: Commit and tag
|
||||||
run: |
|
run: |
|
||||||
git add package.json artifacthub-pkg.yml
|
VERSION="${{ inputs.version }}"
|
||||||
git commit -m "chore: release v${{ inputs.version }}"
|
git add package.json package-lock.json artifacthub-pkg.yml
|
||||||
git push origin main
|
git commit -m "release: v${VERSION}"
|
||||||
|
git tag "v${VERSION}"
|
||||||
- name: Create and push tag
|
git push origin main --tags
|
||||||
run: |
|
|
||||||
git tag "v${{ inputs.version }}"
|
|
||||||
git push origin "v${{ inputs.version }}"
|
|
||||||
|
|
||||||
- name: Create GitHub Release
|
- name: Create GitHub Release
|
||||||
uses: softprops/action-gh-release@v2
|
uses: softprops/action-gh-release@v2
|
||||||
with:
|
with:
|
||||||
tag_name: "v${{ inputs.version }}"
|
tag_name: "v${{ inputs.version }}"
|
||||||
files: polaris-${{ inputs.version }}.tar.gz
|
files: ${{ env.TARBALL }}
|
||||||
fail_on_unmatched_files: true
|
fail_on_unmatched_files: true
|
||||||
draft: false
|
|
||||||
prerelease: false
|
|
||||||
generate_release_notes: true
|
generate_release_notes: true
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Summary
|
|
||||||
run: |
|
|
||||||
echo "✓ Version bumped to ${{ inputs.version }}"
|
|
||||||
echo "✓ Metadata updated with checksum sha256:${{ steps.compute_checksum.outputs.checksum }}"
|
|
||||||
echo "✓ Tag v${{ inputs.version }} created"
|
|
||||||
echo "✓ GitHub release published with tarball"
|
|
||||||
|
|||||||
+1
-1
@@ -1,10 +1,10 @@
|
|||||||
node_modules/
|
node_modules/
|
||||||
dist/
|
dist/
|
||||||
.headlamp-plugin/
|
.headlamp-plugin/
|
||||||
.mcp.json
|
|
||||||
*.tar.gz
|
*.tar.gz
|
||||||
e2e/.auth/
|
e2e/.auth/
|
||||||
test-results/
|
test-results/
|
||||||
.playwright-mcp/
|
.playwright-mcp/
|
||||||
.env
|
.env
|
||||||
.env.local
|
.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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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: {} },
|
||||||
|
}));
|
||||||
|
```
|
||||||
@@ -50,14 +50,11 @@ Polaris must be deployed in the `polaris` namespace with the dashboard component
|
|||||||
|
|
||||||
### Option 1: Headlamp Plugin Manager (Recommended)
|
### 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:
|
The plugin is published on [Artifact Hub](https://artifacthub.io/packages/headlamp/polaris/headlamp-polaris-plugin). Configure Headlamp via Helm:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
config:
|
config:
|
||||||
pluginsDir: /headlamp/plugins
|
pluginsDir: /headlamp/plugins
|
||||||
watchPlugins: false # CRITICAL for v0.39.0+
|
|
||||||
|
|
||||||
pluginsManager:
|
pluginsManager:
|
||||||
sources:
|
sources:
|
||||||
@@ -182,14 +179,14 @@ Every proxied request is recorded in Kubernetes API audit logs as a `get` on `se
|
|||||||
|
|
||||||
### Comprehensive Guides
|
### Comprehensive Guides
|
||||||
|
|
||||||
| Guide | Description |
|
| Guide | Description |
|
||||||
|-------|-------------|
|
| ------------------------------------------------- | --------------------------------------------------------------------- |
|
||||||
| **[Architecture](docs/architecture/overview.md)** | System architecture, data flow, component hierarchy, design decisions |
|
| **[Architecture](docs/architecture/overview.md)** | System architecture, data flow, component hierarchy, design decisions |
|
||||||
| **[Deployment](docs/deployment/helm.md)** | Production deployment with Helm, Kubernetes, FluxCD |
|
| **[Deployment](docs/deployment/helm.md)** | Production deployment with Helm, Kubernetes, FluxCD |
|
||||||
| **[Security](SECURITY.md)** | Security model, RBAC requirements, vulnerability reporting |
|
| **[Security](SECURITY.md)** | Security model, RBAC requirements, vulnerability reporting |
|
||||||
| **[Testing](docs/development/testing.md)** | Unit tests, E2E tests, CI/CD, best practices |
|
| **[Testing](docs/development/testing.md)** | Unit tests, E2E tests, CI/CD, best practices |
|
||||||
| **[Contributing](CONTRIBUTING.md)** | Development workflow, branching strategy, PR process |
|
| **[Contributing](CONTRIBUTING.md)** | Development workflow, branching strategy, PR process |
|
||||||
| **[Changelog](CHANGELOG.md)** | Complete release history (v0.0.1 to current) |
|
| **[Changelog](CHANGELOG.md)** | Complete release history (v0.0.1 to current) |
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
@@ -197,14 +194,14 @@ Every proxied request is recorded in Kubernetes API audit logs as a `get` on `se
|
|||||||
|
|
||||||
Quick reference:
|
Quick reference:
|
||||||
|
|
||||||
| Symptom | Likely Cause | Quick Fix |
|
| 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) |
|
| **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 |
|
| **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 |
|
| **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 |
|
| **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+ |
|
| **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` |
|
| **No data / infinite spinner** | Network policy or Polaris pod down | Check network policies and `kubectl get pods -n polaris` |
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
@@ -373,4 +370,3 @@ Contributions are welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md) for:
|
|||||||
## License
|
## License
|
||||||
|
|
||||||
[Apache-2.0 License](LICENSE) - see LICENSE file for details.
|
[Apache-2.0 License](LICENSE) - see LICENSE file for details.
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -1,4 +1,4 @@
|
|||||||
version: 0.5.0
|
version: "0.5.2"
|
||||||
name: headlamp-polaris-plugin
|
name: headlamp-polaris-plugin
|
||||||
displayName: Polaris
|
displayName: Polaris
|
||||||
createdAt: "2026-02-05T19:00:00Z"
|
createdAt: "2026-02-05T19:00:00Z"
|
||||||
@@ -28,7 +28,7 @@ maintainers:
|
|||||||
- name: privilegedescalation
|
- name: privilegedescalation
|
||||||
email: "chris@farhood.org"
|
email: "chris@farhood.org"
|
||||||
annotations:
|
annotations:
|
||||||
headlamp/plugin/archive-url: "https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/download/v0.5.0/polaris-0.5.0.tar.gz"
|
headlamp/plugin/archive-url: "https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/download/v0.5.2/polaris-0.5.2.tar.gz"
|
||||||
headlamp/plugin/version-compat: ">=0.26"
|
headlamp/plugin/version-compat: ">=0.26"
|
||||||
headlamp/plugin/archive-checksum: sha256:d00b9d068a32f01cf1584465c24e96b66eec60ea80be14f07433530780584451
|
headlamp/plugin/archive-checksum: sha256:61e7e92a26061299956bf133f8d7ec9d86d68b452a5bc4063f4a886fb8f055fd
|
||||||
headlamp/plugin/distro-compat: in-cluster
|
headlamp/plugin/distro-compat: in-cluster
|
||||||
|
|||||||
@@ -1,110 +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`:
|
|
||||||
- **GitHub**: Source control via `github-mcp-server`
|
|
||||||
- **Kubernetes** (local): Cluster access via `kubernetes-mcp-server`
|
|
||||||
- **Flux** (local): Flux Operator access via `flux-operator-mcp`
|
|
||||||
- **Playwright**: Browser automation via `@playwright/mcp`
|
|
||||||
+46
-9
@@ -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.
|
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:**
|
**Key Characteristics:**
|
||||||
|
|
||||||
- **Read-only:** No write operations to cluster or Polaris
|
- **Read-only:** No write operations to cluster or Polaris
|
||||||
- **Service proxy based:** Uses K8s API server proxy to reach Polaris
|
- **Service proxy based:** Uses K8s API server proxy to reach Polaris
|
||||||
- **React Context for state:** Shared data fetch across components
|
- **React Context for state:** Shared data fetch across components
|
||||||
@@ -170,6 +171,7 @@ Display namespace score + resource table
|
|||||||
### Plugin Entry Point
|
### Plugin Entry Point
|
||||||
|
|
||||||
**`src/index.tsx`**
|
**`src/index.tsx`**
|
||||||
|
|
||||||
- Registers sidebar entries (Polaris → Overview, Namespaces)
|
- Registers sidebar entries (Polaris → Overview, Namespaces)
|
||||||
- Registers routes (`/polaris`, `/polaris/namespaces`)
|
- Registers routes (`/polaris`, `/polaris/namespaces`)
|
||||||
- Registers app bar action (score badge)
|
- Registers app bar action (score badge)
|
||||||
@@ -179,22 +181,26 @@ Display namespace score + resource table
|
|||||||
### Data Layer
|
### Data Layer
|
||||||
|
|
||||||
**`src/api/PolarisDataContext.tsx`**
|
**`src/api/PolarisDataContext.tsx`**
|
||||||
|
|
||||||
- React Context Provider for shared data
|
- React Context Provider for shared data
|
||||||
- Fetches AuditData from Polaris dashboard
|
- Fetches AuditData from Polaris dashboard
|
||||||
- Handles auto-refresh based on user settings
|
- Handles auto-refresh based on user settings
|
||||||
- Provides `{ data, loading, error, refresh }` to consumers
|
- Provides `{ data, loading, error, refresh }` to consumers
|
||||||
|
|
||||||
**`src/api/polaris.ts`**
|
**`src/api/polaris.ts`**
|
||||||
|
|
||||||
- TypeScript types for AuditData schema
|
- TypeScript types for AuditData schema
|
||||||
- Utility functions: `countResults()`, `computeScore()`
|
- Utility functions: `countResults()`, `computeScore()`
|
||||||
- Settings management: `getRefreshInterval()`, `setRefreshInterval()`
|
- Settings management: `getRefreshInterval()`, `setRefreshInterval()`
|
||||||
- Constants: `DASHBOARD_URL_DEFAULT`, `INTERVAL_OPTIONS`
|
- Constants: `DASHBOARD_URL_DEFAULT`, `INTERVAL_OPTIONS`
|
||||||
|
|
||||||
**`src/api/checkMapping.ts`**
|
**`src/api/checkMapping.ts`**
|
||||||
|
|
||||||
- Maps Polaris check IDs to human-readable names
|
- Maps Polaris check IDs to human-readable names
|
||||||
- Used for display in UI (e.g., "hostIPCSet" → "Host IPC")
|
- Used for display in UI (e.g., "hostIPCSet" → "Host IPC")
|
||||||
|
|
||||||
**`src/api/topIssues.ts`**
|
**`src/api/topIssues.ts`**
|
||||||
|
|
||||||
- Aggregates failing checks across cluster
|
- Aggregates failing checks across cluster
|
||||||
- Groups by check ID and severity
|
- Groups by check ID and severity
|
||||||
- Used for top issues dashboard
|
- Used for top issues dashboard
|
||||||
@@ -202,6 +208,7 @@ Display namespace score + resource table
|
|||||||
### View Components
|
### View Components
|
||||||
|
|
||||||
**`src/components/DashboardView.tsx`**
|
**`src/components/DashboardView.tsx`**
|
||||||
|
|
||||||
- **Route:** `/polaris`
|
- **Route:** `/polaris`
|
||||||
- **Purpose:** Cluster-wide overview
|
- **Purpose:** Cluster-wide overview
|
||||||
- **Features:**
|
- **Features:**
|
||||||
@@ -212,6 +219,7 @@ Display namespace score + resource table
|
|||||||
- **Data:** Uses `usePolarisDataContext()`
|
- **Data:** Uses `usePolarisDataContext()`
|
||||||
|
|
||||||
**`src/components/NamespacesListView.tsx`**
|
**`src/components/NamespacesListView.tsx`**
|
||||||
|
|
||||||
- **Route:** `/polaris/namespaces`
|
- **Route:** `/polaris/namespaces`
|
||||||
- **Purpose:** List all namespaces with scores
|
- **Purpose:** List all namespaces with scores
|
||||||
- **Features:**
|
- **Features:**
|
||||||
@@ -221,6 +229,7 @@ Display namespace score + resource table
|
|||||||
- **Data:** Uses `usePolarisDataContext()`, aggregates by namespace
|
- **Data:** Uses `usePolarisDataContext()`, aggregates by namespace
|
||||||
|
|
||||||
**`src/components/NamespaceDetailView.tsx`**
|
**`src/components/NamespaceDetailView.tsx`**
|
||||||
|
|
||||||
- **Route:** Drawer on `/polaris/namespaces#<namespace>`
|
- **Route:** Drawer on `/polaris/namespaces#<namespace>`
|
||||||
- **Purpose:** Namespace-level drill-down
|
- **Purpose:** Namespace-level drill-down
|
||||||
- **Features:**
|
- **Features:**
|
||||||
@@ -233,6 +242,7 @@ Display namespace score + resource table
|
|||||||
### UI Components
|
### UI Components
|
||||||
|
|
||||||
**`src/components/AppBarScoreBadge.tsx`**
|
**`src/components/AppBarScoreBadge.tsx`**
|
||||||
|
|
||||||
- **Location:** Headlamp app bar (top-right)
|
- **Location:** Headlamp app bar (top-right)
|
||||||
- **Purpose:** Quick cluster score visibility
|
- **Purpose:** Quick cluster score visibility
|
||||||
- **Features:**
|
- **Features:**
|
||||||
@@ -242,6 +252,7 @@ Display namespace score + resource table
|
|||||||
- **Data:** Uses `usePolarisDataContext()`
|
- **Data:** Uses `usePolarisDataContext()`
|
||||||
|
|
||||||
**`src/components/PolarisSettings.tsx`**
|
**`src/components/PolarisSettings.tsx`**
|
||||||
|
|
||||||
- **Location:** Settings → Plugins → Polaris
|
- **Location:** Settings → Plugins → Polaris
|
||||||
- **Purpose:** Plugin configuration
|
- **Purpose:** Plugin configuration
|
||||||
- **Features:**
|
- **Features:**
|
||||||
@@ -251,6 +262,7 @@ Display namespace score + resource table
|
|||||||
- **Data:** localStorage for persistence
|
- **Data:** localStorage for persistence
|
||||||
|
|
||||||
**`src/components/InlineAuditSection.tsx`**
|
**`src/components/InlineAuditSection.tsx`**
|
||||||
|
|
||||||
- **Location:** Resource detail pages (Deployment, StatefulSet, etc.)
|
- **Location:** Resource detail pages (Deployment, StatefulSet, etc.)
|
||||||
- **Purpose:** Show Polaris audit inline
|
- **Purpose:** Show Polaris audit inline
|
||||||
- **Features:**
|
- **Features:**
|
||||||
@@ -260,6 +272,7 @@ Display namespace score + resource table
|
|||||||
- **Data:** Uses `usePolarisDataContext()`, filters by resource
|
- **Data:** Uses `usePolarisDataContext()`, filters by resource
|
||||||
|
|
||||||
**`src/components/ExemptionManager.tsx`**
|
**`src/components/ExemptionManager.tsx`**
|
||||||
|
|
||||||
- **Location:** (Planned feature, UI exists but not fully integrated)
|
- **Location:** (Planned feature, UI exists but not fully integrated)
|
||||||
- **Purpose:** Manage Polaris exemptions via annotations
|
- **Purpose:** Manage Polaris exemptions via annotations
|
||||||
- **Features:**
|
- **Features:**
|
||||||
@@ -274,6 +287,7 @@ Display namespace score + resource table
|
|||||||
**Decision:** Use React Context instead of Redux/Zustand
|
**Decision:** Use React Context instead of Redux/Zustand
|
||||||
|
|
||||||
**Rationale:**
|
**Rationale:**
|
||||||
|
|
||||||
1. **Simple state:** Single AuditData object shared across views
|
1. **Simple state:** Single AuditData object shared across views
|
||||||
2. **Read-only:** No complex mutations or transactions
|
2. **Read-only:** No complex mutations or transactions
|
||||||
3. **Headlamp constraints:** Plugin cannot add dependencies (Redux not bundled)
|
3. **Headlamp constraints:** Plugin cannot add dependencies (Redux not bundled)
|
||||||
@@ -283,10 +297,10 @@ Display namespace score + resource table
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
interface PolarisDataContextValue {
|
interface PolarisDataContextValue {
|
||||||
data: AuditData | null; // Audit results or null if loading/error
|
data: AuditData | null; // Audit results or null if loading/error
|
||||||
loading: boolean; // True during initial fetch
|
loading: boolean; // True during initial fetch
|
||||||
error: string | null; // Error message if fetch failed
|
error: string | null; // Error message if fetch failed
|
||||||
refresh: () => void; // Manual refresh function
|
refresh: () => void; // Manual refresh function
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -300,6 +314,7 @@ interface PolarisDataContextValue {
|
|||||||
### localStorage Usage
|
### localStorage Usage
|
||||||
|
|
||||||
Settings persisted in localStorage:
|
Settings persisted in localStorage:
|
||||||
|
|
||||||
- **`polaris-plugin-refresh-interval`**: Number (seconds), default 300
|
- **`polaris-plugin-refresh-interval`**: Number (seconds), default 300
|
||||||
- **`polaris-plugin-dashboard-url`**: String, default service proxy path
|
- **`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
|
**Decision:** Use Kubernetes service proxy, not direct ClusterIP access
|
||||||
|
|
||||||
**Rationale:**
|
**Rationale:**
|
||||||
|
|
||||||
- Headlamp already has K8s API credentials (service account or user token)
|
- Headlamp already has K8s API credentials (service account or user token)
|
||||||
- Service proxy leverages existing RBAC (no new credentials needed)
|
- Service proxy leverages existing RBAC (no new credentials needed)
|
||||||
- Works with Headlamp's token auth and OIDC
|
- Works with Headlamp's token auth and OIDC
|
||||||
- Simpler deployment (no additional network policies for plugin)
|
- Simpler deployment (no additional network policies for plugin)
|
||||||
|
|
||||||
**Trade-off:**
|
**Trade-off:**
|
||||||
|
|
||||||
- Requires `get` permission on `services/proxy` resource
|
- Requires `get` permission on `services/proxy` resource
|
||||||
- Path is longer: `/api/v1/namespaces/polaris/services/polaris-dashboard:80/proxy/results.json`
|
- 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)
|
**Decision:** Sidebar has "Polaris" → "Overview" and "Namespaces" (2 levels max)
|
||||||
|
|
||||||
**Rationale:**
|
**Rationale:**
|
||||||
|
|
||||||
- Headlamp sidebar supports 2-level nesting maximum
|
- Headlamp sidebar supports 2-level nesting maximum
|
||||||
- Deeper nesting (e.g., Polaris → Namespaces → <each namespace>) doesn't work
|
- Deeper nesting (e.g., Polaris → Namespaces → <each namespace>) doesn't work
|
||||||
- Sidebar Collapse component is route-based, not click-to-toggle
|
- Sidebar Collapse component is route-based, not click-to-toggle
|
||||||
|
|
||||||
**Alternative Considered:**
|
**Alternative Considered:**
|
||||||
|
|
||||||
- Dynamic sidebar with namespace entries → rejected (Headlamp limitation)
|
- Dynamic sidebar with namespace entries → rejected (Headlamp limitation)
|
||||||
|
|
||||||
**Current Solution:**
|
**Current Solution:**
|
||||||
|
|
||||||
- Use table in NamespacesListView with clickable namespace buttons
|
- Use table in NamespacesListView with clickable namespace buttons
|
||||||
- Namespace detail opens in drawer (not new route)
|
- 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
|
**Decision:** Namespace detail uses drawer, not dedicated route
|
||||||
|
|
||||||
**Rationale:**
|
**Rationale:**
|
||||||
|
|
||||||
- Better UX (drawer overlays table, no navigation loss)
|
- Better UX (drawer overlays table, no navigation loss)
|
||||||
- URL hash preserves navigation state (`#namespace-name`)
|
- URL hash preserves navigation state (`#namespace-name`)
|
||||||
- Keyboard shortcuts (Escape to close)
|
- Keyboard shortcuts (Escape to close)
|
||||||
- Sidebar doesn't support 3-level nesting for per-namespace routes
|
- Sidebar doesn't support 3-level nesting for per-namespace routes
|
||||||
|
|
||||||
**Implementation:**
|
**Implementation:**
|
||||||
|
|
||||||
- URL: `/polaris/namespaces#kube-system`
|
- URL: `/polaris/namespaces#kube-system`
|
||||||
- Drawer controlled by hash presence
|
- Drawer controlled by hash presence
|
||||||
- `useEffect` watches hash changes
|
- `useEffect` watches hash changes
|
||||||
@@ -357,11 +379,13 @@ No sensitive data stored in localStorage.
|
|||||||
**Decision:** Never import from `@mui/material` or `@mui/icons-material`
|
**Decision:** Never import from `@mui/material` or `@mui/icons-material`
|
||||||
|
|
||||||
**Rationale:**
|
**Rationale:**
|
||||||
|
|
||||||
- Headlamp plugin environment doesn't provide full MUI library
|
- Headlamp plugin environment doesn't provide full MUI library
|
||||||
- Importing MUI causes `createSvgIcon undefined` error
|
- Importing MUI causes `createSvgIcon undefined` error
|
||||||
- Plugins must use Headlamp CommonComponents only
|
- Plugins must use Headlamp CommonComponents only
|
||||||
|
|
||||||
**Alternative:**
|
**Alternative:**
|
||||||
|
|
||||||
- Use standard HTML elements with inline styles
|
- Use standard HTML elements with inline styles
|
||||||
- Use theme-aware CSS variables (`--mui-palette-*`)
|
- Use theme-aware CSS variables (`--mui-palette-*`)
|
||||||
|
|
||||||
@@ -370,11 +394,13 @@ No sensitive data stored in localStorage.
|
|||||||
**Decision:** Enable all TypeScript strict checks
|
**Decision:** Enable all TypeScript strict checks
|
||||||
|
|
||||||
**Rationale:**
|
**Rationale:**
|
||||||
|
|
||||||
- Catch errors at compile time
|
- Catch errors at compile time
|
||||||
- Better IDE support and autocomplete
|
- Better IDE support and autocomplete
|
||||||
- Enforces type safety (no `any`, no implicit unknowns)
|
- Enforces type safety (no `any`, no implicit unknowns)
|
||||||
|
|
||||||
**Impact:**
|
**Impact:**
|
||||||
|
|
||||||
- More verbose code (explicit types required)
|
- More verbose code (explicit types required)
|
||||||
- Better maintainability and refactorability
|
- Better maintainability and refactorability
|
||||||
|
|
||||||
@@ -383,11 +409,13 @@ No sensitive data stored in localStorage.
|
|||||||
**Decision:** Default refresh interval is 5 minutes (configurable)
|
**Decision:** Default refresh interval is 5 minutes (configurable)
|
||||||
|
|
||||||
**Rationale:**
|
**Rationale:**
|
||||||
|
|
||||||
- Polaris audits typically run every 10-30 minutes
|
- Polaris audits typically run every 10-30 minutes
|
||||||
- Balance between data freshness and API load
|
- Balance between data freshness and API load
|
||||||
- User can configure from 1 minute to 30 minutes
|
- User can configure from 1 minute to 30 minutes
|
||||||
|
|
||||||
**Considered:**
|
**Considered:**
|
||||||
|
|
||||||
- WebSocket/SSE for real-time updates → rejected (Polaris dashboard doesn't support)
|
- WebSocket/SSE for real-time updates → rejected (Polaris dashboard doesn't support)
|
||||||
- Shorter default → rejected (unnecessary API calls)
|
- Shorter default → rejected (unnecessary API calls)
|
||||||
|
|
||||||
@@ -401,28 +429,30 @@ No sensitive data stored in localStorage.
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// Sidebar navigation
|
// Sidebar navigation
|
||||||
registerSidebarEntry({ parent, name, label, url, icon })
|
registerSidebarEntry({ parent, name, label, url, icon });
|
||||||
|
|
||||||
// Routes
|
// Routes
|
||||||
registerRoute({ path, sidebar, name, exact, component })
|
registerRoute({ path, sidebar, name, exact, component });
|
||||||
|
|
||||||
// App bar actions
|
// App bar actions
|
||||||
registerAppBarAction(component)
|
registerAppBarAction(component);
|
||||||
|
|
||||||
// Plugin settings
|
// Plugin settings
|
||||||
registerPluginSettings(name, component, displaySaveButton)
|
registerPluginSettings(name, component, displaySaveButton);
|
||||||
|
|
||||||
// Resource detail sections
|
// Resource detail sections
|
||||||
registerDetailsViewSection(component)
|
registerDetailsViewSection(component);
|
||||||
```
|
```
|
||||||
|
|
||||||
**Key Changes in v0.13.0:**
|
**Key Changes in v0.13.0:**
|
||||||
|
|
||||||
- `registerDetailsViewSection` now takes 1 argument (component), not 2 (name, component)
|
- `registerDetailsViewSection` now takes 1 argument (component), not 2 (name, component)
|
||||||
- `registerAppBarAction` now takes 1 argument (component), not 2 (name, component)
|
- `registerAppBarAction` now takes 1 argument (component), not 2 (name, component)
|
||||||
|
|
||||||
### Headlamp CommonComponents
|
### Headlamp CommonComponents
|
||||||
|
|
||||||
**Used Components:**
|
**Used Components:**
|
||||||
|
|
||||||
- `SectionBox` - Card-like container with title
|
- `SectionBox` - Card-like container with title
|
||||||
- `SectionHeader` - Page header with title
|
- `SectionHeader` - Page header with title
|
||||||
- `StatusLabel` - Color-coded status badges
|
- `StatusLabel` - Color-coded status badges
|
||||||
@@ -432,16 +462,19 @@ registerDetailsViewSection(component)
|
|||||||
- `Loader` - Loading spinner
|
- `Loader` - Loading spinner
|
||||||
|
|
||||||
**Router:**
|
**Router:**
|
||||||
|
|
||||||
- `Router.createRouteURL()` - Generate plugin route URLs
|
- `Router.createRouteURL()` - Generate plugin route URLs
|
||||||
- React Router's `useHistory()`, `useParams()`, `useLocation()`
|
- React Router's `useHistory()`, `useParams()`, `useLocation()`
|
||||||
|
|
||||||
### Kubernetes API (via ApiProxy)
|
### Kubernetes API (via ApiProxy)
|
||||||
|
|
||||||
**Used for:**
|
**Used for:**
|
||||||
|
|
||||||
- Fetching Polaris results: `ApiProxy.request(dashboardUrl + 'results.json')`
|
- Fetching Polaris results: `ApiProxy.request(dashboardUrl + 'results.json')`
|
||||||
- No direct K8s API calls (all data from Polaris dashboard)
|
- No direct K8s API calls (all data from Polaris dashboard)
|
||||||
|
|
||||||
**RBAC Required:**
|
**RBAC Required:**
|
||||||
|
|
||||||
- `get` on `services/proxy` for `polaris-dashboard` in `polaris` namespace
|
- `get` on `services/proxy` for `polaris-dashboard` in `polaris` namespace
|
||||||
|
|
||||||
## Known Limitations
|
## Known Limitations
|
||||||
@@ -529,18 +562,22 @@ registerDetailsViewSection(component)
|
|||||||
### Potential Improvements
|
### Potential Improvements
|
||||||
|
|
||||||
1. **WebWorker for data processing**
|
1. **WebWorker for data processing**
|
||||||
|
|
||||||
- Offload `countResults()` aggregation for large clusters
|
- Offload `countResults()` aggregation for large clusters
|
||||||
- Keep UI responsive during heavy computation
|
- Keep UI responsive during heavy computation
|
||||||
|
|
||||||
2. **IndexedDB caching**
|
2. **IndexedDB caching**
|
||||||
|
|
||||||
- Cache audit data offline
|
- Cache audit data offline
|
||||||
- Show stale data + "refresh available" indicator
|
- Show stale data + "refresh available" indicator
|
||||||
|
|
||||||
3. **GraphQL/REST API abstraction**
|
3. **GraphQL/REST API abstraction**
|
||||||
|
|
||||||
- Decouple from Polaris dashboard JSON format
|
- Decouple from Polaris dashboard JSON format
|
||||||
- Support multiple backend sources
|
- Support multiple backend sources
|
||||||
|
|
||||||
4. **Plugin-to-plugin communication**
|
4. **Plugin-to-plugin communication**
|
||||||
|
|
||||||
- Integrate with other Headlamp plugins (e.g., policy enforcement)
|
- Integrate with other Headlamp plugins (e.g., policy enforcement)
|
||||||
- Shared state between plugins
|
- Shared state between plugins
|
||||||
|
|
||||||
|
|||||||
+42
-59
@@ -47,9 +47,9 @@ kubectl -n kube-system get pods -l app.kubernetes.io/name=headlamp
|
|||||||
```yaml
|
```yaml
|
||||||
# headlamp-values.yaml
|
# headlamp-values.yaml
|
||||||
config:
|
config:
|
||||||
pluginsDir: "/headlamp/plugins"
|
pluginsDir: /headlamp/plugins
|
||||||
|
|
||||||
pluginsManager:
|
pluginsManager:
|
||||||
enabled: true
|
enabled: true
|
||||||
repositories:
|
repositories:
|
||||||
- https://artifacthub.io/packages/search?kind=4
|
- https://artifacthub.io/packages/search?kind=4
|
||||||
@@ -76,8 +76,7 @@ pluginsManager:
|
|||||||
```yaml
|
```yaml
|
||||||
# headlamp-values.yaml
|
# headlamp-values.yaml
|
||||||
config:
|
config:
|
||||||
pluginsDir: "/headlamp/plugins"
|
pluginsDir: /headlamp/plugins
|
||||||
watchPlugins: false # CRITICAL: Must be false for plugin manager
|
|
||||||
|
|
||||||
replicaCount: 1
|
replicaCount: 1
|
||||||
|
|
||||||
@@ -123,7 +122,7 @@ data:
|
|||||||
```yaml
|
```yaml
|
||||||
# headlamp-values.yaml
|
# headlamp-values.yaml
|
||||||
config:
|
config:
|
||||||
pluginsDir: "/plugins"
|
pluginsDir: '/plugins'
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
- name: plugins
|
- name: plugins
|
||||||
@@ -152,9 +151,8 @@ image:
|
|||||||
tag: v0.39.0
|
tag: v0.39.0
|
||||||
|
|
||||||
config:
|
config:
|
||||||
baseURL: ""
|
baseURL: ''
|
||||||
pluginsDir: "/headlamp/plugins"
|
pluginsDir: /headlamp/plugins
|
||||||
watchPlugins: false # MUST be false for plugin manager
|
|
||||||
|
|
||||||
pluginsManager:
|
pluginsManager:
|
||||||
enabled: true
|
enabled: true
|
||||||
@@ -195,16 +193,16 @@ resources:
|
|||||||
# OIDC Authentication (optional)
|
# OIDC Authentication (optional)
|
||||||
env:
|
env:
|
||||||
- name: HEADLAMP_CONFIG_OIDC_CLIENT_ID
|
- name: HEADLAMP_CONFIG_OIDC_CLIENT_ID
|
||||||
value: "headlamp"
|
value: 'headlamp'
|
||||||
- name: HEADLAMP_CONFIG_OIDC_CLIENT_SECRET
|
- name: HEADLAMP_CONFIG_OIDC_CLIENT_SECRET
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: headlamp-oidc
|
name: headlamp-oidc
|
||||||
key: client-secret
|
key: client-secret
|
||||||
- name: HEADLAMP_CONFIG_OIDC_ISSUER_URL
|
- 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
|
- name: HEADLAMP_CONFIG_OIDC_SCOPES
|
||||||
value: "openid,profile,email,groups"
|
value: 'openid,profile,email,groups'
|
||||||
```
|
```
|
||||||
|
|
||||||
### FluxCD HelmRelease Example
|
### FluxCD HelmRelease Example
|
||||||
@@ -230,8 +228,7 @@ spec:
|
|||||||
|
|
||||||
values:
|
values:
|
||||||
config:
|
config:
|
||||||
pluginsDir: "/headlamp/plugins"
|
pluginsDir: /headlamp/plugins
|
||||||
watchPlugins: false
|
|
||||||
|
|
||||||
pluginsManager:
|
pluginsManager:
|
||||||
enabled: true
|
enabled: true
|
||||||
@@ -265,10 +262,10 @@ metadata:
|
|||||||
name: polaris-proxy-reader
|
name: polaris-proxy-reader
|
||||||
namespace: polaris
|
namespace: polaris
|
||||||
rules:
|
rules:
|
||||||
- apiGroups: [""]
|
- apiGroups: ['']
|
||||||
resources: ["services/proxy"]
|
resources: ['services/proxy']
|
||||||
resourceNames: ["polaris-dashboard"]
|
resourceNames: ['polaris-dashboard']
|
||||||
verbs: ["get"]
|
verbs: ['get']
|
||||||
```
|
```
|
||||||
|
|
||||||
### RoleBinding Options
|
### RoleBinding Options
|
||||||
@@ -303,7 +300,7 @@ metadata:
|
|||||||
namespace: polaris
|
namespace: polaris
|
||||||
subjects:
|
subjects:
|
||||||
- kind: Group
|
- kind: Group
|
||||||
name: system:authenticated # All authenticated users
|
name: system:authenticated # All authenticated users
|
||||||
apiGroup: rbac.authorization.k8s.io
|
apiGroup: rbac.authorization.k8s.io
|
||||||
roleRef:
|
roleRef:
|
||||||
kind: Role
|
kind: Role
|
||||||
@@ -350,10 +347,10 @@ metadata:
|
|||||||
app.kubernetes.io/name: headlamp-polaris-plugin
|
app.kubernetes.io/name: headlamp-polaris-plugin
|
||||||
app.kubernetes.io/component: rbac
|
app.kubernetes.io/component: rbac
|
||||||
rules:
|
rules:
|
||||||
- apiGroups: [""]
|
- apiGroups: ['']
|
||||||
resources: ["services/proxy"]
|
resources: ['services/proxy']
|
||||||
resourceNames: ["polaris-dashboard"]
|
resourceNames: ['polaris-dashboard']
|
||||||
verbs: ["get"]
|
verbs: ['get']
|
||||||
|
|
||||||
---
|
---
|
||||||
# RoleBinding: Grant Headlamp service account access
|
# RoleBinding: Grant Headlamp service account access
|
||||||
@@ -376,6 +373,7 @@ roleRef:
|
|||||||
```
|
```
|
||||||
|
|
||||||
Apply with:
|
Apply with:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl apply -f polaris-plugin-rbac.yaml
|
kubectl apply -f polaris-plugin-rbac.yaml
|
||||||
```
|
```
|
||||||
@@ -385,6 +383,7 @@ kubectl apply -f polaris-plugin-rbac.yaml
|
|||||||
### Required Network Access
|
### Required Network Access
|
||||||
|
|
||||||
The plugin requires network connectivity:
|
The plugin requires network connectivity:
|
||||||
|
|
||||||
- **Headlamp pod** → **Kubernetes API server** (service proxy)
|
- **Headlamp pod** → **Kubernetes API server** (service proxy)
|
||||||
- **Kubernetes API server** → **Polaris dashboard service** (port 80)
|
- **Kubernetes API server** → **Polaris dashboard service** (port 80)
|
||||||
|
|
||||||
@@ -424,36 +423,9 @@ spec:
|
|||||||
|
|
||||||
## Plugin Manager Setup
|
## 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
|
### Plugin Manager Verification
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Check Headlamp config
|
|
||||||
kubectl -n kube-system get configmap headlamp -o yaml | grep watchPlugins
|
|
||||||
|
|
||||||
# Expected output:
|
|
||||||
# watchPlugins: "false"
|
|
||||||
|
|
||||||
# Check plugin is installed
|
# Check plugin is installed
|
||||||
kubectl -n kube-system exec -it deployment/headlamp -- ls -la /headlamp/plugins/
|
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)
|
- [ ] Polaris dashboard service exists (`polaris-dashboard` in `polaris` namespace)
|
||||||
- [ ] RBAC Role and RoleBinding created
|
- [ ] RBAC Role and RoleBinding created
|
||||||
- [ ] Headlamp v0.26+ deployed
|
- [ ] Headlamp v0.26+ deployed
|
||||||
- [ ] `watchPlugins: false` set in Headlamp config
|
|
||||||
|
|
||||||
### Deployment
|
### 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
|
**Symptom:** Plugin listed in Settings → Plugins but no sidebar entry
|
||||||
|
|
||||||
**Causes:**
|
**Causes:**
|
||||||
1. `watchPlugins: true` (should be `false`)
|
|
||||||
2. Browser cache not cleared
|
1. Browser cache not cleared
|
||||||
|
2. Plugin files not properly installed
|
||||||
|
|
||||||
**Solution:**
|
**Solution:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Fix Headlamp config
|
# Verify plugin files exist
|
||||||
kubectl -n kube-system edit configmap headlamp
|
kubectl -n kube-system exec deployment/headlamp -c headlamp -- \
|
||||||
# Set watchPlugins: false
|
ls -la /headlamp/plugins/headlamp-polaris-plugin/
|
||||||
|
|
||||||
# Restart Headlamp
|
# Restart Headlamp
|
||||||
kubectl -n kube-system rollout restart deployment/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
|
**Cause:** RBAC missing or incorrect
|
||||||
|
|
||||||
**Solution:**
|
**Solution:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Verify RBAC exists
|
# Verify RBAC exists
|
||||||
kubectl -n polaris get role polaris-proxy-reader
|
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
|
**Symptom:** Error loading Polaris data, 404 in console
|
||||||
|
|
||||||
**Causes:**
|
**Causes:**
|
||||||
|
|
||||||
1. Polaris not deployed
|
1. Polaris not deployed
|
||||||
2. Polaris service name wrong
|
2. Polaris service name wrong
|
||||||
3. Polaris namespace wrong
|
3. Polaris namespace wrong
|
||||||
|
|
||||||
**Solution:**
|
**Solution:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Check Polaris deployment
|
# Check Polaris deployment
|
||||||
kubectl -n polaris get pods
|
kubectl -n polaris get pods
|
||||||
@@ -579,11 +555,13 @@ helm install polaris fairwinds-stable/polaris \
|
|||||||
**Symptom:** Error when using custom Polaris URL in settings
|
**Symptom:** Error when using custom Polaris URL in settings
|
||||||
|
|
||||||
**Causes:**
|
**Causes:**
|
||||||
|
|
||||||
1. URL format incorrect
|
1. URL format incorrect
|
||||||
2. CORS not configured on external Polaris
|
2. CORS not configured on external Polaris
|
||||||
3. Network policy blocking external access
|
3. Network policy blocking external access
|
||||||
|
|
||||||
**Solution:**
|
**Solution:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Test URL manually
|
# Test URL manually
|
||||||
curl -v https://my-polaris.example.com/results.json
|
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
|
**Cause:** Plugin manager hasn't synced from ArtifactHub
|
||||||
|
|
||||||
**Solution:**
|
**Solution:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Wait 30 minutes (ArtifactHub sync interval)
|
# Wait 30 minutes (ArtifactHub sync interval)
|
||||||
# Or manually refresh plugin list in Headlamp UI
|
# 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
|
**Cause:** NetworkPolicy in `polaris` namespace blocking API server
|
||||||
|
|
||||||
**Solution:**
|
**Solution:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Check NetworkPolicies
|
# Check NetworkPolicies
|
||||||
kubectl -n polaris get networkpolicy
|
kubectl -n polaris get networkpolicy
|
||||||
@@ -633,25 +613,28 @@ kubectl -n polaris get networkpolicy
|
|||||||
### Audit Logging
|
### Audit Logging
|
||||||
|
|
||||||
Kubernetes audit logs will record:
|
Kubernetes audit logs will record:
|
||||||
|
|
||||||
- User/service account accessing service proxy
|
- User/service account accessing service proxy
|
||||||
- Timestamp and response code
|
- Timestamp and response code
|
||||||
|
|
||||||
Configure audit policy if needed:
|
Configure audit policy if needed:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
apiVersion: audit.k8s.io/v1
|
apiVersion: audit.k8s.io/v1
|
||||||
kind: Policy
|
kind: Policy
|
||||||
rules:
|
rules:
|
||||||
- level: Metadata
|
- level: Metadata
|
||||||
verbs: ["get"]
|
verbs: ['get']
|
||||||
resources:
|
resources:
|
||||||
- group: ""
|
- group: ''
|
||||||
resources: ["services/proxy"]
|
resources: ['services/proxy']
|
||||||
namespaces: ["polaris"]
|
namespaces: ['polaris']
|
||||||
```
|
```
|
||||||
|
|
||||||
### Data Sensitivity
|
### Data Sensitivity
|
||||||
|
|
||||||
Polaris audit data may contain:
|
Polaris audit data may contain:
|
||||||
|
|
||||||
- Resource names and namespaces
|
- Resource names and namespaces
|
||||||
- Configuration details
|
- Configuration details
|
||||||
- Potential security vulnerabilities
|
- Potential security vulnerabilities
|
||||||
|
|||||||
@@ -11,8 +11,10 @@ This plan standardizes documentation structure, formatting, and content across t
|
|||||||
## Current State Analysis
|
## Current State Analysis
|
||||||
|
|
||||||
### Polaris Plugin (v0.3.5)
|
### Polaris Plugin (v0.3.5)
|
||||||
|
|
||||||
**Structure**: Topic-focused with monolithic files
|
**Structure**: Topic-focused with monolithic files
|
||||||
**Strengths**:
|
**Strengths**:
|
||||||
|
|
||||||
- Comprehensive CONTRIBUTING.md with branching strategy and commit conventions
|
- Comprehensive CONTRIBUTING.md with branching strategy and commit conventions
|
||||||
- Complete CHANGELOG.md (35 versions documented)
|
- Complete CHANGELOG.md (35 versions documented)
|
||||||
- Dedicated SECURITY.md with vulnerability reporting
|
- 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
|
- Well-organized TROUBLESHOOTING.md with common issues
|
||||||
|
|
||||||
**Gaps**:
|
**Gaps**:
|
||||||
|
|
||||||
- No user journey-based organization
|
- No user journey-based organization
|
||||||
- No Architecture Decision Records
|
- No Architecture Decision Records
|
||||||
- Limited quick-start tutorials
|
- Limited quick-start tutorials
|
||||||
@@ -28,8 +31,10 @@ This plan standardizes documentation structure, formatting, and content across t
|
|||||||
- Deployment guide is monolithic (needs breakdown)
|
- Deployment guide is monolithic (needs breakdown)
|
||||||
|
|
||||||
### Sealed Secrets Plugin
|
### Sealed Secrets Plugin
|
||||||
|
|
||||||
**Structure**: User journey-based with granular topic files
|
**Structure**: User journey-based with granular topic files
|
||||||
**Strengths**:
|
**Strengths**:
|
||||||
|
|
||||||
- Excellent user journey organization (Getting Started → User Guide → Tutorials)
|
- Excellent user journey organization (Getting Started → User Guide → Tutorials)
|
||||||
- Architecture Decision Records (5 ADRs)
|
- Architecture Decision Records (5 ADRs)
|
||||||
- Quick diagnosis flowchart in troubleshooting
|
- 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
|
- Visual hierarchy with strategic emoji use
|
||||||
|
|
||||||
**Gaps**:
|
**Gaps**:
|
||||||
|
|
||||||
- No dedicated CONTRIBUTING.md (content in README)
|
- No dedicated CONTRIBUTING.md (content in README)
|
||||||
- No SECURITY.md for vulnerability reporting
|
- No SECURITY.md for vulnerability reporting
|
||||||
- Incomplete tutorial placeholders
|
- Incomplete tutorial placeholders
|
||||||
@@ -49,6 +55,7 @@ This plan standardizes documentation structure, formatting, and content across t
|
|||||||
### 1. File Structure Standard
|
### 1. File Structure Standard
|
||||||
|
|
||||||
**Root-Level Files** (Common to Both):
|
**Root-Level Files** (Common to Both):
|
||||||
|
|
||||||
```
|
```
|
||||||
README.md # Main entry point with badges, quick links
|
README.md # Main entry point with badges, quick links
|
||||||
CHANGELOG.md # Keep a Changelog format, semantic versioning
|
CHANGELOG.md # Keep a Changelog format, semantic versioning
|
||||||
@@ -59,6 +66,7 @@ package.json # Plugin metadata
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Documentation Directory** (Organized by User Journey):
|
**Documentation Directory** (Organized by User Journey):
|
||||||
|
|
||||||
```
|
```
|
||||||
docs/
|
docs/
|
||||||
├── README.md # Documentation hub with quick links
|
├── README.md # Documentation hub with quick links
|
||||||
@@ -94,6 +102,7 @@ docs/
|
|||||||
### 2. README.md Standard
|
### 2. README.md Standard
|
||||||
|
|
||||||
**Required Sections** (Order Matters):
|
**Required Sections** (Order Matters):
|
||||||
|
|
||||||
1. Title + Badges (ArtifactHub, CI, E2E, License)
|
1. Title + Badges (ArtifactHub, CI, E2E, License)
|
||||||
2. Quick navigation links (📚 Documentation | 🚀 Installation | 🔒 Security | 🛠️ Development)
|
2. Quick navigation links (📚 Documentation | 🚀 Installation | 🔒 Security | 🛠️ Development)
|
||||||
3. **What It Does** (features with visual hierarchy)
|
3. **What It Does** (features with visual hierarchy)
|
||||||
@@ -111,6 +120,7 @@ docs/
|
|||||||
15. Footer ("Made with ❤️ for the Kubernetes community")
|
15. Footer ("Made with ❤️ for the Kubernetes community")
|
||||||
|
|
||||||
**Formatting Standards**:
|
**Formatting Standards**:
|
||||||
|
|
||||||
- Use emojis strategically for visual scanning (not excessive)
|
- Use emojis strategically for visual scanning (not excessive)
|
||||||
- Quick navigation at top
|
- Quick navigation at top
|
||||||
- Tables for structured data (prerequisites, troubleshooting quick ref)
|
- Tables for structured data (prerequisites, troubleshooting quick ref)
|
||||||
@@ -122,6 +132,7 @@ docs/
|
|||||||
**Format**: Keep a Changelog (https://keepachangelog.com/)
|
**Format**: Keep a Changelog (https://keepachangelog.com/)
|
||||||
|
|
||||||
**Structure**:
|
**Structure**:
|
||||||
|
|
||||||
```markdown
|
```markdown
|
||||||
# Changelog
|
# 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
|
## [X.Y.Z] - YYYY-MM-DD
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- New features
|
- New features
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Changes to existing functionality
|
- Changes to existing functionality
|
||||||
|
|
||||||
### Deprecated
|
### Deprecated
|
||||||
|
|
||||||
- Soon-to-be removed features
|
- Soon-to-be removed features
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
- Removed features
|
- Removed features
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Bug fixes
|
- Bug fixes
|
||||||
|
|
||||||
### Security
|
### Security
|
||||||
|
|
||||||
- Security fixes
|
- Security fixes
|
||||||
|
|
||||||
[Unreleased]: https://github.com/user/repo/compare/vX.Y.Z...HEAD
|
[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**:
|
**Standards**:
|
||||||
|
|
||||||
- One entry per version, newest first
|
- One entry per version, newest first
|
||||||
- Date in ISO 8601 format (YYYY-MM-DD)
|
- Date in ISO 8601 format (YYYY-MM-DD)
|
||||||
- Link to GitHub release
|
- 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
|
### 4. CONTRIBUTING.md Standard
|
||||||
|
|
||||||
**Required Sections**:
|
**Required Sections**:
|
||||||
|
|
||||||
1. Code of Conduct (brief, respectful)
|
1. Code of Conduct (brief, respectful)
|
||||||
2. Getting Started (prerequisites, setup)
|
2. Getting Started (prerequisites, setup)
|
||||||
3. Development Workflow (feature development, testing)
|
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)
|
10. Release Process (version numbering, creating releases)
|
||||||
|
|
||||||
**Formatting**:
|
**Formatting**:
|
||||||
|
|
||||||
- Use tables for branch naming conventions
|
- Use tables for branch naming conventions
|
||||||
- Code blocks for commit message examples
|
- Code blocks for commit message examples
|
||||||
- Checklists for PR requirements
|
- 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
|
### 5. SECURITY.md Standard
|
||||||
|
|
||||||
**Required Sections**:
|
**Required Sections**:
|
||||||
|
|
||||||
1. Overview (security model, read-only vs. write operations)
|
1. Overview (security model, read-only vs. write operations)
|
||||||
2. Data Flow Diagram (how data moves through system)
|
2. Data Flow Diagram (how data moves through system)
|
||||||
3. RBAC Requirements (minimal permissions table)
|
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)
|
10. Compliance Considerations (audit trail, GDPR/privacy)
|
||||||
|
|
||||||
**Formatting**:
|
**Formatting**:
|
||||||
|
|
||||||
- Tables for permissions and supported versions
|
- Tables for permissions and supported versions
|
||||||
- YAML examples for RBAC manifests
|
- YAML examples for RBAC manifests
|
||||||
- Bash commands for security verification
|
- 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
|
**Purpose**: Central navigation for all documentation
|
||||||
|
|
||||||
**Structure**:
|
**Structure**:
|
||||||
|
|
||||||
```markdown
|
```markdown
|
||||||
# Documentation
|
# Documentation
|
||||||
|
|
||||||
@@ -222,31 +245,40 @@ Central hub for [Plugin Name] documentation.
|
|||||||
- 💻 [Development](development/workflow.md)
|
- 💻 [Development](development/workflow.md)
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
Description + links to installation, prerequisites, quick-start
|
Description + links to installation, prerequisites, quick-start
|
||||||
|
|
||||||
## User Guide
|
## User Guide
|
||||||
|
|
||||||
Description + links to features, configuration, RBAC
|
Description + links to features, configuration, RBAC
|
||||||
|
|
||||||
## Tutorials
|
## Tutorials
|
||||||
|
|
||||||
Description + links to plugin-specific tutorials
|
Description + links to plugin-specific tutorials
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
Description + link to quick diagnosis + common issues
|
Description + link to quick diagnosis + common issues
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
Description + links to overview, data flow, ADRs
|
Description + links to overview, data flow, ADRs
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
Description + links to workflow, testing, code style, release
|
Description + links to workflow, testing, code style, release
|
||||||
|
|
||||||
## Deployment
|
## Deployment
|
||||||
|
|
||||||
Description + links to Kubernetes, Helm, production
|
Description + links to Kubernetes, Helm, production
|
||||||
|
|
||||||
## API Reference
|
## API Reference
|
||||||
|
|
||||||
Link to JSDoc or generated API docs
|
Link to JSDoc or generated API docs
|
||||||
```
|
```
|
||||||
|
|
||||||
**Formatting**:
|
**Formatting**:
|
||||||
|
|
||||||
- Emojis for visual scanning
|
- Emojis for visual scanning
|
||||||
- Brief descriptions (1-2 sentences) for each section
|
- Brief descriptions (1-2 sentences) for each section
|
||||||
- Organized by user journey (beginner → advanced)
|
- Organized by user journey (beginner → advanced)
|
||||||
@@ -254,12 +286,14 @@ Link to JSDoc or generated API docs
|
|||||||
### 7. Architecture Decision Records (ADR) Standard
|
### 7. Architecture Decision Records (ADR) Standard
|
||||||
|
|
||||||
**When to Create ADRs**:
|
**When to Create ADRs**:
|
||||||
|
|
||||||
- Significant architectural choices
|
- Significant architectural choices
|
||||||
- Technology selection (libraries, patterns)
|
- Technology selection (libraries, patterns)
|
||||||
- Security or performance trade-offs
|
- Security or performance trade-offs
|
||||||
- Design patterns that impact maintainability
|
- Design patterns that impact maintainability
|
||||||
|
|
||||||
**Template** (Based on Michael Nygard's ADR):
|
**Template** (Based on Michael Nygard's ADR):
|
||||||
|
|
||||||
```markdown
|
```markdown
|
||||||
# ADR-NNN: Title
|
# 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?
|
What becomes easier or more difficult to do because of this change?
|
||||||
|
|
||||||
### Positive
|
### Positive
|
||||||
|
|
||||||
- ...
|
- ...
|
||||||
|
|
||||||
### Negative
|
### Negative
|
||||||
|
|
||||||
- ...
|
- ...
|
||||||
|
|
||||||
### Neutral
|
### Neutral
|
||||||
|
|
||||||
- ...
|
- ...
|
||||||
|
|
||||||
## Alternatives Considered
|
## Alternatives Considered
|
||||||
|
|
||||||
### Option 1: Name
|
### Option 1: Name
|
||||||
|
|
||||||
**Pros**: ...
|
**Pros**: ...
|
||||||
**Cons**: ...
|
**Cons**: ...
|
||||||
**Decision**: Not chosen because...
|
**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)
|
**Numbering**: ADR-001, ADR-002, etc. (zero-padded 3 digits)
|
||||||
|
|
||||||
**Index File** (architecture/adr/README.md):
|
**Index File** (architecture/adr/README.md):
|
||||||
|
|
||||||
```markdown
|
```markdown
|
||||||
# Architecture Decision Records
|
# Architecture Decision Records
|
||||||
|
|
||||||
| ADR | Title | Status | Date |
|
| ADR | Title | Status | Date |
|
||||||
|-----|-------|--------|------|
|
| ------------------- | ----- | -------- | ---------- |
|
||||||
| [001](001-title.md) | Title | Accepted | 2026-01-01 |
|
| [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**:
|
**Structure**:
|
||||||
|
|
||||||
**troubleshooting/README.md** (Quick Diagnosis):
|
**troubleshooting/README.md** (Quick Diagnosis):
|
||||||
|
|
||||||
```markdown
|
```markdown
|
||||||
# Troubleshooting
|
# Troubleshooting
|
||||||
|
|
||||||
@@ -324,8 +364,8 @@ Quick diagnosis guide for common issues.
|
|||||||
## Quick Reference
|
## Quick Reference
|
||||||
|
|
||||||
| Symptom | Likely Cause | Quick Fix |
|
| Symptom | Likely Cause | Quick Fix |
|
||||||
|---------|-------------|-----------|
|
| ------- | ------------ | --------- |
|
||||||
| ... | ... | ... |
|
| ... | ... | ... |
|
||||||
|
|
||||||
## Detailed Guides
|
## Detailed Guides
|
||||||
|
|
||||||
@@ -335,6 +375,7 @@ Quick diagnosis guide for common issues.
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Individual Issue Files**:
|
**Individual Issue Files**:
|
||||||
|
|
||||||
- Symptom-based organization
|
- Symptom-based organization
|
||||||
- Step-by-step resolution
|
- Step-by-step resolution
|
||||||
- Bash commands for verification
|
- Bash commands for verification
|
||||||
@@ -346,6 +387,7 @@ Quick diagnosis guide for common issues.
|
|||||||
**docs/development/testing.md**:
|
**docs/development/testing.md**:
|
||||||
|
|
||||||
**Required Sections**:
|
**Required Sections**:
|
||||||
|
|
||||||
1. Overview (testing philosophy, types of tests)
|
1. Overview (testing philosophy, types of tests)
|
||||||
2. Unit Testing (framework, running tests, writing tests, examples)
|
2. Unit Testing (framework, running tests, writing tests, examples)
|
||||||
3. E2E Testing (framework, prerequisites, running 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)
|
7. Debugging (common issues, useful commands)
|
||||||
|
|
||||||
**Formatting**:
|
**Formatting**:
|
||||||
|
|
||||||
- Tables for test types and coverage goals
|
- Tables for test types and coverage goals
|
||||||
- Code blocks for examples
|
- Code blocks for examples
|
||||||
- Bash commands for running tests
|
- Bash commands for running tests
|
||||||
@@ -363,6 +406,7 @@ Quick diagnosis guide for common issues.
|
|||||||
### 10. Visual Formatting Standards
|
### 10. Visual Formatting Standards
|
||||||
|
|
||||||
**Emoji Usage** (Strategic, Not Excessive):
|
**Emoji Usage** (Strategic, Not Excessive):
|
||||||
|
|
||||||
- 📚 Documentation
|
- 📚 Documentation
|
||||||
- 🚀 Installation/Quick Start
|
- 🚀 Installation/Quick Start
|
||||||
- 🔒 Security
|
- 🔒 Security
|
||||||
@@ -375,6 +419,7 @@ Quick diagnosis guide for common issues.
|
|||||||
- 💻 Code/Technical
|
- 💻 Code/Technical
|
||||||
|
|
||||||
**Code Block Languages**:
|
**Code Block Languages**:
|
||||||
|
|
||||||
- `bash` for shell commands
|
- `bash` for shell commands
|
||||||
- `yaml` for Kubernetes/Helm manifests
|
- `yaml` for Kubernetes/Helm manifests
|
||||||
- `typescript` for TypeScript code
|
- `typescript` for TypeScript code
|
||||||
@@ -382,11 +427,13 @@ Quick diagnosis guide for common issues.
|
|||||||
- `diff` for showing changes
|
- `diff` for showing changes
|
||||||
|
|
||||||
**Tables**:
|
**Tables**:
|
||||||
|
|
||||||
- Use for structured data (prerequisites, commands, permissions, troubleshooting)
|
- Use for structured data (prerequisites, commands, permissions, troubleshooting)
|
||||||
- Keep columns concise
|
- Keep columns concise
|
||||||
- Left-align text columns, center-align status columns
|
- Left-align text columns, center-align status columns
|
||||||
|
|
||||||
**Links**:
|
**Links**:
|
||||||
|
|
||||||
- Use descriptive text, not "click here"
|
- Use descriptive text, not "click here"
|
||||||
- Relative paths within repo (`docs/architecture/overview.md`)
|
- Relative paths within repo (`docs/architecture/overview.md`)
|
||||||
- Absolute URLs for external resources
|
- Absolute URLs for external resources
|
||||||
@@ -397,6 +444,7 @@ Quick diagnosis guide for common issues.
|
|||||||
### Phase 1: Polaris Plugin Enhancements
|
### Phase 1: Polaris Plugin Enhancements
|
||||||
|
|
||||||
**Priority 1: Granular Documentation Structure**
|
**Priority 1: Granular Documentation Structure**
|
||||||
|
|
||||||
- [ ] Create docs/README.md (documentation hub)
|
- [ ] Create docs/README.md (documentation hub)
|
||||||
- [ ] Break down DEPLOYMENT.md:
|
- [ ] Break down DEPLOYMENT.md:
|
||||||
- [ ] docs/getting-started/installation.md
|
- [ ] docs/getting-started/installation.md
|
||||||
@@ -414,6 +462,7 @@ Quick diagnosis guide for common issues.
|
|||||||
- [ ] Move TESTING.md → docs/development/testing.md
|
- [ ] Move TESTING.md → docs/development/testing.md
|
||||||
|
|
||||||
**Priority 2: Add Missing Content**
|
**Priority 2: Add Missing Content**
|
||||||
|
|
||||||
- [ ] Create docs/getting-started/quick-start.md (5-minute tutorial)
|
- [ ] Create docs/getting-started/quick-start.md (5-minute tutorial)
|
||||||
- [ ] Create docs/user-guide/features.md
|
- [ ] Create docs/user-guide/features.md
|
||||||
- [ ] Create docs/user-guide/configuration.md
|
- [ ] Create docs/user-guide/configuration.md
|
||||||
@@ -421,6 +470,7 @@ Quick diagnosis guide for common issues.
|
|||||||
- [ ] Create FAQ section in troubleshooting
|
- [ ] Create FAQ section in troubleshooting
|
||||||
|
|
||||||
**Priority 3: Content Refinement**
|
**Priority 3: Content Refinement**
|
||||||
|
|
||||||
- [ ] Add multi-platform instructions to installation.md
|
- [ ] Add multi-platform instructions to installation.md
|
||||||
- [ ] Enhance README.md with better visual hierarchy
|
- [ ] Enhance README.md with better visual hierarchy
|
||||||
- [ ] Add more code examples to user guide
|
- [ ] Add more code examples to user guide
|
||||||
@@ -429,18 +479,21 @@ Quick diagnosis guide for common issues.
|
|||||||
### Phase 2: Sealed Secrets Plugin Enhancements
|
### Phase 2: Sealed Secrets Plugin Enhancements
|
||||||
|
|
||||||
**Priority 1: Root-Level Documentation**
|
**Priority 1: Root-Level Documentation**
|
||||||
|
|
||||||
- [ ] Extract CONTRIBUTING.md from README
|
- [ ] Extract CONTRIBUTING.md from README
|
||||||
- [ ] Create SECURITY.md with vulnerability reporting
|
- [ ] Create SECURITY.md with vulnerability reporting
|
||||||
- [ ] Expand CHANGELOG.md to include all versions
|
- [ ] Expand CHANGELOG.md to include all versions
|
||||||
- [ ] Update README.md to match standardized format
|
- [ ] Update README.md to match standardized format
|
||||||
|
|
||||||
**Priority 2: Complete Incomplete Files**
|
**Priority 2: Complete Incomplete Files**
|
||||||
|
|
||||||
- [ ] Finish placeholder tutorial files
|
- [ ] Finish placeholder tutorial files
|
||||||
- [ ] Add E2E testing guide to docs/development/testing.md
|
- [ ] Add E2E testing guide to docs/development/testing.md
|
||||||
- [ ] Expand API reference (ensure generated docs are readable)
|
- [ ] Expand API reference (ensure generated docs are readable)
|
||||||
- [ ] Add FAQ section
|
- [ ] Add FAQ section
|
||||||
|
|
||||||
**Priority 3: Content Refinement**
|
**Priority 3: Content Refinement**
|
||||||
|
|
||||||
- [ ] Add CI/CD badges to README
|
- [ ] Add CI/CD badges to README
|
||||||
- [ ] Ensure consistent emoji usage
|
- [ ] Ensure consistent emoji usage
|
||||||
- [ ] Standardize code block languages
|
- [ ] Standardize code block languages
|
||||||
@@ -449,12 +502,14 @@ Quick diagnosis guide for common issues.
|
|||||||
### Phase 3: Cross-Repository Standards
|
### Phase 3: Cross-Repository Standards
|
||||||
|
|
||||||
**Documentation Templates**
|
**Documentation Templates**
|
||||||
|
|
||||||
- [ ] ADR template in both repos
|
- [ ] ADR template in both repos
|
||||||
- [ ] Bug report template (GitHub issue template)
|
- [ ] Bug report template (GitHub issue template)
|
||||||
- [ ] Feature request template
|
- [ ] Feature request template
|
||||||
- [ ] PR template
|
- [ ] PR template
|
||||||
|
|
||||||
**Shared Patterns**
|
**Shared Patterns**
|
||||||
|
|
||||||
- [ ] Consistent branching strategy docs
|
- [ ] Consistent branching strategy docs
|
||||||
- [ ] Identical commit message conventions
|
- [ ] Identical commit message conventions
|
||||||
- [ ] Same release process documentation
|
- [ ] Same release process documentation
|
||||||
@@ -463,21 +518,25 @@ Quick diagnosis guide for common issues.
|
|||||||
## Success Metrics
|
## Success Metrics
|
||||||
|
|
||||||
**Completeness**:
|
**Completeness**:
|
||||||
|
|
||||||
- [ ] All standard files present in both repos
|
- [ ] All standard files present in both repos
|
||||||
- [ ] No broken links in documentation
|
- [ ] No broken links in documentation
|
||||||
- [ ] All code examples tested and functional
|
- [ ] All code examples tested and functional
|
||||||
|
|
||||||
**Consistency**:
|
**Consistency**:
|
||||||
|
|
||||||
- [ ] Same file structure in both repos
|
- [ ] Same file structure in both repos
|
||||||
- [ ] Same formatting standards applied
|
- [ ] Same formatting standards applied
|
||||||
- [ ] Same terminology used for common concepts
|
- [ ] Same terminology used for common concepts
|
||||||
|
|
||||||
**Usability**:
|
**Usability**:
|
||||||
|
|
||||||
- [ ] New users can get started in < 5 minutes
|
- [ ] New users can get started in < 5 minutes
|
||||||
- [ ] Contributors can find development workflow easily
|
- [ ] Contributors can find development workflow easily
|
||||||
- [ ] Troubleshooting guides resolve 80%+ of common issues
|
- [ ] Troubleshooting guides resolve 80%+ of common issues
|
||||||
|
|
||||||
**Maintainability**:
|
**Maintainability**:
|
||||||
|
|
||||||
- [ ] Documentation updates documented in CHANGELOG
|
- [ ] Documentation updates documented in CHANGELOG
|
||||||
- [ ] ADRs created for all major decisions
|
- [ ] ADRs created for all major decisions
|
||||||
- [ ] Test documentation kept in sync with code
|
- [ ] Test documentation kept in sync with code
|
||||||
@@ -485,6 +544,7 @@ Quick diagnosis guide for common issues.
|
|||||||
## Maintenance Guidelines
|
## Maintenance Guidelines
|
||||||
|
|
||||||
**When to Update Documentation**:
|
**When to Update Documentation**:
|
||||||
|
|
||||||
1. **New Feature**: Add to CHANGELOG, update user guide, add tutorial if complex
|
1. **New Feature**: Add to CHANGELOG, update user guide, add tutorial if complex
|
||||||
2. **Bug Fix**: Add to CHANGELOG, update troubleshooting if user-facing
|
2. **Bug Fix**: Add to CHANGELOG, update troubleshooting if user-facing
|
||||||
3. **Architecture Change**: Create ADR, update architecture docs
|
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
|
6. **Configuration Change**: Update user guide, add migration notes if needed
|
||||||
|
|
||||||
**Documentation Review Checklist**:
|
**Documentation Review Checklist**:
|
||||||
|
|
||||||
- [ ] Spelling and grammar checked
|
- [ ] Spelling and grammar checked
|
||||||
- [ ] Links tested (no 404s)
|
- [ ] Links tested (no 404s)
|
||||||
- [ ] Code examples tested
|
- [ ] Code examples tested
|
||||||
@@ -502,6 +563,7 @@ Quick diagnosis guide for common issues.
|
|||||||
- [ ] Version numbers current
|
- [ ] Version numbers current
|
||||||
|
|
||||||
**Annual Documentation Audit**:
|
**Annual Documentation Audit**:
|
||||||
|
|
||||||
- Review all docs for accuracy (especially version numbers, screenshots)
|
- Review all docs for accuracy (especially version numbers, screenshots)
|
||||||
- Check for outdated information
|
- Check for outdated information
|
||||||
- Update ADR status if superseded
|
- Update ADR status if superseded
|
||||||
@@ -512,30 +574,30 @@ Quick diagnosis guide for common issues.
|
|||||||
|
|
||||||
### Polaris Plugin Current → Standard
|
### Polaris Plugin Current → Standard
|
||||||
|
|
||||||
| Current | Standard Location |
|
| Current | Standard Location |
|
||||||
|---------|-------------------|
|
| ----------------------- | ---------------------------------------------------------------------------------------------- |
|
||||||
| README.md | README.md (enhanced) |
|
| README.md | README.md (enhanced) |
|
||||||
| CHANGELOG.md | CHANGELOG.md (no change) |
|
| CHANGELOG.md | CHANGELOG.md (no change) |
|
||||||
| CONTRIBUTING.md | CONTRIBUTING.md (no change) |
|
| CONTRIBUTING.md | CONTRIBUTING.md (no change) |
|
||||||
| SECURITY.md | SECURITY.md (no change) |
|
| SECURITY.md | SECURITY.md (no change) |
|
||||||
| docs/ARCHITECTURE.md | docs/architecture/overview.md + data-flow.md + design-decisions.md |
|
| 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/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/TROUBLESHOOTING.md | docs/troubleshooting/README.md + common-issues.md |
|
||||||
| docs/TESTING.md | docs/development/testing.md |
|
| docs/TESTING.md | docs/development/testing.md |
|
||||||
| — (new) | docs/README.md |
|
| — (new) | docs/README.md |
|
||||||
| — (new) | docs/getting-started/quick-start.md |
|
| — (new) | docs/getting-started/quick-start.md |
|
||||||
| — (new) | docs/user-guide/features.md |
|
| — (new) | docs/user-guide/features.md |
|
||||||
| — (new) | docs/architecture/adr/ |
|
| — (new) | docs/architecture/adr/ |
|
||||||
|
|
||||||
### Sealed Secrets Plugin Current → Standard
|
### Sealed Secrets Plugin Current → Standard
|
||||||
|
|
||||||
| Current | Standard Location |
|
| Current | Standard Location |
|
||||||
|---------|-------------------|
|
| ------------ | ----------------------------------------------- |
|
||||||
| README.md | README.md (extract contributing section) |
|
| README.md | README.md (extract contributing section) |
|
||||||
| CHANGELOG.md | CHANGELOG.md (expand) |
|
| CHANGELOG.md | CHANGELOG.md (expand) |
|
||||||
| — (new) | CONTRIBUTING.md (extract from README) |
|
| — (new) | CONTRIBUTING.md (extract from README) |
|
||||||
| — (new) | SECURITY.md (new file) |
|
| — (new) | SECURITY.md (new file) |
|
||||||
| docs/* | docs/* (mostly keep, enhance incomplete files) |
|
| docs/\* | docs/\* (mostly keep, enhance incomplete files) |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+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:
|
The Headlamp Polaris Plugin uses a multi-layered testing approach:
|
||||||
|
|
||||||
| Test Type | Framework | Purpose | Location |
|
| Test Type | Framework | Purpose | Location |
|
||||||
|-----------|-----------|---------|----------|
|
| ----------------- | ---------- | ------------------------------------------------------- | ----------------------- |
|
||||||
| **Unit Tests** | Vitest | Test individual functions and components in isolation | `src/**/*.test.ts(x)` |
|
| **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` |
|
| **E2E Tests** | Playwright | Test complete user flows against live Headlamp instance | `e2e/*.spec.ts` |
|
||||||
| **Type Checking** | TypeScript | Ensure type safety across codebase | `tsc --noEmit` |
|
| **Type Checking** | TypeScript | Ensure type safety across codebase | `tsc --noEmit` |
|
||||||
| **Linting** | ESLint | Enforce code style and catch common errors | `eslint src/` |
|
| **Linting** | ESLint | Enforce code style and catch common errors | `eslint src/` |
|
||||||
| **Formatting** | Prettier | Maintain consistent code formatting | `prettier --check src/` |
|
| **Formatting** | Prettier | Maintain consistent code formatting | `prettier --check src/` |
|
||||||
|
|
||||||
### Test Philosophy
|
### Test Philosophy
|
||||||
|
|
||||||
@@ -178,7 +178,9 @@ describe('DashboardView', () => {
|
|||||||
const mockData = {
|
const mockData = {
|
||||||
DisplayName: 'test-cluster',
|
DisplayName: 'test-cluster',
|
||||||
ClusterInfo: { Version: '1.27', Nodes: 3, Pods: 100, Namespaces: 10, Controllers: 50 },
|
ClusterInfo: { Version: '1.27', Nodes: 3, Pods: 100, Namespaces: 10, Controllers: 50 },
|
||||||
Results: [/* ... */],
|
Results: [
|
||||||
|
/* ... */
|
||||||
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
vi.spyOn(PolarisDataContext, 'usePolarisDataContext').mockReturnValue({
|
vi.spyOn(PolarisDataContext, 'usePolarisDataContext').mockReturnValue({
|
||||||
@@ -197,6 +199,7 @@ describe('DashboardView', () => {
|
|||||||
### What to Unit Test
|
### What to Unit Test
|
||||||
|
|
||||||
✅ **Do test:**
|
✅ **Do test:**
|
||||||
|
|
||||||
- Pure functions (score calculation, filtering, data transformation)
|
- Pure functions (score calculation, filtering, data transformation)
|
||||||
- Data parsing and validation
|
- Data parsing and validation
|
||||||
- Utility functions
|
- Utility functions
|
||||||
@@ -204,6 +207,7 @@ describe('DashboardView', () => {
|
|||||||
- Edge cases (empty arrays, null values, invalid input)
|
- Edge cases (empty arrays, null values, invalid input)
|
||||||
|
|
||||||
❌ **Don't test:**
|
❌ **Don't test:**
|
||||||
|
|
||||||
- Third-party libraries (Headlamp, React)
|
- Third-party libraries (Headlamp, React)
|
||||||
- Simple prop passing
|
- Simple prop passing
|
||||||
- Trivial getters/setters
|
- Trivial getters/setters
|
||||||
@@ -242,6 +246,7 @@ npx playwright show-trace test-results/<test-name>/trace.zip
|
|||||||
**1. Headlamp Instance**
|
**1. Headlamp Instance**
|
||||||
|
|
||||||
E2E tests require a running Headlamp instance with:
|
E2E tests require a running Headlamp instance with:
|
||||||
|
|
||||||
- Polaris plugin installed (version being tested)
|
- Polaris plugin installed (version being tested)
|
||||||
- Polaris dashboard deployed and accessible
|
- Polaris dashboard deployed and accessible
|
||||||
- RBAC configured (service proxy permissions)
|
- RBAC configured (service proxy permissions)
|
||||||
@@ -296,32 +301,32 @@ AUTHENTIK_PASSWORD=secret
|
|||||||
|
|
||||||
**File:** `e2e/polaris.spec.ts`
|
**File:** `e2e/polaris.spec.ts`
|
||||||
|
|
||||||
| Test | Description | Validates |
|
| Test | Description | Validates |
|
||||||
|------|-------------|-----------|
|
| --------------------------------------------- | ------------------------------- | ----------------------------- |
|
||||||
| `sidebar contains Polaris entry` | Polaris appears in sidebar | Plugin registration |
|
| `sidebar contains Polaris entry` | Polaris appears in sidebar | Plugin registration |
|
||||||
| `overview page renders cluster score` | Score displayed on overview | Data fetching, rendering |
|
| `overview page renders cluster score` | Score displayed on overview | Data fetching, rendering |
|
||||||
| `namespaces page renders table` | Namespace table loads | Data parsing, table 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 opens` | Clicking namespace shows drawer | Navigation, drawer UI |
|
||||||
| `namespace detail drawer closes with Escape` | Keyboard shortcut works | Keyboard navigation |
|
| `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 |
|
| `namespace detail drawer opens from URL hash` | Direct URL navigation | URL routing, deep linking |
|
||||||
|
|
||||||
**File:** `e2e/settings.spec.ts`
|
**File:** `e2e/settings.spec.ts`
|
||||||
|
|
||||||
| Test | Description | Validates |
|
| Test | Description | Validates |
|
||||||
|------|-------------|-----------|
|
| ------------------------------------ | ------------------- | --------------------------- |
|
||||||
| `plugin settings page is accessible` | Settings page loads | Settings registration |
|
| `plugin settings page is accessible` | Settings page loads | Settings registration |
|
||||||
| `refresh interval can be changed` | Dropdown works | User preference persistence |
|
| `refresh interval can be changed` | Dropdown works | User preference persistence |
|
||||||
| `dashboard URL can be customized` | Input field works | URL configuration |
|
| `dashboard URL can be customized` | Input field works | URL configuration |
|
||||||
| `connection test button works` | Test functionality | API connectivity validation |
|
| `connection test button works` | Test functionality | API connectivity validation |
|
||||||
|
|
||||||
**File:** `e2e/appbar.spec.ts`
|
**File:** `e2e/appbar.spec.ts`
|
||||||
|
|
||||||
| Test | Description | Validates |
|
| Test | Description | Validates |
|
||||||
|------|-------------|-----------|
|
| -------------------------------------- | ------------------------------- | ------------------- |
|
||||||
| `app bar displays Polaris badge` | Badge visible in header | App bar integration |
|
| `app bar displays Polaris badge` | Badge visible in header | App bar integration |
|
||||||
| `badge shows cluster score` | Score matches dashboard | Data consistency |
|
| `badge shows cluster score` | Score matches dashboard | Data consistency |
|
||||||
| `clicking badge navigates to overview` | Navigation works | App bar action |
|
| `clicking badge navigates to overview` | Navigation works | App bar action |
|
||||||
| `badge color reflects score` | Red/yellow/green based on score | Visual feedback |
|
| `badge color reflects score` | Red/yellow/green based on score | Visual feedback |
|
||||||
|
|
||||||
### Writing E2E Tests
|
### Writing E2E Tests
|
||||||
|
|
||||||
@@ -385,6 +390,7 @@ npx playwright test --debug
|
|||||||
```
|
```
|
||||||
|
|
||||||
This opens Playwright Inspector where you can:
|
This opens Playwright Inspector where you can:
|
||||||
|
|
||||||
- Step through each test action
|
- Step through each test action
|
||||||
- Inspect page state
|
- Inspect page state
|
||||||
- Edit test selectors live
|
- Edit test selectors live
|
||||||
@@ -455,12 +461,12 @@ jobs:
|
|||||||
|
|
||||||
Configure in GitHub repository settings (Settings → Secrets and variables → Actions):
|
Configure in GitHub repository settings (Settings → Secrets and variables → Actions):
|
||||||
|
|
||||||
| Secret | Required | Description |
|
| Secret | Required | Description |
|
||||||
|--------|----------|-------------|
|
| -------------------- | -------- | ------------------------------------------------------- |
|
||||||
| `HEADLAMP_URL` | Optional | Headlamp instance URL (defaults to configured instance) |
|
| `HEADLAMP_URL` | Optional | Headlamp instance URL (defaults to configured instance) |
|
||||||
| `AUTHENTIK_USERNAME` | OIDC | Authentik username/email for CI user |
|
| `AUTHENTIK_USERNAME` | OIDC | Authentik username/email for CI user |
|
||||||
| `AUTHENTIK_PASSWORD` | OIDC | Authentik password |
|
| `AUTHENTIK_PASSWORD` | OIDC | Authentik password |
|
||||||
| `HEADLAMP_TOKEN` | Token | Kubernetes service account token (alternative to OIDC) |
|
| `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.
|
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
|
### Current Coverage
|
||||||
|
|
||||||
| Category | Coverage | Notes |
|
| Category | Coverage | Notes |
|
||||||
|----------|----------|-------|
|
| -------------------- | -------- | ------------------------------ |
|
||||||
| **API Functions** | 95% | Core utilities fully tested |
|
| **API Functions** | 95% | Core utilities fully tested |
|
||||||
| **React Components** | 60% | Focus on critical render paths |
|
| **React Components** | 60% | Focus on critical render paths |
|
||||||
| **E2E User Flows** | 80% | Main features covered |
|
| **E2E User Flows** | 80% | Main features covered |
|
||||||
|
|
||||||
### Coverage Goals
|
### Coverage Goals
|
||||||
|
|
||||||
@@ -507,18 +513,22 @@ open coverage/index.html
|
|||||||
### Unit Testing
|
### Unit Testing
|
||||||
|
|
||||||
1. **Test behavior, not implementation**
|
1. **Test behavior, not implementation**
|
||||||
|
|
||||||
- ✅ `expect(computeScore({ total: 100, pass: 75 })).toBe(75)`
|
- ✅ `expect(computeScore({ total: 100, pass: 75 })).toBe(75)`
|
||||||
- ❌ `expect(mockInternalFunction).toHaveBeenCalled()`
|
- ❌ `expect(mockInternalFunction).toHaveBeenCalled()`
|
||||||
|
|
||||||
2. **Use descriptive test names**
|
2. **Use descriptive test names**
|
||||||
|
|
||||||
- ✅ `it('returns 0 when total checks is zero')`
|
- ✅ `it('returns 0 when total checks is zero')`
|
||||||
- ❌ `it('works')`
|
- ❌ `it('works')`
|
||||||
|
|
||||||
3. **One assertion per test (when possible)**
|
3. **One assertion per test (when possible)**
|
||||||
|
|
||||||
- Makes failures easier to debug
|
- Makes failures easier to debug
|
||||||
- Exceptions: testing multiple properties of same object
|
- Exceptions: testing multiple properties of same object
|
||||||
|
|
||||||
4. **Mock external dependencies**
|
4. **Mock external dependencies**
|
||||||
|
|
||||||
- Mock API calls, context providers, external libraries
|
- Mock API calls, context providers, external libraries
|
||||||
- Don't mock the code you're testing
|
- Don't mock the code you're testing
|
||||||
|
|
||||||
@@ -529,27 +539,33 @@ open coverage/index.html
|
|||||||
### E2E Testing
|
### E2E Testing
|
||||||
|
|
||||||
1. **Use semantic selectors**
|
1. **Use semantic selectors**
|
||||||
|
|
||||||
- ✅ `page.getByRole('button', { name: 'Close' })`
|
- ✅ `page.getByRole('button', { name: 'Close' })`
|
||||||
- ✅ `page.getByText('Polaris — Overview')`
|
- ✅ `page.getByText('Polaris — Overview')`
|
||||||
- ❌ `page.locator('.MuiButton-root')`
|
- ❌ `page.locator('.MuiButton-root')`
|
||||||
|
|
||||||
2. **Wait for visibility, not arbitrary timeouts**
|
2. **Wait for visibility, not arbitrary timeouts**
|
||||||
|
|
||||||
- ✅ `await expect(element).toBeVisible()`
|
- ✅ `await expect(element).toBeVisible()`
|
||||||
- ❌ `await page.waitForTimeout(5000)`
|
- ❌ `await page.waitForTimeout(5000)`
|
||||||
|
|
||||||
3. **Keep tests independent**
|
3. **Keep tests independent**
|
||||||
|
|
||||||
- Each test should work in isolation
|
- Each test should work in isolation
|
||||||
- Don't rely on previous tests' state
|
- Don't rely on previous tests' state
|
||||||
|
|
||||||
4. **Test complete user flows**
|
4. **Test complete user flows**
|
||||||
|
|
||||||
- Navigate → Interact → Verify outcome
|
- Navigate → Interact → Verify outcome
|
||||||
- Don't just test page loads
|
- Don't just test page loads
|
||||||
|
|
||||||
5. **Clean up after tests**
|
5. **Clean up after tests**
|
||||||
|
|
||||||
- Close drawers/modals
|
- Close drawers/modals
|
||||||
- Reset state if needed
|
- Reset state if needed
|
||||||
|
|
||||||
6. **Use storage state for auth**
|
6. **Use storage state for auth**
|
||||||
|
|
||||||
- Reuse authenticated session across tests
|
- Reuse authenticated session across tests
|
||||||
- Faster than logging in for every test
|
- Faster than logging in for every test
|
||||||
|
|
||||||
@@ -560,15 +576,18 @@ open coverage/index.html
|
|||||||
### General
|
### General
|
||||||
|
|
||||||
1. **Run tests before committing**
|
1. **Run tests before committing**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run build && npm run lint && npm test
|
npm run build && npm run lint && npm test
|
||||||
```
|
```
|
||||||
|
|
||||||
2. **Fix failing tests immediately**
|
2. **Fix failing tests immediately**
|
||||||
|
|
||||||
- Don't commit failing tests
|
- Don't commit failing tests
|
||||||
- Don't skip tests to "fix later"
|
- Don't skip tests to "fix later"
|
||||||
|
|
||||||
3. **Update tests when changing code**
|
3. **Update tests when changing code**
|
||||||
|
|
||||||
- Tests are documentation
|
- Tests are documentation
|
||||||
- Keep them in sync with implementation
|
- Keep them in sync with implementation
|
||||||
|
|
||||||
@@ -604,7 +623,7 @@ Check mocks are returning expected structure:
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
vi.spyOn(PolarisDataContext, 'usePolarisDataContext').mockReturnValue({
|
vi.spyOn(PolarisDataContext, 'usePolarisDataContext').mockReturnValue({
|
||||||
data: mockData, // Ensure mockData has all required fields
|
data: mockData, // Ensure mockData has all required fields
|
||||||
loading: false,
|
loading: false,
|
||||||
error: null,
|
error: null,
|
||||||
refresh: vi.fn(),
|
refresh: vi.fn(),
|
||||||
@@ -624,6 +643,7 @@ npm run e2e:headed
|
|||||||
```
|
```
|
||||||
|
|
||||||
Common causes:
|
Common causes:
|
||||||
|
|
||||||
- Element hasn't rendered yet (use `toBeVisible()` instead of `toBeDefined()`)
|
- Element hasn't rendered yet (use `toBeVisible()` instead of `toBeDefined()`)
|
||||||
- Wrong selector (use Playwright Inspector to verify)
|
- Wrong selector (use Playwright Inspector to verify)
|
||||||
- Authentication failed (check token/credentials)
|
- Authentication failed (check token/credentials)
|
||||||
|
|||||||
+65
-28
@@ -20,34 +20,17 @@ This guide covers common issues encountered when using the Headlamp Polaris Plug
|
|||||||
## Plugin Not Showing in Sidebar
|
## Plugin Not Showing in Sidebar
|
||||||
|
|
||||||
### Symptoms
|
### Symptoms
|
||||||
|
|
||||||
- Plugin appears in Settings → Plugins but sidebar entry is missing
|
- Plugin appears in Settings → Plugins but sidebar entry is missing
|
||||||
- No "Polaris" section in navigation
|
- No "Polaris" section in navigation
|
||||||
- Routes like `/polaris` return 404 or blank page
|
- Routes like `/polaris` return 404 or blank page
|
||||||
|
|
||||||
### Common Causes
|
### Common Causes
|
||||||
|
|
||||||
**1. Headlamp v0.39.0+ Plugin Loading Issue**
|
**1. Plugin Not Installed**
|
||||||
|
|
||||||
**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**
|
|
||||||
|
|
||||||
**Check plugin installation**:
|
**Check plugin installation**:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# View Headlamp pod logs (plugin sidecar)
|
# View Headlamp pod logs (plugin sidecar)
|
||||||
kubectl logs -n kube-system deployment/headlamp -c headlamp-plugin
|
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**:
|
**Verify plugin files exist**:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl exec -n kube-system deployment/headlamp -c headlamp -- ls -la /headlamp/plugins/
|
kubectl exec -n kube-system deployment/headlamp -c headlamp -- ls -la /headlamp/plugins/
|
||||||
# Should show: headlamp-polaris-plugin/
|
# Should show: headlamp-polaris-plugin/
|
||||||
```
|
```
|
||||||
|
|
||||||
**3. JavaScript Cached by Browser**
|
**2. JavaScript Cached by Browser**
|
||||||
|
|
||||||
After upgrading the plugin, old JavaScript may be cached.
|
After upgrading the plugin, old JavaScript may be cached.
|
||||||
|
|
||||||
**Solution**:
|
**Solution**:
|
||||||
|
|
||||||
- Hard refresh: Cmd+Shift+R (macOS) or Ctrl+Shift+R (Linux/Windows)
|
- Hard refresh: Cmd+Shift+R (macOS) or Ctrl+Shift+R (Linux/Windows)
|
||||||
- Clear browser cache for Headlamp domain
|
- Clear browser cache for Headlamp domain
|
||||||
- Open DevTools → Application → Clear Storage → Clear all
|
- Open DevTools → Application → Clear Storage → Clear all
|
||||||
|
|
||||||
**4. Plugin Disabled in Settings**
|
**3. Plugin Disabled in Settings**
|
||||||
|
|
||||||
**Check Settings → Plugins**:
|
**Check Settings → Plugins**:
|
||||||
|
|
||||||
- Navigate to Headlamp Settings → Plugins
|
- Navigate to Headlamp Settings → Plugins
|
||||||
- Ensure "Polaris" plugin is enabled (toggle should be ON)
|
- Ensure "Polaris" plugin is enabled (toggle should be ON)
|
||||||
- If disabled, enable it and refresh the page
|
- If disabled, enable it and refresh the page
|
||||||
@@ -84,11 +70,13 @@ After upgrading the plugin, old JavaScript may be cached.
|
|||||||
## 403 Forbidden Error
|
## 403 Forbidden Error
|
||||||
|
|
||||||
### Symptoms
|
### Symptoms
|
||||||
|
|
||||||
- Error message: "Error loading Polaris audit data: 403 Forbidden"
|
- Error message: "Error loading Polaris audit data: 403 Forbidden"
|
||||||
- Browser console shows 403 response from API proxy
|
- Browser console shows 403 response from API proxy
|
||||||
- Plugin sidebar shows but data fails to load
|
- Plugin sidebar shows but data fails to load
|
||||||
|
|
||||||
### Root Cause
|
### Root Cause
|
||||||
|
|
||||||
User or service account lacks `services/proxy` permission on `polaris-dashboard` service in the `polaris` namespace.
|
User or service account lacks `services/proxy` permission on `polaris-dashboard` service in the `polaris` namespace.
|
||||||
|
|
||||||
### Solution
|
### Solution
|
||||||
@@ -96,11 +84,13 @@ User or service account lacks `services/proxy` permission on `polaris-dashboard`
|
|||||||
**1. Verify RBAC Configuration**
|
**1. Verify RBAC Configuration**
|
||||||
|
|
||||||
Check if Role exists:
|
Check if Role exists:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl get role polaris-proxy-reader -n polaris -o yaml
|
kubectl get role polaris-proxy-reader -n polaris -o yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
Expected output:
|
Expected output:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
apiVersion: rbac.authorization.k8s.io/v1
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
kind: Role
|
kind: Role
|
||||||
@@ -108,20 +98,22 @@ metadata:
|
|||||||
name: polaris-proxy-reader
|
name: polaris-proxy-reader
|
||||||
namespace: polaris
|
namespace: polaris
|
||||||
rules:
|
rules:
|
||||||
- apiGroups: [""]
|
- apiGroups: ['']
|
||||||
resources: ["services/proxy"]
|
resources: ['services/proxy']
|
||||||
resourceNames: ["polaris-dashboard"]
|
resourceNames: ['polaris-dashboard']
|
||||||
verbs: ["get"]
|
verbs: ['get']
|
||||||
```
|
```
|
||||||
|
|
||||||
**2. Verify RoleBinding**
|
**2. Verify RoleBinding**
|
||||||
|
|
||||||
For service account mode:
|
For service account mode:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl get rolebinding headlamp-polaris-proxy -n polaris -o yaml
|
kubectl get rolebinding headlamp-polaris-proxy -n polaris -o yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
Expected subjects:
|
Expected subjects:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
subjects:
|
subjects:
|
||||||
- kind: ServiceAccount
|
- kind: ServiceAccount
|
||||||
@@ -130,6 +122,7 @@ subjects:
|
|||||||
```
|
```
|
||||||
|
|
||||||
For OIDC mode:
|
For OIDC mode:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl get rolebinding -n polaris -o yaml | grep -A 5 polaris-proxy-reader
|
kubectl get rolebinding -n polaris -o yaml | grep -A 5 polaris-proxy-reader
|
||||||
```
|
```
|
||||||
@@ -172,6 +165,7 @@ EOF
|
|||||||
**4. Test RBAC Permissions**
|
**4. Test RBAC Permissions**
|
||||||
|
|
||||||
Service account mode:
|
Service account mode:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Impersonate Headlamp service account
|
# Impersonate Headlamp service account
|
||||||
kubectl auth can-i get services/proxy \
|
kubectl auth can-i get services/proxy \
|
||||||
@@ -182,6 +176,7 @@ kubectl auth can-i get services/proxy \
|
|||||||
```
|
```
|
||||||
|
|
||||||
OIDC mode (test as yourself):
|
OIDC mode (test as yourself):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl auth can-i get services/proxy \
|
kubectl auth can-i get services/proxy \
|
||||||
--resource-name=polaris-dashboard \
|
--resource-name=polaris-dashboard \
|
||||||
@@ -192,6 +187,7 @@ kubectl auth can-i get services/proxy \
|
|||||||
**5. Restart Headlamp**
|
**5. Restart Headlamp**
|
||||||
|
|
||||||
After applying RBAC changes:
|
After applying RBAC changes:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl rollout restart deployment headlamp -n kube-system
|
kubectl rollout restart deployment headlamp -n kube-system
|
||||||
```
|
```
|
||||||
@@ -201,11 +197,13 @@ kubectl rollout restart deployment headlamp -n kube-system
|
|||||||
## 404 Not Found Error
|
## 404 Not Found Error
|
||||||
|
|
||||||
### Symptoms
|
### Symptoms
|
||||||
|
|
||||||
- Error message: "Error loading Polaris audit data: 404 Not Found"
|
- Error message: "Error loading Polaris audit data: 404 Not Found"
|
||||||
- Service proxy request returns 404
|
- Service proxy request returns 404
|
||||||
- Polaris dashboard not reachable
|
- Polaris dashboard not reachable
|
||||||
|
|
||||||
### Root Cause
|
### Root Cause
|
||||||
|
|
||||||
Polaris dashboard service doesn't exist or is in a different namespace.
|
Polaris dashboard service doesn't exist or is in a different namespace.
|
||||||
|
|
||||||
### Solution
|
### Solution
|
||||||
@@ -213,12 +211,14 @@ Polaris dashboard service doesn't exist or is in a different namespace.
|
|||||||
**1. Verify Polaris Installation**
|
**1. Verify Polaris Installation**
|
||||||
|
|
||||||
Check if Polaris is installed:
|
Check if Polaris is installed:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl get pods -n polaris
|
kubectl get pods -n polaris
|
||||||
# Expected: polaris-dashboard-* pod running
|
# Expected: polaris-dashboard-* pod running
|
||||||
```
|
```
|
||||||
|
|
||||||
Check if service exists:
|
Check if service exists:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl get service polaris-dashboard -n polaris
|
kubectl get service polaris-dashboard -n polaris
|
||||||
# Expected: ClusterIP service on port 80
|
# Expected: ClusterIP service on port 80
|
||||||
@@ -227,6 +227,7 @@ kubectl get service polaris-dashboard -n polaris
|
|||||||
**2. Verify Service Name and Port**
|
**2. Verify Service Name and Port**
|
||||||
|
|
||||||
The plugin expects:
|
The plugin expects:
|
||||||
|
|
||||||
- **Namespace**: `polaris`
|
- **Namespace**: `polaris`
|
||||||
- **Service Name**: `polaris-dashboard`
|
- **Service Name**: `polaris-dashboard`
|
||||||
- **Port**: `80` (or named port `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**
|
**4. Check Polaris Dashboard Configuration**
|
||||||
|
|
||||||
Verify Polaris is running with dashboard enabled:
|
Verify Polaris is running with dashboard enabled:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl get deployment polaris-dashboard -n polaris -o yaml | grep -A 5 dashboard
|
kubectl get deployment polaris-dashboard -n polaris -o yaml | grep -A 5 dashboard
|
||||||
```
|
```
|
||||||
|
|
||||||
If `dashboard.enabled: false` in Helm values, enable it:
|
If `dashboard.enabled: false` in Helm values, enable it:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
# values.yaml
|
# values.yaml
|
||||||
dashboard:
|
dashboard:
|
||||||
@@ -260,6 +263,7 @@ dashboard:
|
|||||||
**5. Reinstall Polaris**
|
**5. Reinstall Polaris**
|
||||||
|
|
||||||
If Polaris is missing or misconfigured:
|
If Polaris is missing or misconfigured:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
helm repo add fairwinds-stable https://charts.fairwinds.com/stable
|
helm repo add fairwinds-stable https://charts.fairwinds.com/stable
|
||||||
helm upgrade --install polaris fairwinds-stable/polaris \
|
helm upgrade --install polaris fairwinds-stable/polaris \
|
||||||
@@ -273,21 +277,25 @@ helm upgrade --install polaris fairwinds-stable/polaris \
|
|||||||
## Plugin Settings Page Empty
|
## Plugin Settings Page Empty
|
||||||
|
|
||||||
### Symptoms
|
### Symptoms
|
||||||
|
|
||||||
- Settings → Polaris shows title but no content
|
- Settings → Polaris shows title but no content
|
||||||
- Refresh interval and dashboard URL fields not visible
|
- Refresh interval and dashboard URL fields not visible
|
||||||
|
|
||||||
### Root Cause (Fixed in v0.3.3)
|
### Root Cause (Fixed in v0.3.3)
|
||||||
|
|
||||||
Plugin settings registration name didn't match `package.json` name.
|
Plugin settings registration name didn't match `package.json` name.
|
||||||
|
|
||||||
### Solution
|
### Solution
|
||||||
|
|
||||||
Upgrade to v0.3.3 or later:
|
Upgrade to v0.3.3 or later:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Via Headlamp UI: Settings → Plugins → Update
|
# Via Headlamp UI: Settings → Plugins → Update
|
||||||
# Or redeploy with latest version
|
# Or redeploy with latest version
|
||||||
```
|
```
|
||||||
|
|
||||||
If manually installing, ensure plugin name matches `package.json`:
|
If manually installing, ensure plugin name matches `package.json`:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
registerPluginSettings('headlamp-polaris-plugin', PolarisSettings, true);
|
registerPluginSettings('headlamp-polaris-plugin', PolarisSettings, true);
|
||||||
// NOT 'polaris' — must match package.json name
|
// NOT 'polaris' — must match package.json name
|
||||||
@@ -298,6 +306,7 @@ registerPluginSettings('headlamp-polaris-plugin', PolarisSettings, true);
|
|||||||
## Dark Mode Issues
|
## Dark Mode Issues
|
||||||
|
|
||||||
### Symptoms
|
### Symptoms
|
||||||
|
|
||||||
- Drawer background remains white in dark mode
|
- Drawer background remains white in dark mode
|
||||||
- Text is hard to read in dark mode
|
- Text is hard to read in dark mode
|
||||||
- Theme colors don't match Headlamp UI
|
- 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**:
|
**Verify CSS Variables**:
|
||||||
The plugin uses MUI CSS variables for theming:
|
The plugin uses MUI CSS variables for theming:
|
||||||
|
|
||||||
- `--mui-palette-background-default` (drawer background)
|
- `--mui-palette-background-default` (drawer background)
|
||||||
- `--mui-palette-text-primary` (text color)
|
- `--mui-palette-text-primary` (text color)
|
||||||
- `--mui-palette-primary-main` (links, buttons)
|
- `--mui-palette-primary-main` (links, buttons)
|
||||||
@@ -317,6 +327,7 @@ These automatically adapt to Headlamp's theme (light/dark/system).
|
|||||||
|
|
||||||
**Hard Refresh Required**:
|
**Hard Refresh Required**:
|
||||||
After upgrading from v0.3.4 or earlier, hard refresh your browser:
|
After upgrading from v0.3.4 or earlier, hard refresh your browser:
|
||||||
|
|
||||||
- macOS: Cmd+Shift+R
|
- macOS: Cmd+Shift+R
|
||||||
- Linux/Windows: Ctrl+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
|
## Data Not Loading / Infinite Spinner
|
||||||
|
|
||||||
### Symptoms
|
### Symptoms
|
||||||
|
|
||||||
- Plugin shows "Loading Polaris audit data..." forever
|
- Plugin shows "Loading Polaris audit data..." forever
|
||||||
- No error message in UI
|
- No error message in UI
|
||||||
- Data never appears
|
- Data never appears
|
||||||
@@ -339,6 +351,7 @@ If hard refresh doesn't help, clear cache for Headlamp domain.
|
|||||||
Open DevTools (F12) → Console tab.
|
Open DevTools (F12) → Console tab.
|
||||||
|
|
||||||
Look for:
|
Look for:
|
||||||
|
|
||||||
- Network errors (CORS, timeouts, 5xx responses)
|
- Network errors (CORS, timeouts, 5xx responses)
|
||||||
- JavaScript errors
|
- JavaScript errors
|
||||||
- Failed API requests
|
- Failed API requests
|
||||||
@@ -348,6 +361,7 @@ Look for:
|
|||||||
Open DevTools → Network tab → Filter by "results.json"
|
Open DevTools → Network tab → Filter by "results.json"
|
||||||
|
|
||||||
Expected request:
|
Expected request:
|
||||||
|
|
||||||
```
|
```
|
||||||
GET /api/v1/namespaces/polaris/services/polaris-dashboard:80/proxy/results.json
|
GET /api/v1/namespaces/polaris/services/polaris-dashboard:80/proxy/results.json
|
||||||
Status: 200
|
Status: 200
|
||||||
@@ -355,6 +369,7 @@ Response: JSON data
|
|||||||
```
|
```
|
||||||
|
|
||||||
Common issues:
|
Common issues:
|
||||||
|
|
||||||
- **Status 0 / Failed**: Network policy blocking request
|
- **Status 0 / Failed**: Network policy blocking request
|
||||||
- **Status 403**: RBAC issue (see [403 Forbidden Error](#403-forbidden-error))
|
- **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))
|
- **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**
|
**4. Check Network Policies**
|
||||||
|
|
||||||
If your cluster uses NetworkPolicies:
|
If your cluster uses NetworkPolicies:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl get networkpolicy -n polaris
|
kubectl get networkpolicy -n polaris
|
||||||
```
|
```
|
||||||
@@ -385,6 +401,7 @@ kubectl get networkpolicy -n polaris
|
|||||||
Ensure API server (or Headlamp pod) can reach Polaris dashboard.
|
Ensure API server (or Headlamp pod) can reach Polaris dashboard.
|
||||||
|
|
||||||
**Example fix**:
|
**Example fix**:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
apiVersion: networking.k8s.io/v1
|
apiVersion: networking.k8s.io/v1
|
||||||
kind: NetworkPolicy
|
kind: NetworkPolicy
|
||||||
@@ -399,7 +416,7 @@ spec:
|
|||||||
- Ingress
|
- Ingress
|
||||||
ingress:
|
ingress:
|
||||||
- from:
|
- from:
|
||||||
- namespaceSelector: {} # Allow from all namespaces (API server)
|
- namespaceSelector: {} # Allow from all namespaces (API server)
|
||||||
ports:
|
ports:
|
||||||
- protocol: TCP
|
- protocol: TCP
|
||||||
port: 8080
|
port: 8080
|
||||||
@@ -408,6 +425,7 @@ spec:
|
|||||||
**5. Increase Timeout / Disable Auto-Refresh**
|
**5. Increase Timeout / Disable Auto-Refresh**
|
||||||
|
|
||||||
If Polaris responds slowly:
|
If Polaris responds slowly:
|
||||||
|
|
||||||
- Open Settings → Polaris
|
- Open Settings → Polaris
|
||||||
- Increase refresh interval to 10+ minutes
|
- Increase refresh interval to 10+ minutes
|
||||||
- Or set to "Manual only" to disable auto-refresh
|
- 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)
|
**Cause**: Network request failed (CORS, network policy, timeout)
|
||||||
|
|
||||||
**Solution**:
|
**Solution**:
|
||||||
|
|
||||||
1. Check Network tab for actual HTTP status
|
1. Check Network tab for actual HTTP status
|
||||||
2. Verify network policies allow API server → Polaris
|
2. Verify network policies allow API server → Polaris
|
||||||
3. Check Polaris pod is running
|
3. Check Polaris pod is running
|
||||||
@@ -434,6 +453,7 @@ If Polaris responds slowly:
|
|||||||
**Cause**: API returned HTML (error page) instead of JSON
|
**Cause**: API returned HTML (error page) instead of JSON
|
||||||
|
|
||||||
**Solution**:
|
**Solution**:
|
||||||
|
|
||||||
1. Check Network tab response body (likely 404 or 500 error page)
|
1. Check Network tab response body (likely 404 or 500 error page)
|
||||||
2. Verify Polaris service exists and is healthy
|
2. Verify Polaris service exists and is healthy
|
||||||
3. Check service proxy URL is correct
|
3. Check service proxy URL is correct
|
||||||
@@ -453,6 +473,7 @@ If Polaris responds slowly:
|
|||||||
**Cause**: Polaris returned empty or malformed response
|
**Cause**: Polaris returned empty or malformed response
|
||||||
|
|
||||||
**Solution**:
|
**Solution**:
|
||||||
|
|
||||||
1. Check Polaris logs for errors
|
1. Check Polaris logs for errors
|
||||||
2. Verify Polaris is scanning the cluster (check audit timestamp)
|
2. Verify Polaris is scanning the cluster (check audit timestamp)
|
||||||
3. Test `/results.json` endpoint directly
|
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
|
### Sidecar Fails to Install Plugin
|
||||||
|
|
||||||
**Symptoms**:
|
**Symptoms**:
|
||||||
|
|
||||||
- Plugin sidecar logs show download errors
|
- Plugin sidecar logs show download errors
|
||||||
- Plugin directory is empty
|
- Plugin directory is empty
|
||||||
- Settings → Plugins shows nothing
|
- Settings → Plugins shows nothing
|
||||||
|
|
||||||
**Check sidecar logs**:
|
**Check sidecar logs**:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl logs -n kube-system deployment/headlamp -c headlamp-plugin
|
kubectl logs -n kube-system deployment/headlamp -c headlamp-plugin
|
||||||
```
|
```
|
||||||
@@ -566,11 +589,13 @@ Error: 404 Not Found
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Solution**: Verify `archive-url` in plugin config matches GitHub release:
|
**Solution**: Verify `archive-url` in plugin config matches GitHub release:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl get configmap headlamp-plugin-config -n kube-system -o yaml
|
kubectl get configmap headlamp-plugin-config -n kube-system -o yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
Expected format:
|
Expected format:
|
||||||
|
|
||||||
```
|
```
|
||||||
https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/download/v0.3.10/polaris-0.3.10.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/privilegedescalation/headlamp-polaris-plugin/releases/downloa
|
|||||||
**3. Permission denied writing to /headlamp/plugins**
|
**3. Permission denied writing to /headlamp/plugins**
|
||||||
|
|
||||||
**Solution**: Ensure volume mount is writable:
|
**Solution**: Ensure volume mount is writable:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: plugins
|
- name: plugins
|
||||||
@@ -591,17 +617,18 @@ volumeMounts:
|
|||||||
### Plugin Manager Not Working
|
### Plugin Manager Not Working
|
||||||
|
|
||||||
**Symptoms**:
|
**Symptoms**:
|
||||||
|
|
||||||
- Headlamp → Settings → Plugins shows "Catalog" tab but plugins don't install
|
- Headlamp → Settings → Plugins shows "Catalog" tab but plugins don't install
|
||||||
- "Install" button does nothing
|
- "Install" button does nothing
|
||||||
|
|
||||||
**Root Cause**: Plugin manager requires `config.pluginsDir` to be set.
|
**Root Cause**: Plugin manager requires `config.pluginsDir` to be set.
|
||||||
|
|
||||||
**Solution**: Configure Headlamp for plugin manager:
|
**Solution**: Configure Headlamp for plugin manager:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
# HelmRelease values
|
# HelmRelease values
|
||||||
config:
|
config:
|
||||||
pluginsDir: /headlamp/plugins
|
pluginsDir: /headlamp/plugins
|
||||||
watchPlugins: false # CRITICAL for v0.39.0+
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -609,25 +636,30 @@ config:
|
|||||||
## ArtifactHub Sync Delays
|
## ArtifactHub Sync Delays
|
||||||
|
|
||||||
### Symptoms
|
### Symptoms
|
||||||
|
|
||||||
- New version released on GitHub but not showing in ArtifactHub
|
- New version released on GitHub but not showing in ArtifactHub
|
||||||
- Headlamp plugin catalog shows old version
|
- Headlamp plugin catalog shows old version
|
||||||
|
|
||||||
### Root Cause
|
### Root Cause
|
||||||
|
|
||||||
ArtifactHub pulls metadata every 30 minutes. There is no webhook or push mechanism.
|
ArtifactHub pulls metadata every 30 minutes. There is no webhook or push mechanism.
|
||||||
|
|
||||||
### Solution
|
### Solution
|
||||||
|
|
||||||
**Wait 30 minutes** after pushing a GitHub release, then check:
|
**Wait 30 minutes** after pushing a GitHub release, then check:
|
||||||
|
|
||||||
```
|
```
|
||||||
https://artifacthub.io/packages/headlamp/headlamp-polaris-plugin/headlamp-polaris-plugin
|
https://artifacthub.io/packages/headlamp/headlamp-polaris-plugin/headlamp-polaris-plugin
|
||||||
```
|
```
|
||||||
|
|
||||||
**Verify metadata**:
|
**Verify metadata**:
|
||||||
|
|
||||||
1. Check `artifacthub-pkg.yml` is in repository root
|
1. Check `artifacthub-pkg.yml` is in repository root
|
||||||
2. Check `headlamp/plugin/archive-url` points to GitHub release
|
2. Check `headlamp/plugin/archive-url` points to GitHub release
|
||||||
3. Check `headlamp/plugin/archive-checksum` matches tarball SHA256
|
3. Check `headlamp/plugin/archive-checksum` matches tarball SHA256
|
||||||
|
|
||||||
**Force sync** (ArtifactHub UI):
|
**Force sync** (ArtifactHub UI):
|
||||||
|
|
||||||
- Log in to ArtifactHub as package maintainer
|
- Log in to ArtifactHub as package maintainer
|
||||||
- Go to package settings
|
- Go to package settings
|
||||||
- Click "Reindex now"
|
- Click "Reindex now"
|
||||||
@@ -643,23 +675,28 @@ If none of these solutions work, gather debugging information and open an issue:
|
|||||||
### Required Information
|
### Required Information
|
||||||
|
|
||||||
1. **Version Information**:
|
1. **Version Information**:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl get pods -n kube-system -l app.kubernetes.io/name=headlamp -o yaml | grep image:
|
kubectl get pods -n kube-system -l app.kubernetes.io/name=headlamp -o yaml | grep image:
|
||||||
```
|
```
|
||||||
|
|
||||||
2. **Plugin Version**:
|
2. **Plugin Version**:
|
||||||
|
|
||||||
- Check Settings → Plugins in Headlamp UI
|
- Check Settings → Plugins in Headlamp UI
|
||||||
- Or: `kubectl exec -n kube-system deployment/headlamp -c headlamp -- cat /headlamp/plugins/headlamp-polaris-plugin/package.json`
|
- Or: `kubectl exec -n kube-system deployment/headlamp -c headlamp -- cat /headlamp/plugins/headlamp-polaris-plugin/package.json`
|
||||||
|
|
||||||
3. **Browser Console Output**:
|
3. **Browser Console Output**:
|
||||||
|
|
||||||
- Open DevTools (F12) → Console
|
- Open DevTools (F12) → Console
|
||||||
- Screenshot or copy errors
|
- Screenshot or copy errors
|
||||||
|
|
||||||
4. **Network Tab**:
|
4. **Network Tab**:
|
||||||
|
|
||||||
- Open DevTools → Network
|
- Open DevTools → Network
|
||||||
- Screenshot failed requests to `results.json`
|
- Screenshot failed requests to `results.json`
|
||||||
|
|
||||||
5. **Pod Logs**:
|
5. **Pod Logs**:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl logs -n kube-system deployment/headlamp -c headlamp --tail=100
|
kubectl logs -n kube-system deployment/headlamp -c headlamp --tail=100
|
||||||
kubectl logs -n polaris deployment/polaris-dashboard --tail=100
|
kubectl logs -n polaris deployment/polaris-dashboard --tail=100
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
## Context
|
## Context
|
||||||
|
|
||||||
The Headlamp Polaris Plugin needs to fetch Polaris audit data once and share it across multiple components:
|
The Headlamp Polaris Plugin needs to fetch Polaris audit data once and share it across multiple components:
|
||||||
|
|
||||||
- Dashboard view (cluster overview)
|
- Dashboard view (cluster overview)
|
||||||
- Namespaces list view
|
- Namespaces list view
|
||||||
- Namespace detail view (drawer)
|
- 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.
|
Multiple state management approaches are available: Redux, Zustand, Jotai, Recoil, React Context (built-in), or component props with prop drilling.
|
||||||
|
|
||||||
**Constraints:**
|
**Constraints:**
|
||||||
|
|
||||||
- Headlamp plugin environment does not allow adding external dependencies (peer dependencies only)
|
- Headlamp plugin environment does not allow adding external dependencies (peer dependencies only)
|
||||||
- Redux, Zustand, Jotai, Recoil are not available in the plugin runtime
|
- Redux, Zustand, Jotai, Recoil are not available in the plugin runtime
|
||||||
- Plugin must work with Headlamp's existing React context (React 17+)
|
- Plugin must work with Headlamp's existing React context (React 17+)
|
||||||
- Bundle size should remain small (<50 KB)
|
- Bundle size should remain small (<50 KB)
|
||||||
|
|
||||||
**Requirements:**
|
**Requirements:**
|
||||||
|
|
||||||
- Share `AuditData` object across all views without duplicate API calls
|
- Share `AuditData` object across all views without duplicate API calls
|
||||||
- Support auto-refresh on user-configurable interval (1-30 minutes)
|
- Support auto-refresh on user-configurable interval (1-30 minutes)
|
||||||
- Handle loading and error states consistently
|
- 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.
|
Use **React Context API** (built-in, no dependencies) for shared state management.
|
||||||
|
|
||||||
**Implementation:**
|
**Implementation:**
|
||||||
|
|
||||||
- `PolarisDataProvider` wraps all plugin routes
|
- `PolarisDataProvider` wraps all plugin routes
|
||||||
- `usePolarisDataContext()` hook provides `{ data, loading, error, refresh }` to consumers
|
- `usePolarisDataContext()` hook provides `{ data, loading, error, refresh }` to consumers
|
||||||
- Single fetch shared across all views
|
- 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
|
### Option 1: Redux
|
||||||
|
|
||||||
**Pros:**
|
**Pros:**
|
||||||
|
|
||||||
- Powerful state management with middleware
|
- Powerful state management with middleware
|
||||||
- Excellent DevTools for debugging
|
- Excellent DevTools for debugging
|
||||||
- Time-travel debugging
|
- Time-travel debugging
|
||||||
- Well-established patterns
|
- Well-established patterns
|
||||||
|
|
||||||
**Cons:**
|
**Cons:**
|
||||||
|
|
||||||
- Redux is not available as a peer dependency in Headlamp plugins
|
- Redux is not available as a peer dependency in Headlamp plugins
|
||||||
- Massive overkill for single AuditData object
|
- Massive overkill for single AuditData object
|
||||||
- Adds significant bundle size (~10-15 KB)
|
- 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
|
### Option 2: Zustand
|
||||||
|
|
||||||
**Pros:**
|
**Pros:**
|
||||||
|
|
||||||
- Lightweight (~1 KB)
|
- Lightweight (~1 KB)
|
||||||
- Simple API similar to `useState`
|
- Simple API similar to `useState`
|
||||||
- No provider boilerplate
|
- No provider boilerplate
|
||||||
|
|
||||||
**Cons:**
|
**Cons:**
|
||||||
|
|
||||||
- External peer dependency (not available in plugin runtime)
|
- External peer dependency (not available in plugin runtime)
|
||||||
- Still adds bundle size
|
- Still adds bundle size
|
||||||
- Unnecessary for read-only state
|
- 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)
|
### Option 3: Component Props (Prop Drilling)
|
||||||
|
|
||||||
**Pros:**
|
**Pros:**
|
||||||
|
|
||||||
- No dependencies
|
- No dependencies
|
||||||
- Explicit data flow
|
- Explicit data flow
|
||||||
- TypeScript tracks prop types
|
- TypeScript tracks prop types
|
||||||
|
|
||||||
**Cons:**
|
**Cons:**
|
||||||
|
|
||||||
- Prop drilling through 5+ component layers (index.tsx → route → view → subcomponent)
|
- Prop drilling through 5+ component layers (index.tsx → route → view → subcomponent)
|
||||||
- Duplicate fetches if not carefully managed
|
- Duplicate fetches if not carefully managed
|
||||||
- Refactoring nightmare if component tree changes
|
- 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
|
### Option 4: Global Variable / Module State
|
||||||
|
|
||||||
**Pros:**
|
**Pros:**
|
||||||
|
|
||||||
- Simple to implement
|
- Simple to implement
|
||||||
- No React dependencies
|
- No React dependencies
|
||||||
|
|
||||||
**Cons:**
|
**Cons:**
|
||||||
|
|
||||||
- No reactivity (components don't re-render on data change)
|
- No reactivity (components don't re-render on data change)
|
||||||
- No built-in loading/error handling
|
- No built-in loading/error handling
|
||||||
- Breaks React's declarative model
|
- Breaks React's declarative model
|
||||||
@@ -126,6 +138,7 @@ Use **React Context API** (built-in, no dependencies) for shared state managemen
|
|||||||
## Implementation Details
|
## Implementation Details
|
||||||
|
|
||||||
**Context Definition:**
|
**Context Definition:**
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
interface PolarisDataContextValue {
|
interface PolarisDataContextValue {
|
||||||
data: AuditData | null;
|
data: AuditData | null;
|
||||||
@@ -138,6 +151,7 @@ const PolarisDataContext = React.createContext<PolarisDataContextValue | undefin
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Provider Implementation:**
|
**Provider Implementation:**
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
export function PolarisDataProvider({ children }: { children: React.ReactNode }) {
|
export function PolarisDataProvider({ children }: { children: React.ReactNode }) {
|
||||||
const [data, setData] = useState<AuditData | null>(null);
|
const [data, setData] = useState<AuditData | null>(null);
|
||||||
@@ -163,6 +177,7 @@ export function PolarisDataProvider({ children }: { children: React.ReactNode })
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Consumer Hook:**
|
**Consumer Hook:**
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
export function usePolarisDataContext() {
|
export function usePolarisDataContext() {
|
||||||
const context = useContext(PolarisDataContext);
|
const context = useContext(PolarisDataContext);
|
||||||
@@ -176,6 +191,7 @@ export function usePolarisDataContext() {
|
|||||||
## Validation Criteria
|
## Validation Criteria
|
||||||
|
|
||||||
**Success Metrics:**
|
**Success Metrics:**
|
||||||
|
|
||||||
- ✅ All views share single fetch (verified via network tab - one request per refresh)
|
- ✅ All views share single fetch (verified via network tab - one request per refresh)
|
||||||
- ✅ No duplicate API calls (verified via Kubernetes audit logs)
|
- ✅ No duplicate API calls (verified via Kubernetes audit logs)
|
||||||
- ✅ Auto-refresh works correctly (5-30 minute intervals)
|
- ✅ Auto-refresh works correctly (5-30 minute intervals)
|
||||||
@@ -184,6 +200,7 @@ export function usePolarisDataContext() {
|
|||||||
- ✅ Bundle size remains <50 KB (currently ~27 KB)
|
- ✅ Bundle size remains <50 KB (currently ~27 KB)
|
||||||
|
|
||||||
**Tested Scenarios:**
|
**Tested Scenarios:**
|
||||||
|
|
||||||
- ✅ Initial load with loading spinner
|
- ✅ Initial load with loading spinner
|
||||||
- ✅ Error handling (403, 404, network errors)
|
- ✅ Error handling (403, 404, network errors)
|
||||||
- ✅ Manual refresh via button
|
- ✅ Manual refresh via button
|
||||||
@@ -200,6 +217,6 @@ export function usePolarisDataContext() {
|
|||||||
|
|
||||||
## Revision History
|
## Revision History
|
||||||
|
|
||||||
| Date | Author | Change |
|
| Date | Author | Change |
|
||||||
|------|--------|--------|
|
| ---------- | ----------- | ---------------- |
|
||||||
| 2026-02-12 | Plugin Team | Initial decision |
|
| 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?
|
What becomes easier or more difficult to do because of this change?
|
||||||
|
|
||||||
### Positive
|
### Positive
|
||||||
|
|
||||||
- ...
|
- ...
|
||||||
|
|
||||||
### Negative
|
### Negative
|
||||||
|
|
||||||
- ...
|
- ...
|
||||||
|
|
||||||
### Neutral
|
### Neutral
|
||||||
|
|
||||||
- ...
|
- ...
|
||||||
|
|
||||||
## Alternatives Considered
|
## Alternatives Considered
|
||||||
|
|
||||||
### Option 1: Name
|
### Option 1: Name
|
||||||
|
|
||||||
**Pros**: ...
|
**Pros**: ...
|
||||||
**Cons**: ...
|
**Cons**: ...
|
||||||
**Decision**: Not chosen because...
|
**Decision**: Not chosen because...
|
||||||
@@ -63,8 +67,8 @@ What becomes easier or more difficult to do because of this change?
|
|||||||
|
|
||||||
## ADR Index
|
## 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 |
|
| [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.
|
**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
|
```typescript
|
||||||
interface AuditData {
|
interface AuditData {
|
||||||
PolarisOutputVersion: string; // "1.0"
|
PolarisOutputVersion: string; // "1.0"
|
||||||
AuditTime: string; // ISO 8601 timestamp
|
AuditTime: string; // ISO 8601 timestamp
|
||||||
SourceType: string; // "Cluster"
|
SourceType: string; // "Cluster"
|
||||||
SourceName: string; // Cluster identifier
|
SourceName: string; // Cluster identifier
|
||||||
DisplayName: string; // Human-readable name
|
DisplayName: string; // Human-readable name
|
||||||
ClusterInfo: {
|
ClusterInfo: {
|
||||||
Version: string; // K8s version
|
Version: string; // K8s version
|
||||||
Nodes: number;
|
Nodes: number;
|
||||||
Pods: number;
|
Pods: number;
|
||||||
Namespaces: number;
|
Namespaces: number;
|
||||||
Controllers: number;
|
Controllers: number;
|
||||||
};
|
};
|
||||||
Results: Result[]; // Array of resource audit results
|
Results: Result[]; // Array of resource audit results
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Result {
|
interface Result {
|
||||||
Name: string; // Resource name
|
Name: string; // Resource name
|
||||||
Namespace: string; // Kubernetes namespace
|
Namespace: string; // Kubernetes namespace
|
||||||
Kind: string; // "Deployment", "StatefulSet", etc.
|
Kind: string; // "Deployment", "StatefulSet", etc.
|
||||||
Results: ResultSet; // Resource-level checks
|
Results: ResultSet; // Resource-level checks
|
||||||
PodResult?: {
|
PodResult?: {
|
||||||
Name: string;
|
Name: string;
|
||||||
Results: ResultSet; // Pod-level checks
|
Results: ResultSet; // Pod-level checks
|
||||||
ContainerResults: {
|
ContainerResults: {
|
||||||
Name: string;
|
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>;
|
type ResultSet = Record<string, ResultMessage>;
|
||||||
|
|
||||||
interface ResultMessage {
|
interface ResultMessage {
|
||||||
ID: string; // Check ID (e.g., "cpuLimitsMissing")
|
ID: string; // Check ID (e.g., "cpuLimitsMissing")
|
||||||
Message: string; // Human-readable message
|
Message: string; // Human-readable message
|
||||||
Details: string[]; // Additional context
|
Details: string[]; // Additional context
|
||||||
Success: boolean; // true = passed, false = failed
|
Success: boolean; // true = passed, false = failed
|
||||||
Severity: "ignore" | "warning" | "danger";
|
Severity: 'ignore' | 'warning' | 'danger';
|
||||||
Category: string; // "Security", "Efficiency", etc.
|
Category: string; // "Security", "Efficiency", etc.
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -259,11 +259,11 @@ interface ResultMessage {
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
interface ResultCounts {
|
interface ResultCounts {
|
||||||
total: number; // Total checks performed
|
total: number; // Total checks performed
|
||||||
pass: number; // Checks that passed (Success: true)
|
pass: number; // Checks that passed (Success: true)
|
||||||
warning: number; // Failed checks with Severity: "warning"
|
warning: number; // Failed checks with Severity: "warning"
|
||||||
danger: number; // Failed checks with Severity: "danger"
|
danger: number; // Failed checks with Severity: "danger"
|
||||||
skipped: number; // Failed checks with Severity: "ignore"
|
skipped: number; // Failed checks with Severity: "ignore"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -361,21 +361,25 @@ function getNamespaces(data: AuditData): string[] {
|
|||||||
## Caching Strategy
|
## Caching Strategy
|
||||||
|
|
||||||
**Current Implementation:**
|
**Current Implementation:**
|
||||||
|
|
||||||
- Data fetched once and stored in React Context
|
- Data fetched once and stored in React Context
|
||||||
- Shared across all plugin views (no duplicate fetches)
|
- Shared across all plugin views (no duplicate fetches)
|
||||||
- Cached until manual refresh or auto-refresh interval
|
- Cached until manual refresh or auto-refresh interval
|
||||||
|
|
||||||
**Cache Invalidation:**
|
**Cache Invalidation:**
|
||||||
|
|
||||||
- Manual refresh button click
|
- Manual refresh button click
|
||||||
- Auto-refresh interval elapses
|
- Auto-refresh interval elapses
|
||||||
- Settings change (dashboard URL)
|
- Settings change (dashboard URL)
|
||||||
|
|
||||||
**No Persistence:**
|
**No Persistence:**
|
||||||
|
|
||||||
- Data NOT persisted to localStorage
|
- Data NOT persisted to localStorage
|
||||||
- Each browser session fetches fresh data
|
- Each browser session fetches fresh data
|
||||||
- No offline mode
|
- No offline mode
|
||||||
|
|
||||||
**Future Enhancement:**
|
**Future Enhancement:**
|
||||||
|
|
||||||
- IndexedDB caching for offline access
|
- IndexedDB caching for offline access
|
||||||
- Incremental updates (fetch only changed namespaces)
|
- Incremental updates (fetch only changed namespaces)
|
||||||
- Service Worker for background refresh
|
- 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
|
**Decision:** Use Kubernetes service proxy, not direct ClusterIP access
|
||||||
|
|
||||||
**Context:**
|
**Context:**
|
||||||
|
|
||||||
- Plugin needs to access Polaris dashboard API
|
- Plugin needs to access Polaris dashboard API
|
||||||
- Two options: Direct ClusterIP access or Kubernetes service proxy
|
- Two options: Direct ClusterIP access or Kubernetes service proxy
|
||||||
-Headlamp already has K8s API credentials
|
-Headlamp already has K8s API credentials
|
||||||
|
|
||||||
**Decision:**
|
**Decision:**
|
||||||
Use service proxy path: `/api/v1/namespaces/polaris/services/polaris-dashboard:80/proxy/results.json`
|
Use service proxy path: `/api/v1/namespaces/polaris/services/polaris-dashboard:80/proxy/results.json`
|
||||||
|
|
||||||
**Rationale:**
|
**Rationale:**
|
||||||
|
|
||||||
- Headlamp already has K8s API credentials (service account or user token)
|
- Headlamp already has K8s API credentials (service account or user token)
|
||||||
- Service proxy leverages existing RBAC (no new credentials needed)
|
- Service proxy leverages existing RBAC (no new credentials needed)
|
||||||
- Works with Headlamp's token auth and OIDC
|
- 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)
|
- Consistent with Headlamp's architecture (all API calls go through K8s API)
|
||||||
|
|
||||||
**Trade-offs:**
|
**Trade-offs:**
|
||||||
|
|
||||||
- ✅ **Pros:** Simpler RBAC, works with user tokens, no new credentials
|
- ✅ **Pros:** Simpler RBAC, works with user tokens, no new credentials
|
||||||
- ❌ **Cons:** Longer URL path, requires `services/proxy` permission
|
- ❌ **Cons:** Longer URL path, requires `services/proxy` permission
|
||||||
|
|
||||||
**Alternatives Considered:**
|
**Alternatives Considered:**
|
||||||
|
|
||||||
- Direct ClusterIP access → Rejected (requires new credentials, network policies)
|
- Direct ClusterIP access → Rejected (requires new credentials, network policies)
|
||||||
- External Polaris URL → Supported as optional feature (custom URL setting)
|
- 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
|
**Decision:** Use React Context for state management
|
||||||
|
|
||||||
**Context:**
|
**Context:**
|
||||||
|
|
||||||
- Plugin needs to share Polaris audit data across multiple views
|
- Plugin needs to share Polaris audit data across multiple views
|
||||||
- Options: React Context, Redux, Zustand, or component props
|
- 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`
|
Use React Context with `PolarisDataProvider`
|
||||||
|
|
||||||
**Rationale:**
|
**Rationale:**
|
||||||
|
|
||||||
1. **Simple state:** Single AuditData object, no complex mutations
|
1. **Simple state:** Single AuditData object, no complex mutations
|
||||||
2. **Read-only:** No transactions, undo/redo, or optimistic updates
|
2. **Read-only:** No transactions, undo/redo, or optimistic updates
|
||||||
3. **Headlamp constraints:** Cannot add external dependencies (Redux not bundled)
|
3. **Headlamp constraints:** Cannot add external dependencies (Redux not bundled)
|
||||||
4. **Performance:** Data changes infrequently (5-30 minute refresh interval)
|
4. **Performance:** Data changes infrequently (5-30 minute refresh interval)
|
||||||
|
|
||||||
**Trade-offs:**
|
**Trade-offs:**
|
||||||
|
|
||||||
- ✅ **Pros:** No dependencies, simple API, built-in React feature
|
- ✅ **Pros:** No dependencies, simple API, built-in React feature
|
||||||
- ❌ **Cons:** All consumers re-render on data change (acceptable for infrequent updates)
|
- ❌ **Cons:** All consumers re-render on data change (acceptable for infrequent updates)
|
||||||
|
|
||||||
**Alternatives Considered:**
|
**Alternatives Considered:**
|
||||||
|
|
||||||
- Redux → Rejected (not available in plugin environment)
|
- Redux → Rejected (not available in plugin environment)
|
||||||
- Zustand → Rejected (requires external dependency)
|
- Zustand → Rejected (requires external dependency)
|
||||||
- Component props → Rejected (prop drilling, duplicate fetches)
|
- 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
|
**Decision:** Use drawer for namespace detail, not dedicated route
|
||||||
|
|
||||||
**Context:**
|
**Context:**
|
||||||
|
|
||||||
- Namespaces list needs drill-down to per-namespace detail
|
- Namespaces list needs drill-down to per-namespace detail
|
||||||
- Options: Dedicated route (`/polaris/ns/:namespace`) or drawer overlay
|
- 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`)
|
Use drawer with URL hash (`/polaris/namespaces#kube-system`)
|
||||||
|
|
||||||
**Rationale:**
|
**Rationale:**
|
||||||
|
|
||||||
- **Better UX:** Drawer overlays table, preserves scroll position and context
|
- **Better UX:** Drawer overlays table, preserves scroll position and context
|
||||||
- **URL hash:** Preserves navigation state, supports browser back/forward
|
- **URL hash:** Preserves navigation state, supports browser back/forward
|
||||||
- **Keyboard shortcuts:** Escape key to close drawer
|
- **Keyboard shortcuts:** Escape key to close drawer
|
||||||
- **Sidebar limitation:** Headlamp sidebar doesn't support 3-level nesting
|
- **Sidebar limitation:** Headlamp sidebar doesn't support 3-level nesting
|
||||||
|
|
||||||
**Trade-offs:**
|
**Trade-offs:**
|
||||||
|
|
||||||
- ✅ **Pros:** Better UX, preserves context, keyboard navigation
|
- ✅ **Pros:** Better UX, preserves context, keyboard navigation
|
||||||
- ❌ **Cons:** Hash-based routing (not "true" route), drawer accessibility considerations
|
- ❌ **Cons:** Hash-based routing (not "true" route), drawer accessibility considerations
|
||||||
|
|
||||||
**Alternatives Considered:**
|
**Alternatives Considered:**
|
||||||
|
|
||||||
- Dedicated route → Rejected (loses table context, requires back navigation)
|
- Dedicated route → Rejected (loses table context, requires back navigation)
|
||||||
- Modal → Rejected (less natural for drill-down, no URL state)
|
- 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`
|
**Decision:** Never import from `@mui/material` or `@mui/icons-material`
|
||||||
|
|
||||||
**Context:**
|
**Context:**
|
||||||
|
|
||||||
- Plugin needs UI components (buttons, icons, etc.)
|
- Plugin needs UI components (buttons, icons, etc.)
|
||||||
- Headlamp uses MUI but doesn't expose full library to plugins
|
- 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
|
Use only Headlamp CommonComponents or HTML elements with inline styles
|
||||||
|
|
||||||
**Rationale:**
|
**Rationale:**
|
||||||
|
|
||||||
- Importing MUI causes `createSvgIcon undefined` runtime error
|
- Importing MUI causes `createSvgIcon undefined` runtime error
|
||||||
- Headlamp plugin environment provides limited MUI exports
|
- Headlamp plugin environment provides limited MUI exports
|
||||||
- CommonComponents cover 90% of use cases
|
- CommonComponents cover 90% of use cases
|
||||||
|
|
||||||
**Implementation:**
|
**Implementation:**
|
||||||
|
|
||||||
- Use `StatusLabel`, `SectionBox`, `SimpleTable` from CommonComponents
|
- Use `StatusLabel`, `SectionBox`, `SimpleTable` from CommonComponents
|
||||||
- Use standard HTML elements (`<button>`, `<div>`) with inline styles
|
- Use standard HTML elements (`<button>`, `<div>`) with inline styles
|
||||||
- Use theme-aware CSS variables (`--mui-palette-background-paper`)
|
- Use theme-aware CSS variables (`--mui-palette-background-paper`)
|
||||||
|
|
||||||
**Trade-offs:**
|
**Trade-offs:**
|
||||||
|
|
||||||
- ✅ **Pros:** No runtime errors, smaller bundle, consistent with Headlamp
|
- ✅ **Pros:** No runtime errors, smaller bundle, consistent with Headlamp
|
||||||
- ❌ **Cons:** Limited component variety, inline styles verbose
|
- ❌ **Cons:** Limited component variety, inline styles verbose
|
||||||
|
|
||||||
**Alternatives Considered:**
|
**Alternatives Considered:**
|
||||||
|
|
||||||
- Bundle full MUI → Rejected (huge bundle size, version conflicts)
|
- Bundle full MUI → Rejected (huge bundle size, version conflicts)
|
||||||
- Use Headlamp's MUI exports → Rejected (incomplete, undocumented)
|
- 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)
|
**Decision:** Sidebar has "Polaris" → "Overview" and "Namespaces" (2 levels max)
|
||||||
|
|
||||||
**Context:**
|
**Context:**
|
||||||
|
|
||||||
- Plugin needs hierarchical navigation
|
- Plugin needs hierarchical navigation
|
||||||
- Headlamp sidebar supports limited nesting depth
|
- 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)
|
Use 2-level sidebar: `Polaris` (parent) → `Overview`, `Namespaces` (children)
|
||||||
|
|
||||||
**Rationale:**
|
**Rationale:**
|
||||||
|
|
||||||
- Headlamp sidebar `Collapse` component only supports 2 levels
|
- Headlamp sidebar `Collapse` component only supports 2 levels
|
||||||
- Deeper nesting (Polaris → Namespaces → <each namespace>) doesn't work
|
- Deeper nesting (Polaris → Namespaces → <each namespace>) doesn't work
|
||||||
- Sidebar collapse is route-based, not click-to-toggle
|
- Sidebar collapse is route-based, not click-to-toggle
|
||||||
|
|
||||||
**Workaround:**
|
**Workaround:**
|
||||||
|
|
||||||
- Namespace navigation via table (NamespacesListView)
|
- Namespace navigation via table (NamespacesListView)
|
||||||
- Clickable namespace buttons open drawer (not new route)
|
- Clickable namespace buttons open drawer (not new route)
|
||||||
|
|
||||||
**Trade-offs:**
|
**Trade-offs:**
|
||||||
|
|
||||||
- ✅ **Pros:** Works within Headlamp constraints
|
- ✅ **Pros:** Works within Headlamp constraints
|
||||||
- ❌ **Cons:** Can't have dynamic per-namespace sidebar entries
|
- ❌ **Cons:** Can't have dynamic per-namespace sidebar entries
|
||||||
|
|
||||||
**Alternatives Considered:**
|
**Alternatives Considered:**
|
||||||
|
|
||||||
- Dynamic sidebar with namespace entries → Rejected (Headlamp limitation)
|
- Dynamic sidebar with namespace entries → Rejected (Headlamp limitation)
|
||||||
- Flat sidebar (no nesting) → Rejected (poor UX for plugin with multiple views)
|
- 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
|
**Decision:** Enable all TypeScript strict checks
|
||||||
|
|
||||||
**Configuration:**
|
**Configuration:**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
@@ -155,12 +178,14 @@ Use 2-level sidebar: `Polaris` (parent) → `Overview`, `Namespaces` (children)
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Rationale:**
|
**Rationale:**
|
||||||
|
|
||||||
- Catch errors at compile time (not runtime)
|
- Catch errors at compile time (not runtime)
|
||||||
- Better IDE support and autocomplete
|
- Better IDE support and autocomplete
|
||||||
- Enforces type safety (no `any`, no implicit unknowns)
|
- Enforces type safety (no `any`, no implicit unknowns)
|
||||||
- Easier refactoring (type errors surface immediately)
|
- Easier refactoring (type errors surface immediately)
|
||||||
|
|
||||||
**Trade-offs:**
|
**Trade-offs:**
|
||||||
|
|
||||||
- ✅ **Pros:** Fewer runtime errors, better maintainability, self-documenting code
|
- ✅ **Pros:** Fewer runtime errors, better maintainability, self-documenting code
|
||||||
- ❌ **Cons:** More verbose code, steeper learning curve
|
- ❌ **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)
|
**Decision:** Default refresh interval is 5 minutes (configurable 1-30 min)
|
||||||
|
|
||||||
**Context:**
|
**Context:**
|
||||||
|
|
||||||
- Plugin needs to refresh Polaris data periodically
|
- Plugin needs to refresh Polaris data periodically
|
||||||
- Polaris audits typically run every 10-30 minutes
|
- 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)
|
Default to 5 minutes, allow user to configure (1 / 5 / 10 / 30 minutes)
|
||||||
|
|
||||||
**Rationale:**
|
**Rationale:**
|
||||||
|
|
||||||
- Balance between data freshness and API load
|
- Balance between data freshness and API load
|
||||||
- Polaris audits don't change frequently (10-30 min intervals)
|
- Polaris audits don't change frequently (10-30 min intervals)
|
||||||
- 5 minutes provides reasonably fresh data without excessive API calls
|
- 5 minutes provides reasonably fresh data without excessive API calls
|
||||||
|
|
||||||
**Trade-offs:**
|
**Trade-offs:**
|
||||||
|
|
||||||
- ✅ **Pros:** Reasonable default, user-configurable, low API load
|
- ✅ **Pros:** Reasonable default, user-configurable, low API load
|
||||||
- ❌ **Cons:** Not real-time (acceptable for audit data)
|
- ❌ **Cons:** Not real-time (acceptable for audit data)
|
||||||
|
|
||||||
**Alternatives Considered:**
|
**Alternatives Considered:**
|
||||||
|
|
||||||
- WebSocket/SSE for real-time → Rejected (Polaris dashboard doesn't support)
|
- WebSocket/SSE for real-time → Rejected (Polaris dashboard doesn't support)
|
||||||
- 1 minute default → Rejected (unnecessary API calls, audit data changes slowly)
|
- 1 minute default → Rejected (unnecessary API calls, audit data changes slowly)
|
||||||
- 30 minute default → Rejected (too stale for interactive dashboard)
|
- 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)
|
**Decision:** Plugin is read-only (no write operations)
|
||||||
|
|
||||||
**Context:**
|
**Context:**
|
||||||
|
|
||||||
- Plugin could potentially modify Polaris configuration or add exemptions
|
- Plugin could potentially modify Polaris configuration or add exemptions
|
||||||
- Write operations require additional RBAC permissions (PATCH, CREATE)
|
- 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)
|
Plugin only performs GET requests (read-only)
|
||||||
|
|
||||||
**Rationale:**
|
**Rationale:**
|
||||||
|
|
||||||
- **Security:** Minimal RBAC footprint (`get` on `services/proxy` only)
|
- **Security:** Minimal RBAC footprint (`get` on `services/proxy` only)
|
||||||
- **Simplicity:** No mutation logic, error handling for writes, or rollback
|
- **Simplicity:** No mutation logic, error handling for writes, or rollback
|
||||||
- **Polaris design:** Exemptions managed via annotations (outside plugin scope)
|
- **Polaris design:** Exemptions managed via annotations (outside plugin scope)
|
||||||
- **Future:** Can add writes later if user demand exists
|
- **Future:** Can add writes later if user demand exists
|
||||||
|
|
||||||
**Trade-offs:**
|
**Trade-offs:**
|
||||||
|
|
||||||
- ✅ **Pros:** Minimal permissions, simpler code, fewer failure modes
|
- ✅ **Pros:** Minimal permissions, simpler code, fewer failure modes
|
||||||
- ❌ **Cons:** Cannot add exemptions via UI (must edit annotations manually)
|
- ❌ **Cons:** Cannot add exemptions via UI (must edit annotations manually)
|
||||||
|
|
||||||
**Future Enhancement:**
|
**Future Enhancement:**
|
||||||
|
|
||||||
- Add PATCH permission for workload annotations
|
- Add PATCH permission for workload annotations
|
||||||
- Implement `ExemptionManager` component (UI exists, not integrated)
|
- 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.
|
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:**
|
**Key Characteristics:**
|
||||||
|
|
||||||
- **Read-only:** No write operations to cluster or Polaris
|
- **Read-only:** No write operations to cluster or Polaris
|
||||||
- **Service proxy based:** Uses K8s API server proxy to reach Polaris
|
- **Service proxy based:** Uses K8s API server proxy to reach Polaris
|
||||||
- **React Context for state:** Shared data fetch across components
|
- **React Context for state:** Shared data fetch across components
|
||||||
@@ -91,6 +92,7 @@ The Headlamp Polaris Plugin is a **read-only dashboard** that surfaces Fairwinds
|
|||||||
### Plugin Entry Point
|
### Plugin Entry Point
|
||||||
|
|
||||||
**`src/index.tsx`**
|
**`src/index.tsx`**
|
||||||
|
|
||||||
- Registers sidebar entries (Polaris → Overview, Namespaces)
|
- Registers sidebar entries (Polaris → Overview, Namespaces)
|
||||||
- Registers routes (`/polaris`, `/polaris/namespaces`)
|
- Registers routes (`/polaris`, `/polaris/namespaces`)
|
||||||
- Registers app bar action (score badge)
|
- Registers app bar action (score badge)
|
||||||
@@ -100,22 +102,26 @@ The Headlamp Polaris Plugin is a **read-only dashboard** that surfaces Fairwinds
|
|||||||
### Data Layer
|
### Data Layer
|
||||||
|
|
||||||
**`src/api/PolarisDataContext.tsx`**
|
**`src/api/PolarisDataContext.tsx`**
|
||||||
|
|
||||||
- React Context Provider for shared data
|
- React Context Provider for shared data
|
||||||
- Fetches AuditData from Polaris dashboard
|
- Fetches AuditData from Polaris dashboard
|
||||||
- Handles auto-refresh based on user settings
|
- Handles auto-refresh based on user settings
|
||||||
- Provides `{ data, loading, error, refresh }` to consumers
|
- Provides `{ data, loading, error, refresh }` to consumers
|
||||||
|
|
||||||
**`src/api/polaris.ts`**
|
**`src/api/polaris.ts`**
|
||||||
|
|
||||||
- TypeScript types for AuditData schema
|
- TypeScript types for AuditData schema
|
||||||
- Utility functions: `countResults()`, `computeScore()`
|
- Utility functions: `countResults()`, `computeScore()`
|
||||||
- Settings management: `getRefreshInterval()`, `setRefreshInterval()`
|
- Settings management: `getRefreshInterval()`, `setRefreshInterval()`
|
||||||
- Constants: `DASHBOARD_URL_DEFAULT`, `INTERVAL_OPTIONS`
|
- Constants: `DASHBOARD_URL_DEFAULT`, `INTERVAL_OPTIONS`
|
||||||
|
|
||||||
**`src/api/checkMapping.ts`**
|
**`src/api/checkMapping.ts`**
|
||||||
|
|
||||||
- Maps Polaris check IDs to human-readable names
|
- Maps Polaris check IDs to human-readable names
|
||||||
- Used for display in UI (e.g., "hostIPCSet" → "Host IPC")
|
- Used for display in UI (e.g., "hostIPCSet" → "Host IPC")
|
||||||
|
|
||||||
**`src/api/topIssues.ts`**
|
**`src/api/topIssues.ts`**
|
||||||
|
|
||||||
- Aggregates failing checks across cluster
|
- Aggregates failing checks across cluster
|
||||||
- Groups by check ID and severity
|
- Groups by check ID and severity
|
||||||
- Used for top issues dashboard
|
- Used for top issues dashboard
|
||||||
@@ -123,6 +129,7 @@ The Headlamp Polaris Plugin is a **read-only dashboard** that surfaces Fairwinds
|
|||||||
### View Components
|
### View Components
|
||||||
|
|
||||||
**`src/components/DashboardView.tsx`**
|
**`src/components/DashboardView.tsx`**
|
||||||
|
|
||||||
- **Route:** `/polaris`
|
- **Route:** `/polaris`
|
||||||
- **Purpose:** Cluster-wide overview
|
- **Purpose:** Cluster-wide overview
|
||||||
- **Features:**
|
- **Features:**
|
||||||
@@ -133,6 +140,7 @@ The Headlamp Polaris Plugin is a **read-only dashboard** that surfaces Fairwinds
|
|||||||
- **Data:** Uses `usePolarisDataContext()`
|
- **Data:** Uses `usePolarisDataContext()`
|
||||||
|
|
||||||
**`src/components/NamespacesListView.tsx`**
|
**`src/components/NamespacesListView.tsx`**
|
||||||
|
|
||||||
- **Route:** `/polaris/namespaces`
|
- **Route:** `/polaris/namespaces`
|
||||||
- **Purpose:** List all namespaces with scores
|
- **Purpose:** List all namespaces with scores
|
||||||
- **Features:**
|
- **Features:**
|
||||||
@@ -142,6 +150,7 @@ The Headlamp Polaris Plugin is a **read-only dashboard** that surfaces Fairwinds
|
|||||||
- **Data:** Uses `usePolarisDataContext()`, aggregates by namespace
|
- **Data:** Uses `usePolarisDataContext()`, aggregates by namespace
|
||||||
|
|
||||||
**`src/components/NamespaceDetailView.tsx`**
|
**`src/components/NamespaceDetailView.tsx`**
|
||||||
|
|
||||||
- **Route:** Drawer on `/polaris/namespaces#<namespace>`
|
- **Route:** Drawer on `/polaris/namespaces#<namespace>`
|
||||||
- **Purpose:** Namespace-level drill-down
|
- **Purpose:** Namespace-level drill-down
|
||||||
- **Features:**
|
- **Features:**
|
||||||
@@ -154,6 +163,7 @@ The Headlamp Polaris Plugin is a **read-only dashboard** that surfaces Fairwinds
|
|||||||
### UI Components
|
### UI Components
|
||||||
|
|
||||||
**`src/components/AppBarScoreBadge.tsx`**
|
**`src/components/AppBarScoreBadge.tsx`**
|
||||||
|
|
||||||
- **Location:** Headlamp app bar (top-right)
|
- **Location:** Headlamp app bar (top-right)
|
||||||
- **Purpose:** Quick cluster score visibility
|
- **Purpose:** Quick cluster score visibility
|
||||||
- **Features:**
|
- **Features:**
|
||||||
@@ -163,6 +173,7 @@ The Headlamp Polaris Plugin is a **read-only dashboard** that surfaces Fairwinds
|
|||||||
- **Data:** Uses `usePolarisDataContext()`
|
- **Data:** Uses `usePolarisDataContext()`
|
||||||
|
|
||||||
**`src/components/PolarisSettings.tsx`**
|
**`src/components/PolarisSettings.tsx`**
|
||||||
|
|
||||||
- **Location:** Settings → Plugins → Polaris
|
- **Location:** Settings → Plugins → Polaris
|
||||||
- **Purpose:** Plugin configuration
|
- **Purpose:** Plugin configuration
|
||||||
- **Features:**
|
- **Features:**
|
||||||
@@ -172,6 +183,7 @@ The Headlamp Polaris Plugin is a **read-only dashboard** that surfaces Fairwinds
|
|||||||
- **Data:** localStorage for persistence
|
- **Data:** localStorage for persistence
|
||||||
|
|
||||||
**`src/components/InlineAuditSection.tsx`**
|
**`src/components/InlineAuditSection.tsx`**
|
||||||
|
|
||||||
- **Location:** Resource detail pages (Deployment, StatefulSet, etc.)
|
- **Location:** Resource detail pages (Deployment, StatefulSet, etc.)
|
||||||
- **Purpose:** Show Polaris audit inline
|
- **Purpose:** Show Polaris audit inline
|
||||||
- **Features:**
|
- **Features:**
|
||||||
@@ -181,6 +193,7 @@ The Headlamp Polaris Plugin is a **read-only dashboard** that surfaces Fairwinds
|
|||||||
- **Data:** Uses `usePolarisDataContext()`, filters by resource
|
- **Data:** Uses `usePolarisDataContext()`, filters by resource
|
||||||
|
|
||||||
**`src/components/ExemptionManager.tsx`**
|
**`src/components/ExemptionManager.tsx`**
|
||||||
|
|
||||||
- **Location:** (Planned feature, UI exists but not fully integrated)
|
- **Location:** (Planned feature, UI exists but not fully integrated)
|
||||||
- **Purpose:** Manage Polaris exemptions via annotations
|
- **Purpose:** Manage Polaris exemptions via annotations
|
||||||
- **Features:**
|
- **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
|
**Decision:** Use React Context instead of Redux/Zustand
|
||||||
|
|
||||||
**Rationale:**
|
**Rationale:**
|
||||||
|
|
||||||
1. **Simple state:** Single AuditData object shared across views
|
1. **Simple state:** Single AuditData object shared across views
|
||||||
2. **Read-only:** No complex mutations or transactions
|
2. **Read-only:** No complex mutations or transactions
|
||||||
3. **Headlamp constraints:** Plugin cannot add dependencies (Redux not bundled)
|
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
|
```typescript
|
||||||
interface PolarisDataContextValue {
|
interface PolarisDataContextValue {
|
||||||
data: AuditData | null; // Audit results or null if loading/error
|
data: AuditData | null; // Audit results or null if loading/error
|
||||||
loading: boolean; // True during initial fetch
|
loading: boolean; // True during initial fetch
|
||||||
error: string | null; // Error message if fetch failed
|
error: string | null; // Error message if fetch failed
|
||||||
refresh: () => void; // Manual refresh function
|
refresh: () => void; // Manual refresh function
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -221,6 +235,7 @@ interface PolarisDataContextValue {
|
|||||||
### localStorage Usage
|
### localStorage Usage
|
||||||
|
|
||||||
Settings persisted in localStorage:
|
Settings persisted in localStorage:
|
||||||
|
|
||||||
- **`polaris-plugin-refresh-interval`**: Number (seconds), default 300
|
- **`polaris-plugin-refresh-interval`**: Number (seconds), default 300
|
||||||
- **`polaris-plugin-dashboard-url`**: String, default service proxy path
|
- **`polaris-plugin-dashboard-url`**: String, default service proxy path
|
||||||
|
|
||||||
@@ -236,28 +251,30 @@ No sensitive data stored in localStorage.
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// Sidebar navigation
|
// Sidebar navigation
|
||||||
registerSidebarEntry({ parent, name, label, url, icon })
|
registerSidebarEntry({ parent, name, label, url, icon });
|
||||||
|
|
||||||
// Routes
|
// Routes
|
||||||
registerRoute({ path, sidebar, name, exact, component })
|
registerRoute({ path, sidebar, name, exact, component });
|
||||||
|
|
||||||
// App bar actions
|
// App bar actions
|
||||||
registerAppBarAction(component)
|
registerAppBarAction(component);
|
||||||
|
|
||||||
// Plugin settings
|
// Plugin settings
|
||||||
registerPluginSettings(name, component, displaySaveButton)
|
registerPluginSettings(name, component, displaySaveButton);
|
||||||
|
|
||||||
// Resource detail sections
|
// Resource detail sections
|
||||||
registerDetailsViewSection(component)
|
registerDetailsViewSection(component);
|
||||||
```
|
```
|
||||||
|
|
||||||
**Key Changes in v0.13.0:**
|
**Key Changes in v0.13.0:**
|
||||||
|
|
||||||
- `registerDetailsViewSection` now takes 1 argument (component), not 2 (name, component)
|
- `registerDetailsViewSection` now takes 1 argument (component), not 2 (name, component)
|
||||||
- `registerAppBarAction` now takes 1 argument (component), not 2 (name, component)
|
- `registerAppBarAction` now takes 1 argument (component), not 2 (name, component)
|
||||||
|
|
||||||
### Headlamp CommonComponents
|
### Headlamp CommonComponents
|
||||||
|
|
||||||
**Used Components:**
|
**Used Components:**
|
||||||
|
|
||||||
- `SectionBox` - Card-like container with title
|
- `SectionBox` - Card-like container with title
|
||||||
- `SectionHeader` - Page header with title
|
- `SectionHeader` - Page header with title
|
||||||
- `StatusLabel` - Color-coded status badges
|
- `StatusLabel` - Color-coded status badges
|
||||||
@@ -267,16 +284,19 @@ registerDetailsViewSection(component)
|
|||||||
- `Loader` - Loading spinner
|
- `Loader` - Loading spinner
|
||||||
|
|
||||||
**Router:**
|
**Router:**
|
||||||
|
|
||||||
- `Router.createRouteURL()` - Generate plugin route URLs
|
- `Router.createRouteURL()` - Generate plugin route URLs
|
||||||
- React Router's `useHistory()`, `useParams()`, `useLocation()`
|
- React Router's `useHistory()`, `useParams()`, `useLocation()`
|
||||||
|
|
||||||
### Kubernetes API (via ApiProxy)
|
### Kubernetes API (via ApiProxy)
|
||||||
|
|
||||||
**Used for:**
|
**Used for:**
|
||||||
|
|
||||||
- Fetching Polaris results: `ApiProxy.request(dashboardUrl + 'results.json')`
|
- Fetching Polaris results: `ApiProxy.request(dashboardUrl + 'results.json')`
|
||||||
- No direct K8s API calls (all data from Polaris dashboard)
|
- No direct K8s API calls (all data from Polaris dashboard)
|
||||||
|
|
||||||
**RBAC Required:**
|
**RBAC Required:**
|
||||||
|
|
||||||
- `get` on `services/proxy` for `polaris-dashboard` in `polaris` namespace
|
- `get` on `services/proxy` for `polaris-dashboard` in `polaris` namespace
|
||||||
|
|
||||||
## Performance Considerations
|
## Performance Considerations
|
||||||
|
|||||||
+11
-18
@@ -31,7 +31,6 @@ helm repo update
|
|||||||
# headlamp-values.yaml
|
# headlamp-values.yaml
|
||||||
config:
|
config:
|
||||||
pluginsDir: /headlamp/plugins
|
pluginsDir: /headlamp/plugins
|
||||||
watchPlugins: false # CRITICAL for v0.39.0+
|
|
||||||
|
|
||||||
pluginsManager:
|
pluginsManager:
|
||||||
enabled: true
|
enabled: true
|
||||||
@@ -63,9 +62,8 @@ image:
|
|||||||
pullPolicy: IfNotPresent
|
pullPolicy: IfNotPresent
|
||||||
|
|
||||||
config:
|
config:
|
||||||
baseURL: ""
|
baseURL: ''
|
||||||
pluginsDir: /headlamp/plugins
|
pluginsDir: /headlamp/plugins
|
||||||
watchPlugins: false # MUST be false for plugin manager
|
|
||||||
|
|
||||||
pluginsManager:
|
pluginsManager:
|
||||||
enabled: true
|
enabled: true
|
||||||
@@ -81,7 +79,7 @@ ingress:
|
|||||||
className: nginx
|
className: nginx
|
||||||
annotations:
|
annotations:
|
||||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||||
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
|
nginx.ingress.kubernetes.io/force-ssl-redirect: 'true'
|
||||||
hosts:
|
hosts:
|
||||||
- host: headlamp.example.com
|
- host: headlamp.example.com
|
||||||
paths:
|
paths:
|
||||||
@@ -117,16 +115,16 @@ affinity:
|
|||||||
# OIDC Authentication (optional)
|
# OIDC Authentication (optional)
|
||||||
env:
|
env:
|
||||||
- name: HEADLAMP_CONFIG_OIDC_CLIENT_ID
|
- name: HEADLAMP_CONFIG_OIDC_CLIENT_ID
|
||||||
value: "headlamp"
|
value: 'headlamp'
|
||||||
- name: HEADLAMP_CONFIG_OIDC_CLIENT_SECRET
|
- name: HEADLAMP_CONFIG_OIDC_CLIENT_SECRET
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: headlamp-oidc
|
name: headlamp-oidc
|
||||||
key: client-secret
|
key: client-secret
|
||||||
- name: HEADLAMP_CONFIG_OIDC_ISSUER_URL
|
- 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
|
- name: HEADLAMP_CONFIG_OIDC_SCOPES
|
||||||
value: "openid,profile,email,groups"
|
value: 'openid,profile,email,groups'
|
||||||
```
|
```
|
||||||
|
|
||||||
Deploy:
|
Deploy:
|
||||||
@@ -147,7 +145,6 @@ Alternative to Plugin Manager: use an init container to download the plugin.
|
|||||||
# headlamp-values.yaml
|
# headlamp-values.yaml
|
||||||
config:
|
config:
|
||||||
pluginsDir: /headlamp/plugins
|
pluginsDir: /headlamp/plugins
|
||||||
watchPlugins: false
|
|
||||||
|
|
||||||
initContainers:
|
initContainers:
|
||||||
- name: install-polaris-plugin
|
- name: install-polaris-plugin
|
||||||
@@ -230,7 +227,7 @@ spec:
|
|||||||
chart:
|
chart:
|
||||||
spec:
|
spec:
|
||||||
chart: headlamp
|
chart: headlamp
|
||||||
version: 0.26.x # Use semver range
|
version: 0.26.x # Use semver range
|
||||||
sourceRef:
|
sourceRef:
|
||||||
kind: HelmRepository
|
kind: HelmRepository
|
||||||
name: headlamp
|
name: headlamp
|
||||||
@@ -252,7 +249,6 @@ spec:
|
|||||||
|
|
||||||
config:
|
config:
|
||||||
pluginsDir: /headlamp/plugins
|
pluginsDir: /headlamp/plugins
|
||||||
watchPlugins: false
|
|
||||||
|
|
||||||
pluginsManager:
|
pluginsManager:
|
||||||
enabled: true
|
enabled: true
|
||||||
@@ -388,15 +384,12 @@ kubectl -n kube-system rollout status deployment/headlamp
|
|||||||
# Check Headlamp values
|
# Check Headlamp values
|
||||||
helm get values headlamp -n kube-system
|
helm get values headlamp -n kube-system
|
||||||
|
|
||||||
# Verify watchPlugins is false:
|
# Verify plugin files exist
|
||||||
# config:
|
kubectl -n kube-system exec deployment/headlamp -c headlamp -- \
|
||||||
# watchPlugins: false
|
ls -la /headlamp/plugins/headlamp-polaris-plugin/
|
||||||
|
|
||||||
# If incorrect, update values and upgrade:
|
# If missing, reinstall plugin via UI or check init container logs
|
||||||
helm upgrade headlamp headlamp/headlamp \
|
kubectl -n kube-system logs deployment/headlamp -c install-polaris-plugin
|
||||||
--namespace kube-system \
|
|
||||||
--values headlamp-values.yaml \
|
|
||||||
--set config.watchPlugins=false
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Helm Release Stuck
|
### Helm Release Stuck
|
||||||
|
|||||||
@@ -29,10 +29,10 @@ metadata:
|
|||||||
app.kubernetes.io/name: headlamp-polaris-plugin
|
app.kubernetes.io/name: headlamp-polaris-plugin
|
||||||
app.kubernetes.io/component: rbac
|
app.kubernetes.io/component: rbac
|
||||||
rules:
|
rules:
|
||||||
- apiGroups: [""]
|
- apiGroups: ['']
|
||||||
resources: ["services/proxy"]
|
resources: ['services/proxy']
|
||||||
resourceNames: ["polaris-dashboard"]
|
resourceNames: ['polaris-dashboard']
|
||||||
verbs: ["get"]
|
verbs: ['get']
|
||||||
|
|
||||||
---
|
---
|
||||||
# RoleBinding: Grant Headlamp service account access
|
# RoleBinding: Grant Headlamp service account access
|
||||||
@@ -145,11 +145,11 @@ spec:
|
|||||||
- name: headlamp
|
- name: headlamp
|
||||||
image: ghcr.io/headlamp-k8s/headlamp:v0.39.0
|
image: ghcr.io/headlamp-k8s/headlamp:v0.39.0
|
||||||
args:
|
args:
|
||||||
- "-in-cluster"
|
- '-in-cluster'
|
||||||
- "-plugins-dir=/headlamp/plugins"
|
- '-plugins-dir=/headlamp/plugins'
|
||||||
env:
|
env:
|
||||||
- name: HEADLAMP_CONFIG_WATCH_PLUGINS
|
- name: HEADLAMP_CONFIG_WATCH_PLUGINS
|
||||||
value: "false" # CRITICAL: Must be false for plugin manager
|
value: 'false' # CRITICAL: Must be false for plugin manager
|
||||||
ports:
|
ports:
|
||||||
- name: http
|
- name: http
|
||||||
containerPort: 4466
|
containerPort: 4466
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ kubectl -n kube-system get svc headlamp
|
|||||||
### Deployment
|
### Deployment
|
||||||
|
|
||||||
- [ ] Plugin installed via Plugin Manager or sidecar init container
|
- [ ] Plugin installed via Plugin Manager or sidecar init container
|
||||||
- [ ] `config.watchPlugins: false` set in Headlamp configuration
|
|
||||||
- [ ] RBAC Role and RoleBinding applied
|
- [ ] RBAC Role and RoleBinding applied
|
||||||
- [ ] NetworkPolicies configured (if using strict network policies)
|
- [ ] NetworkPolicies configured (if using strict network policies)
|
||||||
- [ ] Headlamp pods running with 2+ replicas (high availability)
|
- [ ] Headlamp pods running with 2+ replicas (high availability)
|
||||||
@@ -121,7 +120,7 @@ metadata:
|
|||||||
namespace: polaris
|
namespace: polaris
|
||||||
subjects:
|
subjects:
|
||||||
- kind: Group
|
- kind: Group
|
||||||
name: system:authenticated # All authenticated users
|
name: system:authenticated # All authenticated users
|
||||||
apiGroup: rbac.authorization.k8s.io
|
apiGroup: rbac.authorization.k8s.io
|
||||||
roleRef:
|
roleRef:
|
||||||
kind: Role
|
kind: Role
|
||||||
@@ -134,7 +133,7 @@ For fine-grained control, bind specific users or groups:
|
|||||||
```yaml
|
```yaml
|
||||||
subjects:
|
subjects:
|
||||||
- kind: Group
|
- kind: Group
|
||||||
name: sre-team # Only SRE team
|
name: sre-team # Only SRE team
|
||||||
apiGroup: rbac.authorization.k8s.io
|
apiGroup: rbac.authorization.k8s.io
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -185,12 +184,12 @@ Kubernetes audit logs record every service proxy request:
|
|||||||
apiVersion: audit.k8s.io/v1
|
apiVersion: audit.k8s.io/v1
|
||||||
kind: Policy
|
kind: Policy
|
||||||
rules:
|
rules:
|
||||||
- level: Metadata # Log metadata only (not full request/response)
|
- level: Metadata # Log metadata only (not full request/response)
|
||||||
verbs: ["get"]
|
verbs: ['get']
|
||||||
resources:
|
resources:
|
||||||
- group: ""
|
- group: ''
|
||||||
resources: ["services/proxy"]
|
resources: ['services/proxy']
|
||||||
namespaces: ["polaris"]
|
namespaces: ['polaris']
|
||||||
```
|
```
|
||||||
|
|
||||||
### Data Sensitivity
|
### Data Sensitivity
|
||||||
@@ -354,8 +353,8 @@ spec:
|
|||||||
labels:
|
labels:
|
||||||
severity: warning
|
severity: warning
|
||||||
annotations:
|
annotations:
|
||||||
summary: "Headlamp pod not ready"
|
summary: 'Headlamp pod not ready'
|
||||||
description: "Pod {{ $labels.pod }} in namespace {{ $labels.namespace }} has been not ready for 5 minutes."
|
description: 'Pod {{ $labels.pod }} in namespace {{ $labels.namespace }} has been not ready for 5 minutes.'
|
||||||
```
|
```
|
||||||
|
|
||||||
## Performance Tuning
|
## Performance Tuning
|
||||||
@@ -414,12 +413,14 @@ Adjust based on cluster size and user count.
|
|||||||
If Headlamp or plugin becomes unavailable:
|
If Headlamp or plugin becomes unavailable:
|
||||||
|
|
||||||
1. **Verify Polaris is running:**
|
1. **Verify Polaris is running:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl -n polaris get pods
|
kubectl -n polaris get pods
|
||||||
kubectl -n polaris get svc polaris-dashboard
|
kubectl -n polaris get svc polaris-dashboard
|
||||||
```
|
```
|
||||||
|
|
||||||
2. **Redeploy Headlamp:**
|
2. **Redeploy Headlamp:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
helm upgrade --install headlamp headlamp/headlamp \
|
helm upgrade --install headlamp headlamp/headlamp \
|
||||||
--namespace kube-system \
|
--namespace kube-system \
|
||||||
@@ -427,11 +428,13 @@ If Headlamp or plugin becomes unavailable:
|
|||||||
```
|
```
|
||||||
|
|
||||||
3. **Reapply RBAC:**
|
3. **Reapply RBAC:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl apply -f polaris-plugin-rbac.yaml
|
kubectl apply -f polaris-plugin-rbac.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
4. **Verify plugin files:**
|
4. **Verify plugin files:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl -n kube-system exec deployment/headlamp -- \
|
kubectl -n kube-system exec deployment/headlamp -- \
|
||||||
ls /headlamp/plugins/headlamp-polaris-plugin/
|
ls /headlamp/plugins/headlamp-polaris-plugin/
|
||||||
@@ -442,30 +445,6 @@ If Headlamp or plugin becomes unavailable:
|
|||||||
|
|
||||||
## Known Issues
|
## 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
|
### Skipped Count Limitation
|
||||||
|
|
||||||
**Symptom:** "Skipped" count in UI is lower than native Polaris dashboard
|
**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:
|
The Headlamp Polaris Plugin uses a multi-layered testing approach:
|
||||||
|
|
||||||
| Test Type | Framework | Purpose | Location |
|
| Test Type | Framework | Purpose | Location |
|
||||||
|-----------|-----------|---------|----------|
|
| ----------------- | ---------- | ------------------------------------------------------- | ----------------------- |
|
||||||
| **Unit Tests** | Vitest | Test individual functions and components in isolation | `src/**/*.test.ts(x)` |
|
| **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` |
|
| **E2E Tests** | Playwright | Test complete user flows against live Headlamp instance | `e2e/*.spec.ts` |
|
||||||
| **Type Checking** | TypeScript | Ensure type safety across codebase | `tsc --noEmit` |
|
| **Type Checking** | TypeScript | Ensure type safety across codebase | `tsc --noEmit` |
|
||||||
| **Linting** | ESLint | Enforce code style and catch common errors | `eslint src/` |
|
| **Linting** | ESLint | Enforce code style and catch common errors | `eslint src/` |
|
||||||
| **Formatting** | Prettier | Maintain consistent code formatting | `prettier --check src/` |
|
| **Formatting** | Prettier | Maintain consistent code formatting | `prettier --check src/` |
|
||||||
|
|
||||||
### Test Philosophy
|
### Test Philosophy
|
||||||
|
|
||||||
@@ -178,7 +178,9 @@ describe('DashboardView', () => {
|
|||||||
const mockData = {
|
const mockData = {
|
||||||
DisplayName: 'test-cluster',
|
DisplayName: 'test-cluster',
|
||||||
ClusterInfo: { Version: '1.27', Nodes: 3, Pods: 100, Namespaces: 10, Controllers: 50 },
|
ClusterInfo: { Version: '1.27', Nodes: 3, Pods: 100, Namespaces: 10, Controllers: 50 },
|
||||||
Results: [/* ... */],
|
Results: [
|
||||||
|
/* ... */
|
||||||
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
vi.spyOn(PolarisDataContext, 'usePolarisDataContext').mockReturnValue({
|
vi.spyOn(PolarisDataContext, 'usePolarisDataContext').mockReturnValue({
|
||||||
@@ -197,6 +199,7 @@ describe('DashboardView', () => {
|
|||||||
### What to Unit Test
|
### What to Unit Test
|
||||||
|
|
||||||
✅ **Do test:**
|
✅ **Do test:**
|
||||||
|
|
||||||
- Pure functions (score calculation, filtering, data transformation)
|
- Pure functions (score calculation, filtering, data transformation)
|
||||||
- Data parsing and validation
|
- Data parsing and validation
|
||||||
- Utility functions
|
- Utility functions
|
||||||
@@ -204,6 +207,7 @@ describe('DashboardView', () => {
|
|||||||
- Edge cases (empty arrays, null values, invalid input)
|
- Edge cases (empty arrays, null values, invalid input)
|
||||||
|
|
||||||
❌ **Don't test:**
|
❌ **Don't test:**
|
||||||
|
|
||||||
- Third-party libraries (Headlamp, React)
|
- Third-party libraries (Headlamp, React)
|
||||||
- Simple prop passing
|
- Simple prop passing
|
||||||
- Trivial getters/setters
|
- Trivial getters/setters
|
||||||
@@ -242,6 +246,7 @@ npx playwright show-trace test-results/<test-name>/trace.zip
|
|||||||
**1. Headlamp Instance**
|
**1. Headlamp Instance**
|
||||||
|
|
||||||
E2E tests require a running Headlamp instance with:
|
E2E tests require a running Headlamp instance with:
|
||||||
|
|
||||||
- Polaris plugin installed (version being tested)
|
- Polaris plugin installed (version being tested)
|
||||||
- Polaris dashboard deployed and accessible
|
- Polaris dashboard deployed and accessible
|
||||||
- RBAC configured (service proxy permissions)
|
- RBAC configured (service proxy permissions)
|
||||||
@@ -296,32 +301,32 @@ AUTHENTIK_PASSWORD=secret
|
|||||||
|
|
||||||
**File:** `e2e/polaris.spec.ts`
|
**File:** `e2e/polaris.spec.ts`
|
||||||
|
|
||||||
| Test | Description | Validates |
|
| Test | Description | Validates |
|
||||||
|------|-------------|-----------|
|
| --------------------------------------------- | ------------------------------- | ----------------------------- |
|
||||||
| `sidebar contains Polaris entry` | Polaris appears in sidebar | Plugin registration |
|
| `sidebar contains Polaris entry` | Polaris appears in sidebar | Plugin registration |
|
||||||
| `overview page renders cluster score` | Score displayed on overview | Data fetching, rendering |
|
| `overview page renders cluster score` | Score displayed on overview | Data fetching, rendering |
|
||||||
| `namespaces page renders table` | Namespace table loads | Data parsing, table 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 opens` | Clicking namespace shows drawer | Navigation, drawer UI |
|
||||||
| `namespace detail drawer closes with Escape` | Keyboard shortcut works | Keyboard navigation |
|
| `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 |
|
| `namespace detail drawer opens from URL hash` | Direct URL navigation | URL routing, deep linking |
|
||||||
|
|
||||||
**File:** `e2e/settings.spec.ts`
|
**File:** `e2e/settings.spec.ts`
|
||||||
|
|
||||||
| Test | Description | Validates |
|
| Test | Description | Validates |
|
||||||
|------|-------------|-----------|
|
| ------------------------------------ | ------------------- | --------------------------- |
|
||||||
| `plugin settings page is accessible` | Settings page loads | Settings registration |
|
| `plugin settings page is accessible` | Settings page loads | Settings registration |
|
||||||
| `refresh interval can be changed` | Dropdown works | User preference persistence |
|
| `refresh interval can be changed` | Dropdown works | User preference persistence |
|
||||||
| `dashboard URL can be customized` | Input field works | URL configuration |
|
| `dashboard URL can be customized` | Input field works | URL configuration |
|
||||||
| `connection test button works` | Test functionality | API connectivity validation |
|
| `connection test button works` | Test functionality | API connectivity validation |
|
||||||
|
|
||||||
**File:** `e2e/appbar.spec.ts`
|
**File:** `e2e/appbar.spec.ts`
|
||||||
|
|
||||||
| Test | Description | Validates |
|
| Test | Description | Validates |
|
||||||
|------|-------------|-----------|
|
| -------------------------------------- | ------------------------------- | ------------------- |
|
||||||
| `app bar displays Polaris badge` | Badge visible in header | App bar integration |
|
| `app bar displays Polaris badge` | Badge visible in header | App bar integration |
|
||||||
| `badge shows cluster score` | Score matches dashboard | Data consistency |
|
| `badge shows cluster score` | Score matches dashboard | Data consistency |
|
||||||
| `clicking badge navigates to overview` | Navigation works | App bar action |
|
| `clicking badge navigates to overview` | Navigation works | App bar action |
|
||||||
| `badge color reflects score` | Red/yellow/green based on score | Visual feedback |
|
| `badge color reflects score` | Red/yellow/green based on score | Visual feedback |
|
||||||
|
|
||||||
### Writing E2E Tests
|
### Writing E2E Tests
|
||||||
|
|
||||||
@@ -385,6 +390,7 @@ npx playwright test --debug
|
|||||||
```
|
```
|
||||||
|
|
||||||
This opens Playwright Inspector where you can:
|
This opens Playwright Inspector where you can:
|
||||||
|
|
||||||
- Step through each test action
|
- Step through each test action
|
||||||
- Inspect page state
|
- Inspect page state
|
||||||
- Edit test selectors live
|
- Edit test selectors live
|
||||||
@@ -455,12 +461,12 @@ jobs:
|
|||||||
|
|
||||||
Configure in GitHub repository settings (Settings → Secrets and variables → Actions):
|
Configure in GitHub repository settings (Settings → Secrets and variables → Actions):
|
||||||
|
|
||||||
| Secret | Required | Description |
|
| Secret | Required | Description |
|
||||||
|--------|----------|-------------|
|
| -------------------- | -------- | ------------------------------------------------------- |
|
||||||
| `HEADLAMP_URL` | Optional | Headlamp instance URL (defaults to configured instance) |
|
| `HEADLAMP_URL` | Optional | Headlamp instance URL (defaults to configured instance) |
|
||||||
| `AUTHENTIK_USERNAME` | OIDC | Authentik username/email for CI user |
|
| `AUTHENTIK_USERNAME` | OIDC | Authentik username/email for CI user |
|
||||||
| `AUTHENTIK_PASSWORD` | OIDC | Authentik password |
|
| `AUTHENTIK_PASSWORD` | OIDC | Authentik password |
|
||||||
| `HEADLAMP_TOKEN` | Token | Kubernetes service account token (alternative to OIDC) |
|
| `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.
|
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
|
### Current Coverage
|
||||||
|
|
||||||
| Category | Coverage | Notes |
|
| Category | Coverage | Notes |
|
||||||
|----------|----------|-------|
|
| -------------------- | -------- | ------------------------------ |
|
||||||
| **API Functions** | 95% | Core utilities fully tested |
|
| **API Functions** | 95% | Core utilities fully tested |
|
||||||
| **React Components** | 60% | Focus on critical render paths |
|
| **React Components** | 60% | Focus on critical render paths |
|
||||||
| **E2E User Flows** | 80% | Main features covered |
|
| **E2E User Flows** | 80% | Main features covered |
|
||||||
|
|
||||||
### Coverage Goals
|
### Coverage Goals
|
||||||
|
|
||||||
@@ -507,18 +513,22 @@ open coverage/index.html
|
|||||||
### Unit Testing
|
### Unit Testing
|
||||||
|
|
||||||
1. **Test behavior, not implementation**
|
1. **Test behavior, not implementation**
|
||||||
|
|
||||||
- ✅ `expect(computeScore({ total: 100, pass: 75 })).toBe(75)`
|
- ✅ `expect(computeScore({ total: 100, pass: 75 })).toBe(75)`
|
||||||
- ❌ `expect(mockInternalFunction).toHaveBeenCalled()`
|
- ❌ `expect(mockInternalFunction).toHaveBeenCalled()`
|
||||||
|
|
||||||
2. **Use descriptive test names**
|
2. **Use descriptive test names**
|
||||||
|
|
||||||
- ✅ `it('returns 0 when total checks is zero')`
|
- ✅ `it('returns 0 when total checks is zero')`
|
||||||
- ❌ `it('works')`
|
- ❌ `it('works')`
|
||||||
|
|
||||||
3. **One assertion per test (when possible)**
|
3. **One assertion per test (when possible)**
|
||||||
|
|
||||||
- Makes failures easier to debug
|
- Makes failures easier to debug
|
||||||
- Exceptions: testing multiple properties of same object
|
- Exceptions: testing multiple properties of same object
|
||||||
|
|
||||||
4. **Mock external dependencies**
|
4. **Mock external dependencies**
|
||||||
|
|
||||||
- Mock API calls, context providers, external libraries
|
- Mock API calls, context providers, external libraries
|
||||||
- Don't mock the code you're testing
|
- Don't mock the code you're testing
|
||||||
|
|
||||||
@@ -529,27 +539,33 @@ open coverage/index.html
|
|||||||
### E2E Testing
|
### E2E Testing
|
||||||
|
|
||||||
1. **Use semantic selectors**
|
1. **Use semantic selectors**
|
||||||
|
|
||||||
- ✅ `page.getByRole('button', { name: 'Close' })`
|
- ✅ `page.getByRole('button', { name: 'Close' })`
|
||||||
- ✅ `page.getByText('Polaris — Overview')`
|
- ✅ `page.getByText('Polaris — Overview')`
|
||||||
- ❌ `page.locator('.MuiButton-root')`
|
- ❌ `page.locator('.MuiButton-root')`
|
||||||
|
|
||||||
2. **Wait for visibility, not arbitrary timeouts**
|
2. **Wait for visibility, not arbitrary timeouts**
|
||||||
|
|
||||||
- ✅ `await expect(element).toBeVisible()`
|
- ✅ `await expect(element).toBeVisible()`
|
||||||
- ❌ `await page.waitForTimeout(5000)`
|
- ❌ `await page.waitForTimeout(5000)`
|
||||||
|
|
||||||
3. **Keep tests independent**
|
3. **Keep tests independent**
|
||||||
|
|
||||||
- Each test should work in isolation
|
- Each test should work in isolation
|
||||||
- Don't rely on previous tests' state
|
- Don't rely on previous tests' state
|
||||||
|
|
||||||
4. **Test complete user flows**
|
4. **Test complete user flows**
|
||||||
|
|
||||||
- Navigate → Interact → Verify outcome
|
- Navigate → Interact → Verify outcome
|
||||||
- Don't just test page loads
|
- Don't just test page loads
|
||||||
|
|
||||||
5. **Clean up after tests**
|
5. **Clean up after tests**
|
||||||
|
|
||||||
- Close drawers/modals
|
- Close drawers/modals
|
||||||
- Reset state if needed
|
- Reset state if needed
|
||||||
|
|
||||||
6. **Use storage state for auth**
|
6. **Use storage state for auth**
|
||||||
|
|
||||||
- Reuse authenticated session across tests
|
- Reuse authenticated session across tests
|
||||||
- Faster than logging in for every test
|
- Faster than logging in for every test
|
||||||
|
|
||||||
@@ -560,15 +576,18 @@ open coverage/index.html
|
|||||||
### General
|
### General
|
||||||
|
|
||||||
1. **Run tests before committing**
|
1. **Run tests before committing**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run build && npm run lint && npm test
|
npm run build && npm run lint && npm test
|
||||||
```
|
```
|
||||||
|
|
||||||
2. **Fix failing tests immediately**
|
2. **Fix failing tests immediately**
|
||||||
|
|
||||||
- Don't commit failing tests
|
- Don't commit failing tests
|
||||||
- Don't skip tests to "fix later"
|
- Don't skip tests to "fix later"
|
||||||
|
|
||||||
3. **Update tests when changing code**
|
3. **Update tests when changing code**
|
||||||
|
|
||||||
- Tests are documentation
|
- Tests are documentation
|
||||||
- Keep them in sync with implementation
|
- Keep them in sync with implementation
|
||||||
|
|
||||||
@@ -604,7 +623,7 @@ Check mocks are returning expected structure:
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
vi.spyOn(PolarisDataContext, 'usePolarisDataContext').mockReturnValue({
|
vi.spyOn(PolarisDataContext, 'usePolarisDataContext').mockReturnValue({
|
||||||
data: mockData, // Ensure mockData has all required fields
|
data: mockData, // Ensure mockData has all required fields
|
||||||
loading: false,
|
loading: false,
|
||||||
error: null,
|
error: null,
|
||||||
refresh: vi.fn(),
|
refresh: vi.fn(),
|
||||||
@@ -624,6 +643,7 @@ npm run e2e:headed
|
|||||||
```
|
```
|
||||||
|
|
||||||
Common causes:
|
Common causes:
|
||||||
|
|
||||||
- Element hasn't rendered yet (use `toBeVisible()` instead of `toBeDefined()`)
|
- Element hasn't rendered yet (use `toBeVisible()` instead of `toBeDefined()`)
|
||||||
- Wrong selector (use Playwright Inspector to verify)
|
- Wrong selector (use Playwright Inspector to verify)
|
||||||
- Authentication failed (check token/credentials)
|
- Authentication failed (check token/credentials)
|
||||||
|
|||||||
@@ -33,16 +33,19 @@ The plugin is published on [Artifact Hub](https://artifacthub.io/packages/headla
|
|||||||
#### Via Headlamp UI
|
#### Via Headlamp UI
|
||||||
|
|
||||||
1. **Navigate to Plugin Settings:**
|
1. **Navigate to Plugin Settings:**
|
||||||
|
|
||||||
- Open Headlamp in your browser
|
- Open Headlamp in your browser
|
||||||
- Go to **Settings → Plugins**
|
- Go to **Settings → Plugins**
|
||||||
- Click the **Catalog** tab
|
- Click the **Catalog** tab
|
||||||
|
|
||||||
2. **Search and Install:**
|
2. **Search and Install:**
|
||||||
|
|
||||||
- Search for "Polaris"
|
- Search for "Polaris"
|
||||||
- Find "Headlamp Polaris Plugin"
|
- Find "Headlamp Polaris Plugin"
|
||||||
- Click **Install**
|
- Click **Install**
|
||||||
|
|
||||||
3. **Hard Refresh Browser:**
|
3. **Hard Refresh Browser:**
|
||||||
|
|
||||||
- **Mac:** Cmd+Shift+R
|
- **Mac:** Cmd+Shift+R
|
||||||
- **Windows/Linux:** Ctrl+Shift+R
|
- **Windows/Linux:** Ctrl+Shift+R
|
||||||
|
|
||||||
@@ -58,7 +61,6 @@ Add to your Headlamp Helm values:
|
|||||||
# headlamp-values.yaml
|
# headlamp-values.yaml
|
||||||
config:
|
config:
|
||||||
pluginsDir: /headlamp/plugins
|
pluginsDir: /headlamp/plugins
|
||||||
watchPlugins: false # CRITICAL for v0.39.0+
|
|
||||||
|
|
||||||
pluginsManager:
|
pluginsManager:
|
||||||
enabled: true
|
enabled: true
|
||||||
@@ -76,23 +78,6 @@ helm upgrade --install headlamp headlamp/headlamp \
|
|||||||
|
|
||||||
Then install the plugin via Headlamp UI as described above.
|
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
|
### Option 2: Sidecar Container
|
||||||
|
|
||||||
**Best for:** Controlled plugin versions, air-gapped environments, specific version pinning
|
**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
|
# headlamp-values.yaml
|
||||||
config:
|
config:
|
||||||
pluginsDir: /headlamp/plugins
|
pluginsDir: /headlamp/plugins
|
||||||
watchPlugins: false
|
|
||||||
|
|
||||||
initContainers:
|
initContainers:
|
||||||
- name: install-polaris-plugin
|
- name: install-polaris-plugin
|
||||||
@@ -204,7 +188,7 @@ config:
|
|||||||
volumes:
|
volumes:
|
||||||
- name: plugins
|
- name: plugins
|
||||||
hostPath:
|
hostPath:
|
||||||
path: /path/to/plugins # Where you extracted the tarball
|
path: /path/to/plugins # Where you extracted the tarball
|
||||||
type: Directory
|
type: Directory
|
||||||
|
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
@@ -316,6 +300,7 @@ kubectl -n kube-system wait --for=condition=ready pod -l app.kubernetes.io/name=
|
|||||||
### 4. Verify Installation
|
### 4. Verify Installation
|
||||||
|
|
||||||
**UI Verification:**
|
**UI Verification:**
|
||||||
|
|
||||||
1. Navigate to **Settings → Plugins**
|
1. Navigate to **Settings → Plugins**
|
||||||
2. Verify "headlamp-polaris-plugin" is listed
|
2. Verify "headlamp-polaris-plugin" is listed
|
||||||
3. Check version matches installed version
|
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
|
**Symptom:** Plugin listed in Settings → Plugins but no "Polaris" entry in sidebar
|
||||||
|
|
||||||
**Causes:**
|
**Causes:**
|
||||||
1. `watchPlugins: true` (should be `false` for v0.39.0+)
|
|
||||||
2. Browser cache not cleared
|
1. Browser cache not cleared
|
||||||
3. Plugin JavaScript failed to load
|
2. Plugin JavaScript failed to load
|
||||||
|
3. Plugin files not properly installed
|
||||||
|
|
||||||
**Solution:**
|
**Solution:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 1. Check Headlamp config
|
# 1. Verify plugin files exist
|
||||||
kubectl -n kube-system get configmap headlamp -o yaml | grep watchPlugins
|
kubectl -n kube-system exec deployment/headlamp -c headlamp -- \
|
||||||
|
ls -la /headlamp/plugins/headlamp-polaris-plugin/
|
||||||
|
|
||||||
# If "true" or missing, fix it:
|
# Expected: dist/, package.json present
|
||||||
kubectl -n kube-system edit configmap headlamp
|
|
||||||
# Set: watchPlugins: "false"
|
|
||||||
|
|
||||||
# 2. Restart Headlamp
|
# 2. Check Headlamp logs for plugin errors
|
||||||
kubectl -n kube-system rollout restart deployment/headlamp
|
kubectl -n kube-system logs deployment/headlamp | grep -i polaris
|
||||||
|
|
||||||
# 3. Hard refresh browser (Cmd+Shift+R or Ctrl+Shift+R)
|
# 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
|
**Symptom:** Error loading Polaris data, 404 in browser console
|
||||||
|
|
||||||
**Causes:**
|
**Causes:**
|
||||||
|
|
||||||
1. Polaris not deployed
|
1. Polaris not deployed
|
||||||
2. Polaris service name incorrect
|
2. Polaris service name incorrect
|
||||||
3. Polaris namespace incorrect
|
3. Polaris namespace incorrect
|
||||||
|
|||||||
@@ -4,12 +4,12 @@ Before installing the Headlamp Polaris Plugin, ensure your environment meets the
|
|||||||
|
|
||||||
## Required Components
|
## Required Components
|
||||||
|
|
||||||
| Requirement | Minimum Version | Recommended Version |
|
| Requirement | Minimum Version | Recommended Version |
|
||||||
| -------------------------------- | ------------------ | ------------------- |
|
| ------------------------------- | ------------------ | --------------------------------- |
|
||||||
| **Kubernetes** | v1.24+ | v1.28+ |
|
| **Kubernetes** | v1.24+ | v1.28+ |
|
||||||
| **Headlamp** | v0.26+ | v0.39+ |
|
| **Headlamp** | v0.26+ | v0.39+ |
|
||||||
| **Polaris** (dashboard enabled) | Any recent release | Latest stable |
|
| **Polaris** (dashboard enabled) | Any recent release | Latest stable |
|
||||||
| **Browser** | Modern (ES2020+) | Latest Chrome/Firefox/Safari/Edge |
|
| **Browser** | Modern (ES2020+) | Latest Chrome/Firefox/Safari/Edge |
|
||||||
|
|
||||||
## Polaris Requirements
|
## Polaris Requirements
|
||||||
|
|
||||||
@@ -91,7 +91,6 @@ helm repo update
|
|||||||
helm install headlamp headlamp/headlamp \
|
helm install headlamp headlamp/headlamp \
|
||||||
--namespace kube-system \
|
--namespace kube-system \
|
||||||
--set config.pluginsDir="/headlamp/plugins" \
|
--set config.pluginsDir="/headlamp/plugins" \
|
||||||
--set config.watchPlugins=false \
|
|
||||||
--set pluginsManager.enabled=true
|
--set pluginsManager.enabled=true
|
||||||
|
|
||||||
# Wait for pod to be ready
|
# Wait for pod to be ready
|
||||||
@@ -133,6 +132,7 @@ Headlamp Pod → Kubernetes API Server → Polaris Dashboard Service
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Required network paths:**
|
**Required network paths:**
|
||||||
|
|
||||||
- Headlamp pod → Kubernetes API server (443)
|
- Headlamp pod → Kubernetes API server (443)
|
||||||
- Kubernetes API server → Polaris dashboard service (80)
|
- Kubernetes API server → Polaris dashboard service (80)
|
||||||
|
|
||||||
@@ -161,12 +161,12 @@ The plugin uses modern JavaScript features and requires:
|
|||||||
|
|
||||||
### Tested Browsers
|
### Tested Browsers
|
||||||
|
|
||||||
| Browser | Minimum Version |
|
| Browser | Minimum Version |
|
||||||
| ---------------- | --------------- |
|
| --------------- | --------------- |
|
||||||
| Chrome/Chromium | 80+ |
|
| Chrome/Chromium | 80+ |
|
||||||
| Firefox | 75+ |
|
| Firefox | 75+ |
|
||||||
| Safari | 13.1+ |
|
| Safari | 13.1+ |
|
||||||
| Edge | 80+ |
|
| Edge | 80+ |
|
||||||
|
|
||||||
## Optional Components
|
## Optional Components
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ Don't have these? See [Prerequisites](prerequisites.md) for installation instruc
|
|||||||
cat <<EOF > headlamp-values.yaml
|
cat <<EOF > headlamp-values.yaml
|
||||||
config:
|
config:
|
||||||
pluginsDir: /headlamp/plugins
|
pluginsDir: /headlamp/plugins
|
||||||
watchPlugins: false # CRITICAL for v0.39.0+
|
|
||||||
|
|
||||||
pluginsManager:
|
pluginsManager:
|
||||||
enabled: true
|
enabled: true
|
||||||
@@ -86,14 +85,17 @@ EOF
|
|||||||
### UI Verification
|
### UI Verification
|
||||||
|
|
||||||
1. **Check Plugin is Loaded:**
|
1. **Check Plugin is Loaded:**
|
||||||
|
|
||||||
- Go to **Settings → Plugins**
|
- Go to **Settings → Plugins**
|
||||||
- Verify "headlamp-polaris-plugin" is listed
|
- Verify "headlamp-polaris-plugin" is listed
|
||||||
|
|
||||||
2. **Check Sidebar:**
|
2. **Check Sidebar:**
|
||||||
|
|
||||||
- Look for **Polaris** entry in the left sidebar
|
- Look for **Polaris** entry in the left sidebar
|
||||||
- If not visible, hard refresh: **Cmd+Shift+R** / **Ctrl+Shift+R**
|
- If not visible, hard refresh: **Cmd+Shift+R** / **Ctrl+Shift+R**
|
||||||
|
|
||||||
3. **View Overview Dashboard:**
|
3. **View Overview Dashboard:**
|
||||||
|
|
||||||
- Click **Polaris** in sidebar
|
- Click **Polaris** in sidebar
|
||||||
- Overview page loads with:
|
- Overview page loads with:
|
||||||
- Cluster score gauge
|
- Cluster score gauge
|
||||||
@@ -137,6 +139,7 @@ kubectl get --raw /api/v1/namespaces/polaris/services/polaris-dashboard:80/proxy
|
|||||||
Navigate to **Polaris → Overview**:
|
Navigate to **Polaris → Overview**:
|
||||||
|
|
||||||
- **Cluster Score Gauge:** Overall cluster health (0-100%)
|
- **Cluster Score Gauge:** Overall cluster health (0-100%)
|
||||||
|
|
||||||
- Green (≥80%): Excellent
|
- Green (≥80%): Excellent
|
||||||
- Yellow (50-79%): Needs improvement
|
- Yellow (50-79%): Needs improvement
|
||||||
- Red (<50%): Critical issues
|
- Red (<50%): Critical issues
|
||||||
@@ -181,15 +184,11 @@ Cluster score badge in top navigation:
|
|||||||
### Plugin Not in Sidebar
|
### Plugin Not in Sidebar
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Check Headlamp config
|
# Verify plugin files exist
|
||||||
kubectl -n kube-system get configmap headlamp -o yaml | grep watchPlugins
|
kubectl -n kube-system exec -it deployment/headlamp -c headlamp -- \
|
||||||
|
ls /headlamp/plugins/headlamp-polaris-plugin/
|
||||||
|
|
||||||
# If "true" or missing, set to false:
|
# If missing, reinstall via Headlamp UI or sidecar method
|
||||||
kubectl -n kube-system edit configmap headlamp
|
|
||||||
# Set: watchPlugins: "false"
|
|
||||||
|
|
||||||
# Restart Headlamp
|
|
||||||
kubectl -n kube-system rollout restart deployment/headlamp
|
|
||||||
|
|
||||||
# Hard refresh browser
|
# Hard refresh browser
|
||||||
# Cmd+Shift+R (Mac) or Ctrl+Shift+R (Windows/Linux)
|
# Cmd+Shift+R (Mac) or Ctrl+Shift+R (Windows/Linux)
|
||||||
|
|||||||
@@ -4,17 +4,17 @@ Quick diagnosis guide and common issues for the Headlamp Polaris Plugin.
|
|||||||
|
|
||||||
## Quick Diagnosis
|
## Quick Diagnosis
|
||||||
|
|
||||||
| Symptom | Likely Cause | Quick Fix | Details |
|
| 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) |
|
| **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) |
|
| **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) |
|
| **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) |
|
| **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) |
|
| **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) |
|
| **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) |
|
| **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) |
|
| **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) |
|
| **Custom URL not working** | CORS or incorrect URL format | Test with curl, check CORS headers | [Network Problems](network-problems.md#cors-issues) |
|
||||||
|
|
||||||
## Detailed Guides
|
## Detailed Guides
|
||||||
|
|
||||||
@@ -56,11 +56,6 @@ kubectl -n kube-system logs deployment/headlamp | grep -i polaris
|
|||||||
### Plugin Loading Verification
|
### Plugin Loading Verification
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Check Headlamp config
|
|
||||||
kubectl -n kube-system get configmap headlamp -o yaml | grep watchPlugins
|
|
||||||
|
|
||||||
# Expected: watchPlugins: "false"
|
|
||||||
|
|
||||||
# Verify plugin files exist
|
# Verify plugin files exist
|
||||||
kubectl -n kube-system exec deployment/headlamp -c headlamp -- \
|
kubectl -n kube-system exec deployment/headlamp -c headlamp -- \
|
||||||
ls -la /headlamp/plugins/headlamp-polaris-plugin/
|
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"
|
3. Look for errors containing "polaris" or "plugin"
|
||||||
|
|
||||||
**Common errors:**
|
**Common errors:**
|
||||||
|
|
||||||
- `createSvgIcon is not defined` → MUI import issue (plugin bug)
|
- `createSvgIcon is not defined` → MUI import issue (plugin bug)
|
||||||
- `403 Forbidden` → RBAC permission denied
|
- `403 Forbidden` → RBAC permission denied
|
||||||
- `404 Not Found` → Polaris not installed or wrong URL
|
- `404 Not Found` → Polaris not installed or wrong URL
|
||||||
@@ -132,12 +128,12 @@ kubectl run -it --rm debug --image=curlimages/curl --restart=Never -- \
|
|||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// Open browser console and run:
|
// Open browser console and run:
|
||||||
localStorage.getItem('polaris-plugin-refresh-interval')
|
localStorage.getItem('polaris-plugin-refresh-interval');
|
||||||
localStorage.getItem('polaris-plugin-dashboard-url')
|
localStorage.getItem('polaris-plugin-dashboard-url');
|
||||||
|
|
||||||
// Reset to defaults:
|
// Reset to defaults:
|
||||||
localStorage.removeItem('polaris-plugin-refresh-interval')
|
localStorage.removeItem('polaris-plugin-refresh-interval');
|
||||||
localStorage.removeItem('polaris-plugin-dashboard-url')
|
localStorage.removeItem('polaris-plugin-dashboard-url');
|
||||||
```
|
```
|
||||||
|
|
||||||
## Still Having Issues?
|
## Still Having Issues?
|
||||||
@@ -145,11 +141,13 @@ localStorage.removeItem('polaris-plugin-dashboard-url')
|
|||||||
If the quick diagnosis doesn't resolve your issue:
|
If the quick diagnosis doesn't resolve your issue:
|
||||||
|
|
||||||
1. **Check detailed guides:**
|
1. **Check detailed guides:**
|
||||||
|
|
||||||
- [Common Issues](common-issues.md)
|
- [Common Issues](common-issues.md)
|
||||||
- [RBAC Issues](rbac-issues.md)
|
- [RBAC Issues](rbac-issues.md)
|
||||||
- [Network Problems](network-problems.md)
|
- [Network Problems](network-problems.md)
|
||||||
|
|
||||||
2. **Review documentation:**
|
2. **Review documentation:**
|
||||||
|
|
||||||
- [Installation Guide](../getting-started/installation.md)
|
- [Installation Guide](../getting-started/installation.md)
|
||||||
- [RBAC Permissions](../user-guide/rbac-permissions.md)
|
- [RBAC Permissions](../user-guide/rbac-permissions.md)
|
||||||
- [Deployment Guide](../deployment/kubernetes.md)
|
- [Deployment Guide](../deployment/kubernetes.md)
|
||||||
|
|||||||
@@ -20,34 +20,17 @@ This guide covers common issues encountered when using the Headlamp Polaris Plug
|
|||||||
## Plugin Not Showing in Sidebar
|
## Plugin Not Showing in Sidebar
|
||||||
|
|
||||||
### Symptoms
|
### Symptoms
|
||||||
|
|
||||||
- Plugin appears in Settings → Plugins but sidebar entry is missing
|
- Plugin appears in Settings → Plugins but sidebar entry is missing
|
||||||
- No "Polaris" section in navigation
|
- No "Polaris" section in navigation
|
||||||
- Routes like `/polaris` return 404 or blank page
|
- Routes like `/polaris` return 404 or blank page
|
||||||
|
|
||||||
### Common Causes
|
### Common Causes
|
||||||
|
|
||||||
**1. Headlamp v0.39.0+ Plugin Loading Issue**
|
**1. Plugin Not Installed**
|
||||||
|
|
||||||
**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**
|
|
||||||
|
|
||||||
**Check plugin installation**:
|
**Check plugin installation**:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# View Headlamp pod logs (plugin sidecar)
|
# View Headlamp pod logs (plugin sidecar)
|
||||||
kubectl logs -n kube-system deployment/headlamp -c headlamp-plugin
|
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**:
|
**Verify plugin files exist**:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl exec -n kube-system deployment/headlamp -c headlamp -- ls -la /headlamp/plugins/
|
kubectl exec -n kube-system deployment/headlamp -c headlamp -- ls -la /headlamp/plugins/
|
||||||
# Should show: headlamp-polaris-plugin/
|
# Should show: headlamp-polaris-plugin/
|
||||||
```
|
```
|
||||||
|
|
||||||
**3. JavaScript Cached by Browser**
|
**2. JavaScript Cached by Browser**
|
||||||
|
|
||||||
After upgrading the plugin, old JavaScript may be cached.
|
After upgrading the plugin, old JavaScript may be cached.
|
||||||
|
|
||||||
**Solution**:
|
**Solution**:
|
||||||
|
|
||||||
- Hard refresh: Cmd+Shift+R (macOS) or Ctrl+Shift+R (Linux/Windows)
|
- Hard refresh: Cmd+Shift+R (macOS) or Ctrl+Shift+R (Linux/Windows)
|
||||||
- Clear browser cache for Headlamp domain
|
- Clear browser cache for Headlamp domain
|
||||||
- Open DevTools → Application → Clear Storage → Clear all
|
- Open DevTools → Application → Clear Storage → Clear all
|
||||||
|
|
||||||
**4. Plugin Disabled in Settings**
|
**3. Plugin Disabled in Settings**
|
||||||
|
|
||||||
**Check Settings → Plugins**:
|
**Check Settings → Plugins**:
|
||||||
|
|
||||||
- Navigate to Headlamp Settings → Plugins
|
- Navigate to Headlamp Settings → Plugins
|
||||||
- Ensure "Polaris" plugin is enabled (toggle should be ON)
|
- Ensure "Polaris" plugin is enabled (toggle should be ON)
|
||||||
- If disabled, enable it and refresh the page
|
- If disabled, enable it and refresh the page
|
||||||
@@ -84,11 +70,13 @@ After upgrading the plugin, old JavaScript may be cached.
|
|||||||
## 403 Forbidden Error
|
## 403 Forbidden Error
|
||||||
|
|
||||||
### Symptoms
|
### Symptoms
|
||||||
|
|
||||||
- Error message: "Error loading Polaris audit data: 403 Forbidden"
|
- Error message: "Error loading Polaris audit data: 403 Forbidden"
|
||||||
- Browser console shows 403 response from API proxy
|
- Browser console shows 403 response from API proxy
|
||||||
- Plugin sidebar shows but data fails to load
|
- Plugin sidebar shows but data fails to load
|
||||||
|
|
||||||
### Root Cause
|
### Root Cause
|
||||||
|
|
||||||
User or service account lacks `services/proxy` permission on `polaris-dashboard` service in the `polaris` namespace.
|
User or service account lacks `services/proxy` permission on `polaris-dashboard` service in the `polaris` namespace.
|
||||||
|
|
||||||
### Solution
|
### Solution
|
||||||
@@ -96,11 +84,13 @@ User or service account lacks `services/proxy` permission on `polaris-dashboard`
|
|||||||
**1. Verify RBAC Configuration**
|
**1. Verify RBAC Configuration**
|
||||||
|
|
||||||
Check if Role exists:
|
Check if Role exists:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl get role polaris-proxy-reader -n polaris -o yaml
|
kubectl get role polaris-proxy-reader -n polaris -o yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
Expected output:
|
Expected output:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
apiVersion: rbac.authorization.k8s.io/v1
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
kind: Role
|
kind: Role
|
||||||
@@ -108,20 +98,22 @@ metadata:
|
|||||||
name: polaris-proxy-reader
|
name: polaris-proxy-reader
|
||||||
namespace: polaris
|
namespace: polaris
|
||||||
rules:
|
rules:
|
||||||
- apiGroups: [""]
|
- apiGroups: ['']
|
||||||
resources: ["services/proxy"]
|
resources: ['services/proxy']
|
||||||
resourceNames: ["polaris-dashboard"]
|
resourceNames: ['polaris-dashboard']
|
||||||
verbs: ["get"]
|
verbs: ['get']
|
||||||
```
|
```
|
||||||
|
|
||||||
**2. Verify RoleBinding**
|
**2. Verify RoleBinding**
|
||||||
|
|
||||||
For service account mode:
|
For service account mode:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl get rolebinding headlamp-polaris-proxy -n polaris -o yaml
|
kubectl get rolebinding headlamp-polaris-proxy -n polaris -o yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
Expected subjects:
|
Expected subjects:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
subjects:
|
subjects:
|
||||||
- kind: ServiceAccount
|
- kind: ServiceAccount
|
||||||
@@ -130,6 +122,7 @@ subjects:
|
|||||||
```
|
```
|
||||||
|
|
||||||
For OIDC mode:
|
For OIDC mode:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl get rolebinding -n polaris -o yaml | grep -A 5 polaris-proxy-reader
|
kubectl get rolebinding -n polaris -o yaml | grep -A 5 polaris-proxy-reader
|
||||||
```
|
```
|
||||||
@@ -172,6 +165,7 @@ EOF
|
|||||||
**4. Test RBAC Permissions**
|
**4. Test RBAC Permissions**
|
||||||
|
|
||||||
Service account mode:
|
Service account mode:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Impersonate Headlamp service account
|
# Impersonate Headlamp service account
|
||||||
kubectl auth can-i get services/proxy \
|
kubectl auth can-i get services/proxy \
|
||||||
@@ -182,6 +176,7 @@ kubectl auth can-i get services/proxy \
|
|||||||
```
|
```
|
||||||
|
|
||||||
OIDC mode (test as yourself):
|
OIDC mode (test as yourself):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl auth can-i get services/proxy \
|
kubectl auth can-i get services/proxy \
|
||||||
--resource-name=polaris-dashboard \
|
--resource-name=polaris-dashboard \
|
||||||
@@ -192,6 +187,7 @@ kubectl auth can-i get services/proxy \
|
|||||||
**5. Restart Headlamp**
|
**5. Restart Headlamp**
|
||||||
|
|
||||||
After applying RBAC changes:
|
After applying RBAC changes:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl rollout restart deployment headlamp -n kube-system
|
kubectl rollout restart deployment headlamp -n kube-system
|
||||||
```
|
```
|
||||||
@@ -201,11 +197,13 @@ kubectl rollout restart deployment headlamp -n kube-system
|
|||||||
## 404 Not Found Error
|
## 404 Not Found Error
|
||||||
|
|
||||||
### Symptoms
|
### Symptoms
|
||||||
|
|
||||||
- Error message: "Error loading Polaris audit data: 404 Not Found"
|
- Error message: "Error loading Polaris audit data: 404 Not Found"
|
||||||
- Service proxy request returns 404
|
- Service proxy request returns 404
|
||||||
- Polaris dashboard not reachable
|
- Polaris dashboard not reachable
|
||||||
|
|
||||||
### Root Cause
|
### Root Cause
|
||||||
|
|
||||||
Polaris dashboard service doesn't exist or is in a different namespace.
|
Polaris dashboard service doesn't exist or is in a different namespace.
|
||||||
|
|
||||||
### Solution
|
### Solution
|
||||||
@@ -213,12 +211,14 @@ Polaris dashboard service doesn't exist or is in a different namespace.
|
|||||||
**1. Verify Polaris Installation**
|
**1. Verify Polaris Installation**
|
||||||
|
|
||||||
Check if Polaris is installed:
|
Check if Polaris is installed:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl get pods -n polaris
|
kubectl get pods -n polaris
|
||||||
# Expected: polaris-dashboard-* pod running
|
# Expected: polaris-dashboard-* pod running
|
||||||
```
|
```
|
||||||
|
|
||||||
Check if service exists:
|
Check if service exists:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl get service polaris-dashboard -n polaris
|
kubectl get service polaris-dashboard -n polaris
|
||||||
# Expected: ClusterIP service on port 80
|
# Expected: ClusterIP service on port 80
|
||||||
@@ -227,6 +227,7 @@ kubectl get service polaris-dashboard -n polaris
|
|||||||
**2. Verify Service Name and Port**
|
**2. Verify Service Name and Port**
|
||||||
|
|
||||||
The plugin expects:
|
The plugin expects:
|
||||||
|
|
||||||
- **Namespace**: `polaris`
|
- **Namespace**: `polaris`
|
||||||
- **Service Name**: `polaris-dashboard`
|
- **Service Name**: `polaris-dashboard`
|
||||||
- **Port**: `80` (or named port `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**
|
**4. Check Polaris Dashboard Configuration**
|
||||||
|
|
||||||
Verify Polaris is running with dashboard enabled:
|
Verify Polaris is running with dashboard enabled:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl get deployment polaris-dashboard -n polaris -o yaml | grep -A 5 dashboard
|
kubectl get deployment polaris-dashboard -n polaris -o yaml | grep -A 5 dashboard
|
||||||
```
|
```
|
||||||
|
|
||||||
If `dashboard.enabled: false` in Helm values, enable it:
|
If `dashboard.enabled: false` in Helm values, enable it:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
# values.yaml
|
# values.yaml
|
||||||
dashboard:
|
dashboard:
|
||||||
@@ -260,6 +263,7 @@ dashboard:
|
|||||||
**5. Reinstall Polaris**
|
**5. Reinstall Polaris**
|
||||||
|
|
||||||
If Polaris is missing or misconfigured:
|
If Polaris is missing or misconfigured:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
helm repo add fairwinds-stable https://charts.fairwinds.com/stable
|
helm repo add fairwinds-stable https://charts.fairwinds.com/stable
|
||||||
helm upgrade --install polaris fairwinds-stable/polaris \
|
helm upgrade --install polaris fairwinds-stable/polaris \
|
||||||
@@ -273,21 +277,25 @@ helm upgrade --install polaris fairwinds-stable/polaris \
|
|||||||
## Plugin Settings Page Empty
|
## Plugin Settings Page Empty
|
||||||
|
|
||||||
### Symptoms
|
### Symptoms
|
||||||
|
|
||||||
- Settings → Polaris shows title but no content
|
- Settings → Polaris shows title but no content
|
||||||
- Refresh interval and dashboard URL fields not visible
|
- Refresh interval and dashboard URL fields not visible
|
||||||
|
|
||||||
### Root Cause (Fixed in v0.3.3)
|
### Root Cause (Fixed in v0.3.3)
|
||||||
|
|
||||||
Plugin settings registration name didn't match `package.json` name.
|
Plugin settings registration name didn't match `package.json` name.
|
||||||
|
|
||||||
### Solution
|
### Solution
|
||||||
|
|
||||||
Upgrade to v0.3.3 or later:
|
Upgrade to v0.3.3 or later:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Via Headlamp UI: Settings → Plugins → Update
|
# Via Headlamp UI: Settings → Plugins → Update
|
||||||
# Or redeploy with latest version
|
# Or redeploy with latest version
|
||||||
```
|
```
|
||||||
|
|
||||||
If manually installing, ensure plugin name matches `package.json`:
|
If manually installing, ensure plugin name matches `package.json`:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
registerPluginSettings('headlamp-polaris-plugin', PolarisSettings, true);
|
registerPluginSettings('headlamp-polaris-plugin', PolarisSettings, true);
|
||||||
// NOT 'polaris' — must match package.json name
|
// NOT 'polaris' — must match package.json name
|
||||||
@@ -298,6 +306,7 @@ registerPluginSettings('headlamp-polaris-plugin', PolarisSettings, true);
|
|||||||
## Dark Mode Issues
|
## Dark Mode Issues
|
||||||
|
|
||||||
### Symptoms
|
### Symptoms
|
||||||
|
|
||||||
- Drawer background remains white in dark mode
|
- Drawer background remains white in dark mode
|
||||||
- Text is hard to read in dark mode
|
- Text is hard to read in dark mode
|
||||||
- Theme colors don't match Headlamp UI
|
- 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**:
|
**Verify CSS Variables**:
|
||||||
The plugin uses MUI CSS variables for theming:
|
The plugin uses MUI CSS variables for theming:
|
||||||
|
|
||||||
- `--mui-palette-background-default` (drawer background)
|
- `--mui-palette-background-default` (drawer background)
|
||||||
- `--mui-palette-text-primary` (text color)
|
- `--mui-palette-text-primary` (text color)
|
||||||
- `--mui-palette-primary-main` (links, buttons)
|
- `--mui-palette-primary-main` (links, buttons)
|
||||||
@@ -317,6 +327,7 @@ These automatically adapt to Headlamp's theme (light/dark/system).
|
|||||||
|
|
||||||
**Hard Refresh Required**:
|
**Hard Refresh Required**:
|
||||||
After upgrading from v0.3.4 or earlier, hard refresh your browser:
|
After upgrading from v0.3.4 or earlier, hard refresh your browser:
|
||||||
|
|
||||||
- macOS: Cmd+Shift+R
|
- macOS: Cmd+Shift+R
|
||||||
- Linux/Windows: Ctrl+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
|
## Data Not Loading / Infinite Spinner
|
||||||
|
|
||||||
### Symptoms
|
### Symptoms
|
||||||
|
|
||||||
- Plugin shows "Loading Polaris audit data..." forever
|
- Plugin shows "Loading Polaris audit data..." forever
|
||||||
- No error message in UI
|
- No error message in UI
|
||||||
- Data never appears
|
- Data never appears
|
||||||
@@ -339,6 +351,7 @@ If hard refresh doesn't help, clear cache for Headlamp domain.
|
|||||||
Open DevTools (F12) → Console tab.
|
Open DevTools (F12) → Console tab.
|
||||||
|
|
||||||
Look for:
|
Look for:
|
||||||
|
|
||||||
- Network errors (CORS, timeouts, 5xx responses)
|
- Network errors (CORS, timeouts, 5xx responses)
|
||||||
- JavaScript errors
|
- JavaScript errors
|
||||||
- Failed API requests
|
- Failed API requests
|
||||||
@@ -348,6 +361,7 @@ Look for:
|
|||||||
Open DevTools → Network tab → Filter by "results.json"
|
Open DevTools → Network tab → Filter by "results.json"
|
||||||
|
|
||||||
Expected request:
|
Expected request:
|
||||||
|
|
||||||
```
|
```
|
||||||
GET /api/v1/namespaces/polaris/services/polaris-dashboard:80/proxy/results.json
|
GET /api/v1/namespaces/polaris/services/polaris-dashboard:80/proxy/results.json
|
||||||
Status: 200
|
Status: 200
|
||||||
@@ -355,6 +369,7 @@ Response: JSON data
|
|||||||
```
|
```
|
||||||
|
|
||||||
Common issues:
|
Common issues:
|
||||||
|
|
||||||
- **Status 0 / Failed**: Network policy blocking request
|
- **Status 0 / Failed**: Network policy blocking request
|
||||||
- **Status 403**: RBAC issue (see [403 Forbidden Error](#403-forbidden-error))
|
- **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))
|
- **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**
|
**4. Check Network Policies**
|
||||||
|
|
||||||
If your cluster uses NetworkPolicies:
|
If your cluster uses NetworkPolicies:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl get networkpolicy -n polaris
|
kubectl get networkpolicy -n polaris
|
||||||
```
|
```
|
||||||
@@ -385,6 +401,7 @@ kubectl get networkpolicy -n polaris
|
|||||||
Ensure API server (or Headlamp pod) can reach Polaris dashboard.
|
Ensure API server (or Headlamp pod) can reach Polaris dashboard.
|
||||||
|
|
||||||
**Example fix**:
|
**Example fix**:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
apiVersion: networking.k8s.io/v1
|
apiVersion: networking.k8s.io/v1
|
||||||
kind: NetworkPolicy
|
kind: NetworkPolicy
|
||||||
@@ -399,7 +416,7 @@ spec:
|
|||||||
- Ingress
|
- Ingress
|
||||||
ingress:
|
ingress:
|
||||||
- from:
|
- from:
|
||||||
- namespaceSelector: {} # Allow from all namespaces (API server)
|
- namespaceSelector: {} # Allow from all namespaces (API server)
|
||||||
ports:
|
ports:
|
||||||
- protocol: TCP
|
- protocol: TCP
|
||||||
port: 8080
|
port: 8080
|
||||||
@@ -408,6 +425,7 @@ spec:
|
|||||||
**5. Increase Timeout / Disable Auto-Refresh**
|
**5. Increase Timeout / Disable Auto-Refresh**
|
||||||
|
|
||||||
If Polaris responds slowly:
|
If Polaris responds slowly:
|
||||||
|
|
||||||
- Open Settings → Polaris
|
- Open Settings → Polaris
|
||||||
- Increase refresh interval to 10+ minutes
|
- Increase refresh interval to 10+ minutes
|
||||||
- Or set to "Manual only" to disable auto-refresh
|
- 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)
|
**Cause**: Network request failed (CORS, network policy, timeout)
|
||||||
|
|
||||||
**Solution**:
|
**Solution**:
|
||||||
|
|
||||||
1. Check Network tab for actual HTTP status
|
1. Check Network tab for actual HTTP status
|
||||||
2. Verify network policies allow API server → Polaris
|
2. Verify network policies allow API server → Polaris
|
||||||
3. Check Polaris pod is running
|
3. Check Polaris pod is running
|
||||||
@@ -434,6 +453,7 @@ If Polaris responds slowly:
|
|||||||
**Cause**: API returned HTML (error page) instead of JSON
|
**Cause**: API returned HTML (error page) instead of JSON
|
||||||
|
|
||||||
**Solution**:
|
**Solution**:
|
||||||
|
|
||||||
1. Check Network tab response body (likely 404 or 500 error page)
|
1. Check Network tab response body (likely 404 or 500 error page)
|
||||||
2. Verify Polaris service exists and is healthy
|
2. Verify Polaris service exists and is healthy
|
||||||
3. Check service proxy URL is correct
|
3. Check service proxy URL is correct
|
||||||
@@ -453,6 +473,7 @@ If Polaris responds slowly:
|
|||||||
**Cause**: Polaris returned empty or malformed response
|
**Cause**: Polaris returned empty or malformed response
|
||||||
|
|
||||||
**Solution**:
|
**Solution**:
|
||||||
|
|
||||||
1. Check Polaris logs for errors
|
1. Check Polaris logs for errors
|
||||||
2. Verify Polaris is scanning the cluster (check audit timestamp)
|
2. Verify Polaris is scanning the cluster (check audit timestamp)
|
||||||
3. Test `/results.json` endpoint directly
|
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
|
### Sidecar Fails to Install Plugin
|
||||||
|
|
||||||
**Symptoms**:
|
**Symptoms**:
|
||||||
|
|
||||||
- Plugin sidecar logs show download errors
|
- Plugin sidecar logs show download errors
|
||||||
- Plugin directory is empty
|
- Plugin directory is empty
|
||||||
- Settings → Plugins shows nothing
|
- Settings → Plugins shows nothing
|
||||||
|
|
||||||
**Check sidecar logs**:
|
**Check sidecar logs**:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl logs -n kube-system deployment/headlamp -c headlamp-plugin
|
kubectl logs -n kube-system deployment/headlamp -c headlamp-plugin
|
||||||
```
|
```
|
||||||
@@ -566,11 +589,13 @@ Error: 404 Not Found
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Solution**: Verify `archive-url` in plugin config matches GitHub release:
|
**Solution**: Verify `archive-url` in plugin config matches GitHub release:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl get configmap headlamp-plugin-config -n kube-system -o yaml
|
kubectl get configmap headlamp-plugin-config -n kube-system -o yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
Expected format:
|
Expected format:
|
||||||
|
|
||||||
```
|
```
|
||||||
https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/download/v0.3.10/polaris-0.3.10.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/privilegedescalation/headlamp-polaris-plugin/releases/downloa
|
|||||||
**3. Permission denied writing to /headlamp/plugins**
|
**3. Permission denied writing to /headlamp/plugins**
|
||||||
|
|
||||||
**Solution**: Ensure volume mount is writable:
|
**Solution**: Ensure volume mount is writable:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: plugins
|
- name: plugins
|
||||||
@@ -591,17 +617,18 @@ volumeMounts:
|
|||||||
### Plugin Manager Not Working
|
### Plugin Manager Not Working
|
||||||
|
|
||||||
**Symptoms**:
|
**Symptoms**:
|
||||||
|
|
||||||
- Headlamp → Settings → Plugins shows "Catalog" tab but plugins don't install
|
- Headlamp → Settings → Plugins shows "Catalog" tab but plugins don't install
|
||||||
- "Install" button does nothing
|
- "Install" button does nothing
|
||||||
|
|
||||||
**Root Cause**: Plugin manager requires `config.pluginsDir` to be set.
|
**Root Cause**: Plugin manager requires `config.pluginsDir` to be set.
|
||||||
|
|
||||||
**Solution**: Configure Headlamp for plugin manager:
|
**Solution**: Configure Headlamp for plugin manager:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
# HelmRelease values
|
# HelmRelease values
|
||||||
config:
|
config:
|
||||||
pluginsDir: /headlamp/plugins
|
pluginsDir: /headlamp/plugins
|
||||||
watchPlugins: false # CRITICAL for v0.39.0+
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -609,25 +636,30 @@ config:
|
|||||||
## ArtifactHub Sync Delays
|
## ArtifactHub Sync Delays
|
||||||
|
|
||||||
### Symptoms
|
### Symptoms
|
||||||
|
|
||||||
- New version released on GitHub but not showing in ArtifactHub
|
- New version released on GitHub but not showing in ArtifactHub
|
||||||
- Headlamp plugin catalog shows old version
|
- Headlamp plugin catalog shows old version
|
||||||
|
|
||||||
### Root Cause
|
### Root Cause
|
||||||
|
|
||||||
ArtifactHub pulls metadata every 30 minutes. There is no webhook or push mechanism.
|
ArtifactHub pulls metadata every 30 minutes. There is no webhook or push mechanism.
|
||||||
|
|
||||||
### Solution
|
### Solution
|
||||||
|
|
||||||
**Wait 30 minutes** after pushing a GitHub release, then check:
|
**Wait 30 minutes** after pushing a GitHub release, then check:
|
||||||
|
|
||||||
```
|
```
|
||||||
https://artifacthub.io/packages/headlamp/headlamp-polaris-plugin/headlamp-polaris-plugin
|
https://artifacthub.io/packages/headlamp/headlamp-polaris-plugin/headlamp-polaris-plugin
|
||||||
```
|
```
|
||||||
|
|
||||||
**Verify metadata**:
|
**Verify metadata**:
|
||||||
|
|
||||||
1. Check `artifacthub-pkg.yml` is in repository root
|
1. Check `artifacthub-pkg.yml` is in repository root
|
||||||
2. Check `headlamp/plugin/archive-url` points to GitHub release
|
2. Check `headlamp/plugin/archive-url` points to GitHub release
|
||||||
3. Check `headlamp/plugin/archive-checksum` matches tarball SHA256
|
3. Check `headlamp/plugin/archive-checksum` matches tarball SHA256
|
||||||
|
|
||||||
**Force sync** (ArtifactHub UI):
|
**Force sync** (ArtifactHub UI):
|
||||||
|
|
||||||
- Log in to ArtifactHub as package maintainer
|
- Log in to ArtifactHub as package maintainer
|
||||||
- Go to package settings
|
- Go to package settings
|
||||||
- Click "Reindex now"
|
- Click "Reindex now"
|
||||||
@@ -643,23 +675,28 @@ If none of these solutions work, gather debugging information and open an issue:
|
|||||||
### Required Information
|
### Required Information
|
||||||
|
|
||||||
1. **Version Information**:
|
1. **Version Information**:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl get pods -n kube-system -l app.kubernetes.io/name=headlamp -o yaml | grep image:
|
kubectl get pods -n kube-system -l app.kubernetes.io/name=headlamp -o yaml | grep image:
|
||||||
```
|
```
|
||||||
|
|
||||||
2. **Plugin Version**:
|
2. **Plugin Version**:
|
||||||
|
|
||||||
- Check Settings → Plugins in Headlamp UI
|
- Check Settings → Plugins in Headlamp UI
|
||||||
- Or: `kubectl exec -n kube-system deployment/headlamp -c headlamp -- cat /headlamp/plugins/headlamp-polaris-plugin/package.json`
|
- Or: `kubectl exec -n kube-system deployment/headlamp -c headlamp -- cat /headlamp/plugins/headlamp-polaris-plugin/package.json`
|
||||||
|
|
||||||
3. **Browser Console Output**:
|
3. **Browser Console Output**:
|
||||||
|
|
||||||
- Open DevTools (F12) → Console
|
- Open DevTools (F12) → Console
|
||||||
- Screenshot or copy errors
|
- Screenshot or copy errors
|
||||||
|
|
||||||
4. **Network Tab**:
|
4. **Network Tab**:
|
||||||
|
|
||||||
- Open DevTools → Network
|
- Open DevTools → Network
|
||||||
- Screenshot failed requests to `results.json`
|
- Screenshot failed requests to `results.json`
|
||||||
|
|
||||||
5. **Pod Logs**:
|
5. **Pod Logs**:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl logs -n kube-system deployment/headlamp -c headlamp --tail=100
|
kubectl logs -n kube-system deployment/headlamp -c headlamp --tail=100
|
||||||
kubectl logs -n polaris deployment/polaris-dashboard --tail=100
|
kubectl logs -n polaris deployment/polaris-dashboard --tail=100
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ dashboard:
|
|||||||
enabled: true
|
enabled: true
|
||||||
env:
|
env:
|
||||||
- name: CORS_ALLOWED_ORIGINS
|
- name: CORS_ALLOWED_ORIGINS
|
||||||
value: "https://headlamp.example.com"
|
value: 'https://headlamp.example.com'
|
||||||
```
|
```
|
||||||
|
|
||||||
Test CORS headers:
|
Test CORS headers:
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ metadata:
|
|||||||
namespace: polaris
|
namespace: polaris
|
||||||
subjects:
|
subjects:
|
||||||
- kind: Group
|
- kind: Group
|
||||||
name: system:authenticated # All authenticated users
|
name: system:authenticated # All authenticated users
|
||||||
apiGroup: rbac.authorization.k8s.io
|
apiGroup: rbac.authorization.k8s.io
|
||||||
roleRef:
|
roleRef:
|
||||||
kind: Role
|
kind: Role
|
||||||
|
|||||||
@@ -28,12 +28,14 @@ Access plugin settings via **Settings → Plugins → Polaris** in the Headlamp
|
|||||||
### Impact
|
### Impact
|
||||||
|
|
||||||
**Affects:**
|
**Affects:**
|
||||||
|
|
||||||
- Dashboard overview page
|
- Dashboard overview page
|
||||||
- Namespace list and detail views
|
- Namespace list and detail views
|
||||||
- Inline audit sections on resource pages
|
- Inline audit sections on resource pages
|
||||||
- App bar score badge
|
- App bar score badge
|
||||||
|
|
||||||
**API Load:**
|
**API Load:**
|
||||||
|
|
||||||
- Each refresh triggers one HTTP GET to Polaris dashboard
|
- Each refresh triggers one HTTP GET to Polaris dashboard
|
||||||
- Each request is logged in Kubernetes audit logs
|
- Each request is logged in Kubernetes audit logs
|
||||||
- Longer intervals reduce API server and audit log pressure
|
- 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
|
### Performance Considerations
|
||||||
|
|
||||||
**For small clusters (<100 pods):**
|
**For small clusters (<100 pods):**
|
||||||
|
|
||||||
- Recommended: 5 minutes (default)
|
- Recommended: 5 minutes (default)
|
||||||
- Acceptable: 1 minute (if real-time data is critical)
|
- Acceptable: 1 minute (if real-time data is critical)
|
||||||
|
|
||||||
**For large clusters (>1000 pods):**
|
**For large clusters (>1000 pods):**
|
||||||
|
|
||||||
- Recommended: 10-30 minutes
|
- Recommended: 10-30 minutes
|
||||||
- Reason: Reduces audit log volume and API server load
|
- Reason: Reduces audit log volume and API server load
|
||||||
- Example: 10 users × 1-minute refresh = ~14,400 audit logs/day
|
- Example: 10 users × 1-minute refresh = ~14,400 audit logs/day
|
||||||
- Example: 10 users × 30-minute refresh = ~480 audit logs/day
|
- Example: 10 users × 30-minute refresh = ~480 audit logs/day
|
||||||
|
|
||||||
**For production environments:**
|
**For production environments:**
|
||||||
|
|
||||||
- Start with 5 minutes
|
- Start with 5 minutes
|
||||||
- Monitor API server metrics and audit log volume
|
- Monitor API server metrics and audit log volume
|
||||||
- Increase interval if needed
|
- Increase interval if needed
|
||||||
@@ -62,6 +67,7 @@ Access plugin settings via **Settings → Plugins → Polaris** in the Headlamp
|
|||||||
### Default Configuration
|
### Default Configuration
|
||||||
|
|
||||||
**Service proxy path (default):**
|
**Service proxy path (default):**
|
||||||
|
|
||||||
```
|
```
|
||||||
/api/v1/namespaces/polaris/services/polaris-dashboard:80/proxy/
|
/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.
|
This uses the Kubernetes API server to proxy requests to the Polaris dashboard service in the `polaris` namespace.
|
||||||
|
|
||||||
**Advantages:**
|
**Advantages:**
|
||||||
|
|
||||||
- Uses existing Headlamp authentication (service account or user token)
|
- Uses existing Headlamp authentication (service account or user token)
|
||||||
- Works with Headlamp's OIDC and token-auth modes
|
- Works with Headlamp's OIDC and token-auth modes
|
||||||
- No additional RBAC or network configuration needed
|
- No additional RBAC or network configuration needed
|
||||||
@@ -85,6 +92,7 @@ https://polaris.example.com/
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Requirements:**
|
**Requirements:**
|
||||||
|
|
||||||
- Polaris dashboard must be accessible from browser
|
- Polaris dashboard must be accessible from browser
|
||||||
- CORS must be configured on Polaris to allow Headlamp origin
|
- CORS must be configured on Polaris to allow Headlamp origin
|
||||||
- HTTPS recommended for production
|
- HTTPS recommended for production
|
||||||
@@ -98,6 +106,7 @@ If Polaris is deployed in a different namespace:
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Requirements:**
|
**Requirements:**
|
||||||
|
|
||||||
- Update RBAC Role namespace to match
|
- Update RBAC Role namespace to match
|
||||||
- Service name must still be `polaris-dashboard` (or adjust in URL)
|
- 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.
|
**What it does:** Verifies the plugin can reach the Polaris dashboard and fetch audit data.
|
||||||
|
|
||||||
**To test:**
|
**To test:**
|
||||||
|
|
||||||
1. Enter Dashboard URL in settings
|
1. Enter Dashboard URL in settings
|
||||||
2. Click **Test Connection**
|
2. Click **Test Connection**
|
||||||
3. Wait for response (2-5 seconds)
|
3. Wait for response (2-5 seconds)
|
||||||
|
|
||||||
**Success Response:**
|
**Success Response:**
|
||||||
|
|
||||||
```
|
```
|
||||||
✓ Connected to Polaris v4.2.0
|
✓ Connected to Polaris v4.2.0
|
||||||
```
|
```
|
||||||
|
|
||||||
**Error Responses:**
|
**Error Responses:**
|
||||||
|
|
||||||
| Error | Meaning | Solution |
|
| Error | Meaning | Solution |
|
||||||
|-------|---------|----------|
|
| --------------------------- | ------------------------- | ----------------------------------------------------------- |
|
||||||
| **403 Forbidden** | RBAC permission denied | Check RBAC bindings (see [RBAC Guide](rbac-permissions.md)) |
|
| **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` |
|
| **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` |
|
| **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 |
|
| **Network Error** | Cannot reach URL | Check URL format, CORS (for external), NetworkPolicies |
|
||||||
| **CORS Error** | Cross-origin blocked | Configure Polaris dashboard CORS headers |
|
| **CORS Error** | Cross-origin blocked | Configure Polaris dashboard CORS headers |
|
||||||
|
|
||||||
### CORS Configuration (External Polaris)
|
### CORS Configuration (External Polaris)
|
||||||
|
|
||||||
If using an external Polaris URL, configure CORS to allow Headlamp origin.
|
If using an external Polaris URL, configure CORS to allow Headlamp origin.
|
||||||
|
|
||||||
**Polaris Helm values:**
|
**Polaris Helm values:**
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
dashboard:
|
dashboard:
|
||||||
enabled: true
|
enabled: true
|
||||||
env:
|
env:
|
||||||
- name: CORS_ALLOWED_ORIGINS
|
- name: CORS_ALLOWED_ORIGINS
|
||||||
value: "https://headlamp.example.com"
|
value: 'https://headlamp.example.com'
|
||||||
```
|
```
|
||||||
|
|
||||||
**Test CORS:**
|
**Test CORS:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -v -H "Origin: https://headlamp.example.com" \
|
curl -v -H "Origin: https://headlamp.example.com" \
|
||||||
https://polaris.example.com/results.json \
|
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**:
|
Plugin settings are stored in browser **localStorage**:
|
||||||
|
|
||||||
**Keys:**
|
**Keys:**
|
||||||
|
|
||||||
- `polaris-plugin-refresh-interval` - Refresh interval in seconds (number)
|
- `polaris-plugin-refresh-interval` - Refresh interval in seconds (number)
|
||||||
- `polaris-plugin-dashboard-url` - Dashboard URL (string)
|
- `polaris-plugin-dashboard-url` - Dashboard URL (string)
|
||||||
|
|
||||||
**View settings:**
|
**View settings:**
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// Open browser DevTools Console (F12)
|
// Open browser DevTools Console (F12)
|
||||||
console.log('Refresh Interval:', localStorage.getItem('polaris-plugin-refresh-interval'))
|
console.log('Refresh Interval:', localStorage.getItem('polaris-plugin-refresh-interval'));
|
||||||
console.log('Dashboard URL:', localStorage.getItem('polaris-plugin-dashboard-url'))
|
console.log('Dashboard URL:', localStorage.getItem('polaris-plugin-dashboard-url'));
|
||||||
```
|
```
|
||||||
|
|
||||||
**Reset to defaults:**
|
**Reset to defaults:**
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// Open browser DevTools Console (F12)
|
// Open browser DevTools Console (F12)
|
||||||
localStorage.removeItem('polaris-plugin-refresh-interval')
|
localStorage.removeItem('polaris-plugin-refresh-interval');
|
||||||
localStorage.removeItem('polaris-plugin-dashboard-url')
|
localStorage.removeItem('polaris-plugin-dashboard-url');
|
||||||
// Hard refresh browser: Cmd+Shift+R (Mac) or Ctrl+Shift+R (Windows/Linux)
|
// Hard refresh browser: Cmd+Shift+R (Mac) or Ctrl+Shift+R (Windows/Linux)
|
||||||
```
|
```
|
||||||
|
|
||||||
**Notes:**
|
**Notes:**
|
||||||
|
|
||||||
- Settings are per-browser, per-user
|
- Settings are per-browser, per-user
|
||||||
- Private/incognito mode may clear settings on browser close
|
- Private/incognito mode may clear settings on browser close
|
||||||
- Settings are NOT synced across devices
|
- Settings are NOT synced across devices
|
||||||
@@ -208,6 +225,7 @@ localStorage.removeItem('polaris-plugin-dashboard-url')
|
|||||||
### For Development Clusters
|
### For Development Clusters
|
||||||
|
|
||||||
**Recommended Settings:**
|
**Recommended Settings:**
|
||||||
|
|
||||||
- **Refresh Interval:** 1-5 minutes (faster feedback loop)
|
- **Refresh Interval:** 1-5 minutes (faster feedback loop)
|
||||||
- **Dashboard URL:** Service proxy (default)
|
- **Dashboard URL:** Service proxy (default)
|
||||||
|
|
||||||
@@ -216,6 +234,7 @@ localStorage.removeItem('polaris-plugin-dashboard-url')
|
|||||||
### For Staging Clusters
|
### For Staging Clusters
|
||||||
|
|
||||||
**Recommended Settings:**
|
**Recommended Settings:**
|
||||||
|
|
||||||
- **Refresh Interval:** 5-10 minutes (balanced)
|
- **Refresh Interval:** 5-10 minutes (balanced)
|
||||||
- **Dashboard URL:** Service proxy (default)
|
- **Dashboard URL:** Service proxy (default)
|
||||||
|
|
||||||
@@ -224,6 +243,7 @@ localStorage.removeItem('polaris-plugin-dashboard-url')
|
|||||||
### For Production Clusters
|
### For Production Clusters
|
||||||
|
|
||||||
**Recommended Settings:**
|
**Recommended Settings:**
|
||||||
|
|
||||||
- **Refresh Interval:** 10-30 minutes (reduce load)
|
- **Refresh Interval:** 10-30 minutes (reduce load)
|
||||||
- **Dashboard URL:** Service proxy (default)
|
- **Dashboard URL:** Service proxy (default)
|
||||||
|
|
||||||
@@ -232,6 +252,7 @@ localStorage.removeItem('polaris-plugin-dashboard-url')
|
|||||||
### For Multi-Tenant Environments
|
### For Multi-Tenant Environments
|
||||||
|
|
||||||
**Recommended Settings:**
|
**Recommended Settings:**
|
||||||
|
|
||||||
- **Refresh Interval:** 10-30 minutes (minimize per-user load)
|
- **Refresh Interval:** 10-30 minutes (minimize per-user load)
|
||||||
- **Dashboard URL:** Service proxy with per-namespace RBAC
|
- **Dashboard URL:** Service proxy with per-namespace RBAC
|
||||||
|
|
||||||
@@ -240,6 +261,7 @@ localStorage.removeItem('polaris-plugin-dashboard-url')
|
|||||||
### For External Polaris
|
### For External Polaris
|
||||||
|
|
||||||
**Recommended Settings:**
|
**Recommended Settings:**
|
||||||
|
|
||||||
- **Refresh Interval:** 5-10 minutes (depends on network latency)
|
- **Refresh Interval:** 5-10 minutes (depends on network latency)
|
||||||
- **Dashboard URL:** `https://polaris.example.com/`
|
- **Dashboard URL:** `https://polaris.example.com/`
|
||||||
- **CORS:** Must be configured on Polaris side
|
- **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
|
**Symptom:** Changes to settings revert after clicking Save
|
||||||
|
|
||||||
**Possible Causes:**
|
**Possible Causes:**
|
||||||
|
|
||||||
1. Browser blocks localStorage (privacy mode)
|
1. Browser blocks localStorage (privacy mode)
|
||||||
2. Browser extension interfering
|
2. Browser extension interfering
|
||||||
3. JavaScript error in console
|
3. JavaScript error in console
|
||||||
|
|
||||||
**Solution:**
|
**Solution:**
|
||||||
|
|
||||||
1. Open browser DevTools Console (F12)
|
1. Open browser DevTools Console (F12)
|
||||||
2. Check for JavaScript errors
|
2. Check for JavaScript errors
|
||||||
3. Disable privacy mode or try different browser
|
3. Disable privacy mode or try different browser
|
||||||
4. Check if localStorage is enabled:
|
4. Check if localStorage is enabled:
|
||||||
```javascript
|
```javascript
|
||||||
console.log('localStorage available:', typeof localStorage !== 'undefined')
|
console.log('localStorage available:', typeof localStorage !== 'undefined');
|
||||||
```
|
```
|
||||||
|
|
||||||
### Settings Lost After Browser Restart
|
### Settings Lost After Browser Restart
|
||||||
@@ -273,6 +297,7 @@ localStorage.removeItem('polaris-plugin-dashboard-url')
|
|||||||
**Cause:** Browser privacy settings clear localStorage on exit
|
**Cause:** Browser privacy settings clear localStorage on exit
|
||||||
|
|
||||||
**Solution:**
|
**Solution:**
|
||||||
|
|
||||||
- Use normal browsing mode (not private/incognito)
|
- Use normal browsing mode (not private/incognito)
|
||||||
- Check browser settings for "Clear data on exit"
|
- Check browser settings for "Clear data on exit"
|
||||||
- Consider requesting ConfigMap-based settings (future feature)
|
- Consider requesting ConfigMap-based settings (future feature)
|
||||||
@@ -284,6 +309,7 @@ localStorage.removeItem('polaris-plugin-dashboard-url')
|
|||||||
**Solutions by error type:**
|
**Solutions by error type:**
|
||||||
|
|
||||||
**403 Forbidden:**
|
**403 Forbidden:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Verify RBAC exists
|
# Verify RBAC exists
|
||||||
kubectl -n polaris get role polaris-proxy-reader
|
kubectl -n polaris get role polaris-proxy-reader
|
||||||
@@ -297,6 +323,7 @@ kubectl auth can-i get services/proxy \
|
|||||||
```
|
```
|
||||||
|
|
||||||
**404 Not Found:**
|
**404 Not Found:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Verify Polaris is running
|
# Verify Polaris is running
|
||||||
kubectl -n polaris get pods
|
kubectl -n polaris get pods
|
||||||
@@ -310,6 +337,7 @@ helm install polaris fairwinds-stable/polaris \
|
|||||||
```
|
```
|
||||||
|
|
||||||
**503 Service Unavailable:**
|
**503 Service Unavailable:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Check pod status
|
# Check pod status
|
||||||
kubectl -n polaris get pods
|
kubectl -n polaris get pods
|
||||||
@@ -319,6 +347,7 @@ kubectl -n polaris logs deployment/polaris-dashboard
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Network Error / CORS:**
|
**Network Error / CORS:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# For external Polaris, test CORS
|
# For external Polaris, test CORS
|
||||||
curl -v -H "Origin: https://headlamp.example.com" \
|
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
|
**Symptom:** Data doesn't refresh automatically
|
||||||
|
|
||||||
**Check:**
|
**Check:**
|
||||||
|
|
||||||
1. Verify setting is saved (localStorage key exists)
|
1. Verify setting is saved (localStorage key exists)
|
||||||
2. Check browser console for errors
|
2. Check browser console for errors
|
||||||
3. Verify Polaris is returning data (manual refresh works)
|
3. Verify Polaris is returning data (manual refresh works)
|
||||||
4. Ensure you're on a Polaris plugin page (not other Headlamp pages)
|
4. Ensure you're on a Polaris plugin page (not other Headlamp pages)
|
||||||
|
|
||||||
**Debug:**
|
**Debug:**
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// Check refresh interval
|
// 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.
|
// Should return: "300" (5 minutes), "600" (10 minutes), etc.
|
||||||
```
|
```
|
||||||
@@ -361,6 +392,7 @@ Before going to production, verify:
|
|||||||
## Future Configuration Options
|
## Future Configuration Options
|
||||||
|
|
||||||
**Planned features:**
|
**Planned features:**
|
||||||
|
|
||||||
- ConfigMap-based settings (server-side, not localStorage)
|
- ConfigMap-based settings (server-side, not localStorage)
|
||||||
- Per-cluster settings (multi-cluster Headlamp support)
|
- Per-cluster settings (multi-cluster Headlamp support)
|
||||||
- Webhook notifications for score changes
|
- 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.
|
Navigate to **Polaris → Namespaces** to see all namespaces with audit results.
|
||||||
|
|
||||||
**Table Columns:**
|
**Table Columns:**
|
||||||
|
|
||||||
- **Namespace** - Clickable namespace name (opens detail panel)
|
- **Namespace** - Clickable namespace name (opens detail panel)
|
||||||
- **Score** - Per-namespace score with color coding
|
- **Score** - Per-namespace score with color coding
|
||||||
- **Pass** - Passing checks count
|
- **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.
|
Click any namespace to open a 1000px-wide side panel with detailed information.
|
||||||
|
|
||||||
**Features:**
|
**Features:**
|
||||||
|
|
||||||
- **Namespace Score** - Color-coded score gauge
|
- **Namespace Score** - Color-coded score gauge
|
||||||
- **Check Counts** - Pass/Warning/Danger/Skipped breakdown
|
- **Check Counts** - Pass/Warning/Danger/Skipped breakdown
|
||||||
- **Resource Table** - Per-resource audit results:
|
- **Resource Table** - Per-resource audit results:
|
||||||
@@ -92,6 +94,7 @@ Polaris audit results automatically appear on resource detail pages.
|
|||||||
### Supported Resources
|
### Supported Resources
|
||||||
|
|
||||||
Inline audit sections appear on:
|
Inline audit sections appear on:
|
||||||
|
|
||||||
- Deployments
|
- Deployments
|
||||||
- StatefulSets
|
- StatefulSets
|
||||||
- DaemonSets
|
- DaemonSets
|
||||||
@@ -101,6 +104,7 @@ Inline audit sections appear on:
|
|||||||
### What's Shown
|
### What's Shown
|
||||||
|
|
||||||
**Compact Audit Section:**
|
**Compact Audit Section:**
|
||||||
|
|
||||||
- **Score Badge** - Color-coded score
|
- **Score Badge** - Color-coded score
|
||||||
- **Check Counts** - Pass/Warning/Danger summary
|
- **Check Counts** - Pass/Warning/Danger summary
|
||||||
- **Failing Checks Table** - Only failed checks listed:
|
- **Failing Checks Table** - Only failed checks listed:
|
||||||
@@ -116,6 +120,7 @@ Inline audit sections appear on:
|
|||||||
Top-right corner of Headlamp shows a persistent cluster score badge.
|
Top-right corner of Headlamp shows a persistent cluster score badge.
|
||||||
|
|
||||||
**Features:**
|
**Features:**
|
||||||
|
|
||||||
- **Color-Coded Chip** - Green/Yellow/Red based on score
|
- **Color-Coded Chip** - Green/Yellow/Red based on score
|
||||||
- **Shield Icon** - Visual indicator
|
- **Shield Icon** - Visual indicator
|
||||||
- **Score Percentage** - e.g., "85%"
|
- **Score Percentage** - e.g., "85%"
|
||||||
@@ -134,12 +139,14 @@ Access plugin settings via **Settings → Plugins → Polaris**.
|
|||||||
Controls how often the plugin fetches new audit data.
|
Controls how often the plugin fetches new audit data.
|
||||||
|
|
||||||
**Options:**
|
**Options:**
|
||||||
|
|
||||||
- 1 minute - Most frequent (highest API load)
|
- 1 minute - Most frequent (highest API load)
|
||||||
- 5 minutes - **Default** (recommended)
|
- 5 minutes - **Default** (recommended)
|
||||||
- 10 minutes - Moderate refresh rate
|
- 10 minutes - Moderate refresh rate
|
||||||
- 30 minutes - Light load (large clusters)
|
- 30 minutes - Light load (large clusters)
|
||||||
|
|
||||||
**Impact:**
|
**Impact:**
|
||||||
|
|
||||||
- Affects all views (dashboard, namespaces, inline audits, app bar badge)
|
- Affects all views (dashboard, namespaces, inline audits, app bar badge)
|
||||||
- Longer intervals reduce Kubernetes API audit logging
|
- Longer intervals reduce Kubernetes API audit logging
|
||||||
- Changes take effect immediately (no restart required)
|
- 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.
|
Specifies which Polaris instance to connect to.
|
||||||
|
|
||||||
**Default:** Kubernetes service proxy path
|
**Default:** Kubernetes service proxy path
|
||||||
|
|
||||||
```
|
```
|
||||||
/api/v1/namespaces/polaris/services/polaris-dashboard:80/proxy/
|
/api/v1/namespaces/polaris/services/polaris-dashboard:80/proxy/
|
||||||
```
|
```
|
||||||
|
|
||||||
**Custom Options:**
|
**Custom Options:**
|
||||||
|
|
||||||
- External Polaris: `https://polaris.example.com/`
|
- External Polaris: `https://polaris.example.com/`
|
||||||
- Different namespace: `/api/v1/namespaces/custom-ns/services/polaris-dashboard:80/proxy/`
|
- 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.
|
Full theme adaptation for Headlamp's light and dark modes.
|
||||||
|
|
||||||
**Features:**
|
**Features:**
|
||||||
|
|
||||||
- **Auto Dark Mode** - Respects system preference when Headlamp uses it
|
- **Auto Dark Mode** - Respects system preference when Headlamp uses it
|
||||||
- **Theme Toggle** - Adapts when you change Headlamp theme
|
- **Theme Toggle** - Adapts when you change Headlamp theme
|
||||||
- **All UI Elements** - Drawer backgrounds, tables, buttons, badges, score gauge
|
- **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)
|
**Status:** Planned feature (UI components exist but not fully integrated)
|
||||||
|
|
||||||
**Future Capability:**
|
**Future Capability:**
|
||||||
|
|
||||||
- View current exemptions on resources
|
- View current exemptions on resources
|
||||||
- Add exemptions for specific failing checks
|
- Add exemptions for specific failing checks
|
||||||
- Remove exemptions
|
- Remove exemptions
|
||||||
@@ -190,21 +201,25 @@ This feature requires additional RBAC permissions (PATCH on workload resources)
|
|||||||
## Data Refresh Behavior
|
## Data Refresh Behavior
|
||||||
|
|
||||||
**Initial Load:**
|
**Initial Load:**
|
||||||
|
|
||||||
- Data fetched when you first navigate to any Polaris view
|
- Data fetched when you first navigate to any Polaris view
|
||||||
- Shared across all views via React Context (no duplicate fetches)
|
- Shared across all views via React Context (no duplicate fetches)
|
||||||
- Loading spinner displayed during initial fetch
|
- Loading spinner displayed during initial fetch
|
||||||
|
|
||||||
**Auto-Refresh:**
|
**Auto-Refresh:**
|
||||||
|
|
||||||
- Configured via Settings → Plugins → Polaris
|
- Configured via Settings → Plugins → Polaris
|
||||||
- Default: 5 minutes
|
- Default: 5 minutes
|
||||||
- Triggers background fetch without disrupting UI
|
- Triggers background fetch without disrupting UI
|
||||||
|
|
||||||
**Manual Refresh:**
|
**Manual Refresh:**
|
||||||
|
|
||||||
- Click refresh button on overview dashboard
|
- Click refresh button on overview dashboard
|
||||||
- Forces immediate data fetch
|
- Forces immediate data fetch
|
||||||
- Updates all views simultaneously
|
- Updates all views simultaneously
|
||||||
|
|
||||||
**Error Handling:**
|
**Error Handling:**
|
||||||
|
|
||||||
- 403 errors show RBAC permission guidance
|
- 403 errors show RBAC permission guidance
|
||||||
- 404/503 errors indicate Polaris not installed
|
- 404/503 errors indicate Polaris not installed
|
||||||
- Network errors show generic failure with retry suggestion
|
- Network errors show generic failure with retry suggestion
|
||||||
@@ -212,12 +227,14 @@ This feature requires additional RBAC permissions (PATCH on workload resources)
|
|||||||
## Browser Requirements
|
## Browser Requirements
|
||||||
|
|
||||||
**Supported Browsers:**
|
**Supported Browsers:**
|
||||||
|
|
||||||
- Chrome/Chromium 80+
|
- Chrome/Chromium 80+
|
||||||
- Firefox 75+
|
- Firefox 75+
|
||||||
- Safari 13.1+
|
- Safari 13.1+
|
||||||
- Edge 80+
|
- Edge 80+
|
||||||
|
|
||||||
**Required:**
|
**Required:**
|
||||||
|
|
||||||
- JavaScript enabled
|
- JavaScript enabled
|
||||||
- localStorage enabled (for settings persistence)
|
- localStorage enabled (for settings persistence)
|
||||||
- Cookies enabled (for Headlamp session)
|
- 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)
|
**Bundle Size:** ~27 KB minified (gzip: ~7.6 KB)
|
||||||
|
|
||||||
**Data Volume:** Depends on cluster size. Example:
|
**Data Volume:** Depends on cluster size. Example:
|
||||||
|
|
||||||
- Small cluster (50 resources): ~100 KB JSON
|
- Small cluster (50 resources): ~100 KB JSON
|
||||||
- Medium cluster (500 resources): ~1 MB JSON
|
- Medium cluster (500 resources): ~1 MB JSON
|
||||||
- Large cluster (5000 resources): ~10 MB JSON
|
- Large cluster (5000 resources): ~10 MB JSON
|
||||||
|
|
||||||
**Rendering Performance:**
|
**Rendering Performance:**
|
||||||
|
|
||||||
- Handles up to 100 namespaces without virtual scrolling
|
- Handles up to 100 namespaces without virtual scrolling
|
||||||
- Namespace detail drawer renders instantly for up to 500 resources
|
- Namespace detail drawer renders instantly for up to 500 resources
|
||||||
- React Context prevents unnecessary re-fetches
|
- 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.
|
This allows the plugin to fetch audit results via the Kubernetes service proxy.
|
||||||
|
|
||||||
**Why this permission?**
|
**Why this permission?**
|
||||||
|
|
||||||
- Plugin accesses Polaris through Kubernetes API server's service proxy
|
- Plugin accesses Polaris through Kubernetes API server's service proxy
|
||||||
- Service proxy requires `get` verb on `services/proxy` resource
|
- Service proxy requires `get` verb on `services/proxy` resource
|
||||||
- Scoped to specific service (`polaris-dashboard`) for security
|
- Scoped to specific service (`polaris-dashboard`) for security
|
||||||
@@ -37,13 +38,14 @@ metadata:
|
|||||||
app.kubernetes.io/name: headlamp-polaris-plugin
|
app.kubernetes.io/name: headlamp-polaris-plugin
|
||||||
app.kubernetes.io/component: rbac
|
app.kubernetes.io/component: rbac
|
||||||
rules:
|
rules:
|
||||||
- apiGroups: [""]
|
- apiGroups: ['']
|
||||||
resources: ["services/proxy"]
|
resources: ['services/proxy']
|
||||||
resourceNames: ["polaris-dashboard"]
|
resourceNames: ['polaris-dashboard']
|
||||||
verbs: ["get"]
|
verbs: ['get']
|
||||||
```
|
```
|
||||||
|
|
||||||
**Key points:**
|
**Key points:**
|
||||||
|
|
||||||
- **Role** (not ClusterRole) - Scoped to `polaris` namespace only
|
- **Role** (not ClusterRole) - Scoped to `polaris` namespace only
|
||||||
- **resourceNames** - Restricts access to `polaris-dashboard` service only
|
- **resourceNames** - Restricts access to `polaris-dashboard` service only
|
||||||
- **verbs: ["get"]** - Read-only permission
|
- **verbs: ["get"]** - Read-only permission
|
||||||
@@ -62,8 +64,8 @@ metadata:
|
|||||||
app.kubernetes.io/component: rbac
|
app.kubernetes.io/component: rbac
|
||||||
subjects:
|
subjects:
|
||||||
- kind: ServiceAccount
|
- kind: ServiceAccount
|
||||||
name: headlamp # Adjust to your Headlamp SA name
|
name: headlamp # Adjust to your Headlamp SA name
|
||||||
namespace: kube-system # Adjust to Headlamp's namespace
|
namespace: kube-system # Adjust to Headlamp's namespace
|
||||||
roleRef:
|
roleRef:
|
||||||
kind: Role
|
kind: Role
|
||||||
name: polaris-proxy-reader
|
name: polaris-proxy-reader
|
||||||
@@ -71,6 +73,7 @@ roleRef:
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Adjust for your environment:**
|
**Adjust for your environment:**
|
||||||
|
|
||||||
- `subjects[0].name` - Your Headlamp service account name (often `headlamp`)
|
- `subjects[0].name` - Your Headlamp service account name (often `headlamp`)
|
||||||
- `subjects[0].namespace` - Namespace where Headlamp runs (often `kube-system`)
|
- `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?
|
### Why Per-User RBAC?
|
||||||
|
|
||||||
With service account mode:
|
With service account mode:
|
||||||
|
|
||||||
- Single RoleBinding grants access to all Headlamp users
|
- Single RoleBinding grants access to all Headlamp users
|
||||||
- Kubernetes sees all requests as `system:serviceaccount:kube-system:headlamp`
|
- Kubernetes sees all requests as `system:serviceaccount:kube-system:headlamp`
|
||||||
|
|
||||||
With token-auth mode:
|
With token-auth mode:
|
||||||
|
|
||||||
- Each user's own token (OIDC, kubeconfig) is used
|
- Each user's own token (OIDC, kubeconfig) is used
|
||||||
- Kubernetes sees requests as `user@example.com` or `system:serviceaccount:team-ns:user-sa`
|
- Kubernetes sees requests as `user@example.com` or `system:serviceaccount:team-ns:user-sa`
|
||||||
- **Each user needs individual RBAC permissions**
|
- **Each user needs individual RBAC permissions**
|
||||||
@@ -125,7 +130,7 @@ metadata:
|
|||||||
namespace: polaris
|
namespace: polaris
|
||||||
subjects:
|
subjects:
|
||||||
- kind: Group
|
- kind: Group
|
||||||
name: system:authenticated # All authenticated users
|
name: system:authenticated # All authenticated users
|
||||||
apiGroup: rbac.authorization.k8s.io
|
apiGroup: rbac.authorization.k8s.io
|
||||||
roleRef:
|
roleRef:
|
||||||
kind: Role
|
kind: Role
|
||||||
@@ -174,7 +179,7 @@ metadata:
|
|||||||
namespace: polaris
|
namespace: polaris
|
||||||
subjects:
|
subjects:
|
||||||
- kind: Group
|
- kind: Group
|
||||||
name: sre-team # OIDC group claim
|
name: sre-team # OIDC group claim
|
||||||
apiGroup: rbac.authorization.k8s.io
|
apiGroup: rbac.authorization.k8s.io
|
||||||
- kind: Group
|
- kind: Group
|
||||||
name: devops-team
|
name: devops-team
|
||||||
@@ -186,11 +191,13 @@ roleRef:
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Requirements:**
|
**Requirements:**
|
||||||
|
|
||||||
- OIDC provider must include group claims in token
|
- OIDC provider must include group claims in token
|
||||||
- Headlamp must be configured to extract groups from OIDC token
|
- Headlamp must be configured to extract groups from OIDC token
|
||||||
- Group names must match exactly (case-sensitive)
|
- Group names must match exactly (case-sensitive)
|
||||||
|
|
||||||
**Example OIDC group claim:**
|
**Example OIDC group claim:**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"sub": "user@example.com",
|
"sub": "user@example.com",
|
||||||
@@ -229,23 +236,23 @@ apiVersion: rbac.authorization.k8s.io/v1
|
|||||||
kind: Role
|
kind: Role
|
||||||
metadata:
|
metadata:
|
||||||
name: polaris-proxy-reader
|
name: polaris-proxy-reader
|
||||||
namespace: team-a-polaris # First Polaris instance
|
namespace: team-a-polaris # First Polaris instance
|
||||||
rules:
|
rules:
|
||||||
- apiGroups: [""]
|
- apiGroups: ['']
|
||||||
resources: ["services/proxy"]
|
resources: ['services/proxy']
|
||||||
resourceNames: ["polaris-dashboard"]
|
resourceNames: ['polaris-dashboard']
|
||||||
verbs: ["get"]
|
verbs: ['get']
|
||||||
---
|
---
|
||||||
apiVersion: rbac.authorization.k8s.io/v1
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
kind: Role
|
kind: Role
|
||||||
metadata:
|
metadata:
|
||||||
name: polaris-proxy-reader
|
name: polaris-proxy-reader
|
||||||
namespace: team-b-polaris # Second Polaris instance
|
namespace: team-b-polaris # Second Polaris instance
|
||||||
rules:
|
rules:
|
||||||
- apiGroups: [""]
|
- apiGroups: ['']
|
||||||
resources: ["services/proxy"]
|
resources: ['services/proxy']
|
||||||
resourceNames: ["polaris-dashboard"]
|
resourceNames: ['polaris-dashboard']
|
||||||
verbs: ["get"]
|
verbs: ['get']
|
||||||
```
|
```
|
||||||
|
|
||||||
### Create RoleBindings per Namespace
|
### Create RoleBindings per Namespace
|
||||||
@@ -343,22 +350,24 @@ When using OAuth2/OIDC authentication with Headlamp:
|
|||||||
### Required Configuration
|
### Required Configuration
|
||||||
|
|
||||||
**Headlamp Helm values:**
|
**Headlamp Helm values:**
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
env:
|
env:
|
||||||
- name: HEADLAMP_CONFIG_OIDC_CLIENT_ID
|
- name: HEADLAMP_CONFIG_OIDC_CLIENT_ID
|
||||||
value: "headlamp"
|
value: 'headlamp'
|
||||||
- name: HEADLAMP_CONFIG_OIDC_CLIENT_SECRET
|
- name: HEADLAMP_CONFIG_OIDC_CLIENT_SECRET
|
||||||
valueFrom:
|
valueFrom:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: headlamp-oidc
|
name: headlamp-oidc
|
||||||
key: client-secret
|
key: client-secret
|
||||||
- name: HEADLAMP_CONFIG_OIDC_ISSUER_URL
|
- 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
|
- name: HEADLAMP_CONFIG_OIDC_SCOPES
|
||||||
value: "openid,profile,email,groups"
|
value: 'openid,profile,email,groups'
|
||||||
```
|
```
|
||||||
|
|
||||||
**RBAC for OIDC users:**
|
**RBAC for OIDC users:**
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
---
|
---
|
||||||
apiVersion: rbac.authorization.k8s.io/v1
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
@@ -368,7 +377,7 @@ metadata:
|
|||||||
namespace: polaris
|
namespace: polaris
|
||||||
subjects:
|
subjects:
|
||||||
- kind: Group
|
- kind: Group
|
||||||
name: kubernetes-admins # OIDC group claim
|
name: kubernetes-admins # OIDC group claim
|
||||||
apiGroup: rbac.authorization.k8s.io
|
apiGroup: rbac.authorization.k8s.io
|
||||||
roleRef:
|
roleRef:
|
||||||
kind: Role
|
kind: Role
|
||||||
@@ -421,32 +430,36 @@ Every plugin data fetch creates a Kubernetes API audit log entry.
|
|||||||
### Volume Estimates
|
### Volume Estimates
|
||||||
|
|
||||||
**Per user:**
|
**Per user:**
|
||||||
|
|
||||||
- 1 refresh per 5 minutes = 288 requests/day
|
- 1 refresh per 5 minutes = 288 requests/day
|
||||||
- 1 refresh per 30 minutes = 48 requests/day
|
- 1 refresh per 30 minutes = 48 requests/day
|
||||||
|
|
||||||
**Cluster-wide:**
|
**Cluster-wide:**
|
||||||
|
|
||||||
- 10 concurrent users × 5-minute refresh = 2,880 audit logs/day
|
- 10 concurrent users × 5-minute refresh = 2,880 audit logs/day
|
||||||
- 100 concurrent users × 30-minute refresh = 4,800 audit logs/day
|
- 100 concurrent users × 30-minute refresh = 4,800 audit logs/day
|
||||||
|
|
||||||
### Reducing Audit Volume
|
### Reducing Audit Volume
|
||||||
|
|
||||||
**Option 1: Increase refresh interval**
|
**Option 1: Increase refresh interval**
|
||||||
|
|
||||||
```
|
```
|
||||||
Settings → Plugins → Polaris → Refresh Interval → 30 minutes
|
Settings → Plugins → Polaris → Refresh Interval → 30 minutes
|
||||||
```
|
```
|
||||||
|
|
||||||
**Option 2: Adjust audit policy level**
|
**Option 2: Adjust audit policy level**
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
# kube-apiserver audit policy
|
# kube-apiserver audit policy
|
||||||
apiVersion: audit.k8s.io/v1
|
apiVersion: audit.k8s.io/v1
|
||||||
kind: Policy
|
kind: Policy
|
||||||
rules:
|
rules:
|
||||||
- level: Metadata # Log metadata only, not full request/response
|
- level: Metadata # Log metadata only, not full request/response
|
||||||
verbs: ["get"]
|
verbs: ['get']
|
||||||
resources:
|
resources:
|
||||||
- group: ""
|
- group: ''
|
||||||
resources: ["services/proxy"]
|
resources: ['services/proxy']
|
||||||
namespaces: ["polaris"]
|
namespaces: ['polaris']
|
||||||
```
|
```
|
||||||
|
|
||||||
**Option 3: Filter audit logs**
|
**Option 3: Filter audit logs**
|
||||||
@@ -461,18 +474,23 @@ If using a log aggregator (e.g., Elasticsearch), create filters to exclude or do
|
|||||||
**Diagnosis:**
|
**Diagnosis:**
|
||||||
|
|
||||||
1. **Check Role exists:**
|
1. **Check Role exists:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl -n polaris get role polaris-proxy-reader
|
kubectl -n polaris get role polaris-proxy-reader
|
||||||
```
|
```
|
||||||
|
|
||||||
If missing: Apply Role manifest
|
If missing: Apply Role manifest
|
||||||
|
|
||||||
2. **Check RoleBinding exists:**
|
2. **Check RoleBinding exists:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl -n polaris get rolebinding headlamp-polaris-proxy
|
kubectl -n polaris get rolebinding headlamp-polaris-proxy
|
||||||
```
|
```
|
||||||
|
|
||||||
If missing: Apply RoleBinding manifest
|
If missing: Apply RoleBinding manifest
|
||||||
|
|
||||||
3. **Test permission:**
|
3. **Test permission:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Service account mode
|
# Service account mode
|
||||||
kubectl auth can-i get services/proxy \
|
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 \
|
-n polaris \
|
||||||
--resource-name=polaris-dashboard
|
--resource-name=polaris-dashboard
|
||||||
```
|
```
|
||||||
|
|
||||||
Expected: `yes`
|
Expected: `yes`
|
||||||
|
|
||||||
4. **Verify RoleBinding subjects match:**
|
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.
|
**This is NOT an RBAC issue.** 404 means Polaris service doesn't exist.
|
||||||
|
|
||||||
**Check:**
|
**Check:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl -n polaris get svc polaris-dashboard
|
kubectl -n polaris get svc polaris-dashboard
|
||||||
```
|
```
|
||||||
@@ -510,14 +530,17 @@ If missing, install Polaris with dashboard enabled.
|
|||||||
**Possible causes:**
|
**Possible causes:**
|
||||||
|
|
||||||
1. **Wrong namespace in RoleBinding:**
|
1. **Wrong namespace in RoleBinding:**
|
||||||
|
|
||||||
- RoleBinding must be in `polaris` namespace (where the service is)
|
- RoleBinding must be in `polaris` namespace (where the service is)
|
||||||
- Common mistake: Creating RoleBinding in `kube-system`
|
- Common mistake: Creating RoleBinding in `kube-system`
|
||||||
|
|
||||||
2. **Wrong resourceName:**
|
2. **Wrong resourceName:**
|
||||||
|
|
||||||
- Must match service name exactly: `polaris-dashboard`
|
- Must match service name exactly: `polaris-dashboard`
|
||||||
- Check: `kubectl -n polaris get svc`
|
- Check: `kubectl -n polaris get svc`
|
||||||
|
|
||||||
3. **Browser caching old 403:**
|
3. **Browser caching old 403:**
|
||||||
|
|
||||||
- Hard refresh browser: Cmd+Shift+R (Mac) or Ctrl+Shift+R (Windows/Linux)
|
- Hard refresh browser: Cmd+Shift+R (Mac) or Ctrl+Shift+R (Windows/Linux)
|
||||||
|
|
||||||
4. **Token expired (OIDC mode):**
|
4. **Token expired (OIDC mode):**
|
||||||
@@ -529,6 +552,7 @@ If missing, install Polaris with dashboard enabled.
|
|||||||
### 1. Use Namespaced Roles (Not ClusterRoles)
|
### 1. Use Namespaced Roles (Not ClusterRoles)
|
||||||
|
|
||||||
✅ **Good:**
|
✅ **Good:**
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
kind: Role
|
kind: Role
|
||||||
metadata:
|
metadata:
|
||||||
@@ -536,6 +560,7 @@ metadata:
|
|||||||
```
|
```
|
||||||
|
|
||||||
❌ **Bad:**
|
❌ **Bad:**
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
kind: ClusterRole
|
kind: ClusterRole
|
||||||
# Grants access to all namespaces
|
# Grants access to all namespaces
|
||||||
@@ -546,13 +571,15 @@ kind: ClusterRole
|
|||||||
### 2. Always Specify resourceNames
|
### 2. Always Specify resourceNames
|
||||||
|
|
||||||
✅ **Good:**
|
✅ **Good:**
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
resourceNames: ["polaris-dashboard"]
|
resourceNames: ['polaris-dashboard']
|
||||||
```
|
```
|
||||||
|
|
||||||
❌ **Bad:**
|
❌ **Bad:**
|
||||||
|
|
||||||
```yaml
|
```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.
|
**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
|
### 3. Use Read-Only Verb
|
||||||
|
|
||||||
✅ **Good:**
|
✅ **Good:**
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
verbs: ["get"]
|
verbs: ['get']
|
||||||
```
|
```
|
||||||
|
|
||||||
❌ **Bad:**
|
❌ **Bad:**
|
||||||
|
|
||||||
```yaml
|
```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.
|
**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
|
### 5. Monitor Audit Logs
|
||||||
|
|
||||||
Set alerts for:
|
Set alerts for:
|
||||||
|
|
||||||
- Unusual access patterns (e.g., 403 spikes = permission issues)
|
- Unusual access patterns (e.g., 403 spikes = permission issues)
|
||||||
- High request volume (e.g., misconfigured refresh interval)
|
- High request volume (e.g., misconfigured refresh interval)
|
||||||
- Access from unexpected users (security monitoring)
|
- Access from unexpected users (security monitoring)
|
||||||
@@ -587,11 +617,12 @@ Set alerts for:
|
|||||||
### 6. Avoid Wildcard Permissions
|
### 6. Avoid Wildcard Permissions
|
||||||
|
|
||||||
❌ **Never do this:**
|
❌ **Never do this:**
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
rules:
|
rules:
|
||||||
- apiGroups: ["*"]
|
- apiGroups: ['*']
|
||||||
resources: ["*"]
|
resources: ['*']
|
||||||
verbs: ["*"]
|
verbs: ['*']
|
||||||
```
|
```
|
||||||
|
|
||||||
This grants cluster-admin equivalent permissions. Always use specific resources and verbs.
|
This grants cluster-admin equivalent permissions. Always use specific resources and verbs.
|
||||||
|
|||||||
Generated
+5
-4
@@ -1,12 +1,13 @@
|
|||||||
{
|
{
|
||||||
"name": "headlamp-polaris-plugin",
|
"name": "polaris",
|
||||||
"version": "0.2.0",
|
"version": "0.5.2",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "headlamp-polaris-plugin",
|
"name": "polaris",
|
||||||
"version": "0.2.0",
|
"version": "0.5.2",
|
||||||
|
"license": "Apache-2.0",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@kinvolk/headlamp-plugin": "^0.13.0",
|
"@kinvolk/headlamp-plugin": "^0.13.0",
|
||||||
"@playwright/test": "^1.58.2"
|
"@playwright/test": "^1.58.2"
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "polaris",
|
"name": "polaris",
|
||||||
"version": "0.5.0",
|
"version": "0.5.2",
|
||||||
"description": "Headlamp plugin for Fairwinds Polaris audit results",
|
"description": "Headlamp plugin for Fairwinds Polaris audit results",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||||
|
"extends": ["config:recommended"]
|
||||||
|
}
|
||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"extends": "@kinvolk/headlamp-plugin/config/plugins-tsconfig.json",
|
"extends": "@kinvolk/headlamp-plugin/config/plugins-tsconfig.json",
|
||||||
"compilerOptions": {
|
"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"]
|
"include": ["src"]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user