Compare commits

..

24 Commits

Author SHA1 Message Date
github-actions[bot] 0faa50cd9d chore: release v0.5.0 2026-02-13 14:32:56 +00:00
Chris Farhood de5feb68a3 feat: add maximize/minimize buttons to namespace drawer
Add toolbar with maximize/minimize and close buttons to namespace detail
drawer, matching Headlamp's native drawer behavior.

Changes:
- Add maximize/minimize button (⊡/⊟) to toggle drawer width
- Maximized width: calc(100vw - 240px) to avoid covering sidebar
- Normal width: 1000px
- Add smooth transition animation (0.3s)
- Add hover effects using MUI theme variables
- Improve close button styling with hover state
- Add accessibility labels and tooltips

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2026-02-13 09:32:03 -05:00
Chris Farhood 42df8dd7cc docs: add comprehensive CONTEXT.md reverse prompt
Add CONTEXT.md as a comprehensive reverse prompt for AI assistants working
on this project. Consolidates knowledge from CLAUDE.md and MEMORY.md into
a single, structured reference document.

Includes:
- Project overview and architecture
- Technology constraints and component patterns
- Development workflow and testing strategy
- CI/CD and release process
- Known issues and workarounds (corrects outdated watchPlugins info)
- Deployment patterns and RBAC requirements
- Quick reference commands and diagnosis guide
- Historical context for key decisions

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2026-02-12 19:44:48 -05:00
github-actions[bot] 3796d57d12 chore: release v0.4.1 2026-02-12 20:44:31 +00:00
Chris Farhood 88541bd328 chore: remove Gitea configuration and references
Removed all Gitea-related files and references:
- Deleted .gitea/workflows directory (ai-review, ci, e2e, release)
- Removed gitea MCP server from .mcp.json
- Updated CLAUDE.md to list GitHub instead of Gitea
- Updated CHANGELOG.md to remove Gitea migration note

All CI/CD now runs exclusively through GitHub Actions.

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2026-02-12 15:25:46 -05:00
Chris Farhood e884894840 ci: consolidate release workflow into single step
Merged prepare-release and release workflows into a single workflow
that handles everything in one job. This eliminates the need for
separate tokens or manual intervention.

Single workflow now:
- Validates version format
- Updates package.json and artifacthub-pkg.yml
- Builds and packages plugin
- Computes checksum
- Updates metadata with real checksum
- Commits all changes to main
- Creates and pushes tag
- Creates GitHub release with tarball

No more tag push triggers, no separate tokens needed.
Everything runs in one workflow_dispatch job.

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2026-02-12 15:20:17 -05:00
Chris Farhood 189ae50024 Revert "ci: use GitHub App token to enable automatic workflow triggering"
This reverts commit e62fba9cc1.
2026-02-12 15:19:22 -05:00
Chris Farhood e62fba9cc1 ci: use GitHub App token to enable automatic workflow triggering
The prepare-release workflow now uses GH_APP_TOKEN instead of
GITHUB_TOKEN to push commits and tags. This allows the tag push
to automatically trigger the release workflow without manual
intervention.

GITHUB_TOKEN cannot trigger other workflows due to GitHub's
security policy to prevent infinite workflow loops.

Added documentation in .github/GH_APP_TOKEN.md explaining the
token setup and requirements.

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2026-02-12 15:08:53 -05:00
github-actions[bot] 062ac72340 ci: update checksum for v0.4.0 2026-02-12 20:03:53 +00:00
github-actions[bot] 515758c829 chore: bump version to 0.4.0 2026-02-12 20:01:15 +00:00
Chris Farhood 40c4add01b fix: add contents write permission to prepare-release workflow 2026-02-12 15:00:55 -05:00
Chris Farhood cdc1ce0303 ci: overhaul release workflow to eliminate manual steps and tag manipulation
Replace complex draft/publish release workflow with clean two-workflow approach:

1. prepare-release.yaml (manual workflow_dispatch)
   - Validates version format
   - Updates package.json and artifacthub-pkg.yml
   - Commits to main
   - Creates and pushes tag
   - Triggers release workflow automatically

2. release.yaml (automatic on tag push)
   - Single build-and-release job
   - Creates GitHub release with tarball in one step (no draft/publish)
   - Separate update-metadata job runs after release
   - Updates checksum on main branch

Benefits:
- No manual tarball upload required
- No tag force-push anti-pattern
- No draft/publish asset attachment failures
- Clear separation of concerns
- Self-documenting workflow

Eliminates:
- Guard logic for infinite loop prevention
- Post-release tag manipulation
- Manual intervention after workflow "succeeds"
- Checksum chicken-and-egg problem

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2026-02-12 13:44:22 -05:00
Chris Farhood dd5a76e348 ci: update workflows to use local-ubuntu-latest runner
- Changed ci.yaml from ubuntu-latest to local-ubuntu-latest
- Changed release.yaml from ubuntu-latest to local-ubuntu-latest
- e2e.yaml already using k3s-animaniacs (correct)

This ensures all CI jobs run on on-prem runners instead of GitHub-hosted runners.

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2026-02-12 12:25:04 -05:00
Chris Farhood 3b6d7e6b6c chore: bump version to 0.3.12 2026-02-12 12:24:13 -05:00
Chris Farhood 0e5ff9b7b7 fix: add explicit GET method to API requests and make refresh interval reactive
- Add explicit method: 'GET' to ApiProxy.request() calls in polaris.ts and PolarisSettings.tsx
  for compatibility with Headlamp SDK
- Make refresh interval reactive by polling localStorage every second in PolarisDataContext
  so settings changes take effect immediately without page reload

Fixes connection test button and data refresh issues.

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2026-02-12 12:23:33 -05:00
Chris Farhood 8fab7828f4 ci: update checksum for manually uploaded v0.3.11 tarball 2026-02-12 12:02:59 -05:00
github-actions[bot] 1733eab21b ci: update artifact hub metadata for v0.3.11 2026-02-12 17:00:09 +00:00
Chris Farhood 44fe9ab749 Fix/update org references (#13)
* chore: bump version to 0.3.11

* fix: update owner references from cpfarhood to privilegedescalation

- Updated artifacthub-repo.yml owner
- Updated artifacthub-pkg.yml maintainer
- Updated package.json author

Part of organization migration from cpfarhood to privilegedescalation.
2026-02-12 11:57:10 -05:00
Chris Farhood 0b081246b0 docs: remove marketing fluff and emojis
- Remove navigation emojis from README and docs/README
- Remove "Made with ❤️ for the Kubernetes community" footer
- Remove checkmark/celebration emojis from quick-start guide
- Remove "(This!)" annotation from architecture diagrams
- Replace emoji references with plain text in features documentation
- Remove GOOD/BAD emojis from production deployment guide
- Simplify congratulations message

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2026-02-12 11:19:05 -05:00
Chris Farhood 765f081867 docs: standardize license to Apache-2.0 and update version references
- Change license from MIT to Apache-2.0 across all documentation to match package.json
- Update all version references from v0.3.4/v0.3.5 to v0.3.10
- Update tarball filenames from headlamp-polaris-plugin-*.tar.gz to polaris-0.3.10.tar.gz
- Update README.md license badge
- Update artifacthub-pkg.yml license field

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2026-02-12 11:13:27 -05:00
Chris Farhood d4fa1674dc chore: update repository references to privilegedescalation org
Repository transferred from cpfarhood to privilegedescalation organization.

Updated all references in:
- Configuration files (package.json, artifacthub-pkg.yml)
- Documentation (README, CONTRIBUTING, SECURITY, docs/)
- Workflow files

GitHub Actions workflows will continue to work as they use
${{ github.repository }} which auto-updates.

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2026-02-12 10:46:44 -05:00
github-actions[bot] 9655514066 ci: update artifact hub metadata for v0.3.10 2026-02-12 15:33:30 +00:00
Chris Farhood ece87a9824 chore: bump version to 0.3.10
Fixes:
- Drawer transparency using --mui-palette-background-default
- Plugin settings page blank due to name mismatch

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2026-02-12 10:32:51 -05:00
Chris Farhood 5adcca2eb9 fix: plugin settings name must match package.json
Changed registerPluginSettings from 'headlamp-polaris-plugin' to 'polaris'
to match package.json name field. Headlamp requires exact match for
settings registration, otherwise settings page renders blank.

Root cause: When package.json was renamed to 'polaris' in PR #9,
the settings registration was not updated.

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2026-02-12 10:32:20 -05:00
29 changed files with 836 additions and 232 deletions
+1 -1
View File
@@ -8,7 +8,7 @@ on:
jobs:
lint-and-test:
runs-on: ubuntu-latest
runs-on: local-ubuntu-latest
timeout-minutes: 10
steps:
+90 -108
View File
@@ -1,129 +1,111 @@
name: Release
on:
push:
tags:
- 'v*'
workflow_dispatch:
inputs:
version:
description: 'Version to release (without v prefix, e.g., 0.4.0)'
required: true
type: string
jobs:
release:
runs-on: ubuntu-latest
runs-on: local-ubuntu-latest
permissions:
contents: write
packages: write
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Check if release is already finalized
- name: Validate version format
run: |
VERSION=${GITHUB_REF_NAME#v}
TARBALL_URL="https://github.com/${{ github.repository }}/releases/download/${GITHUB_REF_NAME}/polaris-${VERSION}.tar.gz"
HTTP_CODE=$(curl -sL -o /tmp/release.tar.gz -w "%{http_code}" "$TARBALL_URL" 2>/dev/null)
if [ "$HTTP_CODE" = "200" ]; then
ACTUAL="sha256:$(sha256sum /tmp/release.tar.gz | awk '{print $1}')"
EXPECTED=$(grep 'archive-checksum' artifacthub-pkg.yml | awk '{print $2}')
echo "Release tarball checksum: $ACTUAL"
echo "Metadata checksum: $EXPECTED"
if [ "$ACTUAL" = "$EXPECTED" ]; then
echo "SKIP_BUILD=true" >> $GITHUB_ENV
echo "Checksums match - release is finalized, nothing to do"
fi
else
echo "No existing release (HTTP $HTTP_CODE) - will build"
fi
rm -f /tmp/release.tar.gz
- name: Setup Node.js
if: env.SKIP_BUILD != 'true'
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
if: env.SKIP_BUILD != 'true'
run: npm ci
- name: Build plugin
if: env.SKIP_BUILD != 'true'
run: npx @kinvolk/headlamp-plugin build
- name: Package tarball
if: env.SKIP_BUILD != 'true'
run: npx @kinvolk/headlamp-plugin package
- name: Validate tarball name matches package.json
if: env.SKIP_BUILD != 'true'
run: |
PACKAGE_NAME=$(jq -r '.name' package.json)
VERSION=${GITHUB_REF_NAME#v}
EXPECTED_TARBALL="${PACKAGE_NAME}-${VERSION}.tar.gz"
ACTUAL_TARBALL=$(ls *.tar.gz)
if [ "$EXPECTED_TARBALL" != "$ACTUAL_TARBALL" ]; then
echo "::error::Tarball name mismatch!"
echo "Expected: $EXPECTED_TARBALL"
echo "Actual: $ACTUAL_TARBALL"
echo "Update workflow to use correct tarball name pattern"
if ! echo "${{ inputs.version }}" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then
echo "::error::Version must be in format X.Y.Z (e.g., 0.4.0)"
exit 1
fi
echo "✓ Tarball name validation passed: $ACTUAL_TARBALL"
- name: Compute tarball checksum
if: env.SKIP_BUILD != 'true'
- name: Checkout
uses: actions/checkout@v4
- name: Configure git
run: |
TARBALL=$(ls *.tar.gz)
CHECKSUM=$(sha256sum "$TARBALL" | awk '{print $1}')
echo "TARBALL=$TARBALL" >> $GITHUB_ENV
echo "CHECKSUM=$CHECKSUM" >> $GITHUB_ENV
echo "Tarball: $TARBALL"
echo "Checksum: sha256:$CHECKSUM"
- name: Create draft release and upload tarball
if: env.SKIP_BUILD != 'true'
uses: softprops/action-gh-release@v2
with:
files: ${{ env.TARBALL }}
fail_on_unmatched_files: true
draft: true
prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Publish release
if: env.SKIP_BUILD != 'true'
uses: softprops/action-gh-release@v2
with:
draft: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Update metadata and align tag
if: env.SKIP_BUILD != 'true'
run: |
VERSION=${GITHUB_REF_NAME#v}
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
# Update metadata
git fetch origin main
git checkout origin/main -B temp-update
sed -i "s|headlamp/plugin/archive-checksum:.*|headlamp/plugin/archive-checksum: sha256:${CHECKSUM}|" artifacthub-pkg.yml
sed -i "s|headlamp/plugin/archive-url:.*|headlamp/plugin/archive-url: \"https://github.com/${{ github.repository }}/releases/download/${GITHUB_REF_NAME}/polaris-${VERSION}.tar.gz\"|" artifacthub-pkg.yml
- name: Update package.json version
run: |
jq --arg version "${{ inputs.version }}" '.version = $version' package.json > package.json.tmp
mv package.json.tmp package.json
- name: Update artifacthub-pkg.yml version
run: |
VERSION="${{ inputs.version }}"
RELEASE_URL="https://github.com/${{ github.repository }}/releases/download/v${VERSION}/polaris-${VERSION}.tar.gz"
sed -i "s|^version:.*|version: ${VERSION}|" artifacthub-pkg.yml
git add artifacthub-pkg.yml
sed -i "s|headlamp/plugin/archive-url:.*|headlamp/plugin/archive-url: \"${RELEASE_URL}\"|" artifacthub-pkg.yml
if ! git diff --cached --quiet; then
git commit -m "ci: update artifact hub metadata for ${GITHUB_REF_NAME}"
git push origin temp-update:main
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build plugin
run: npx @kinvolk/headlamp-plugin build
- name: Package plugin
run: npx @kinvolk/headlamp-plugin package
- name: Validate tarball name
run: |
EXPECTED="polaris-${{ inputs.version }}.tar.gz"
ACTUAL=$(ls *.tar.gz)
if [ "$EXPECTED" != "$ACTUAL" ]; then
echo "::error::Tarball name mismatch! Expected: $EXPECTED, Got: $ACTUAL"
exit 1
fi
echo "✓ Tarball name validated: $ACTUAL"
# Force-move tag to the commit with correct checksum.
# This triggers a new CI run, but the guard step will detect
# that the release checksum already matches and skip the build.
git tag -f ${GITHUB_REF_NAME}
git push -f origin ${GITHUB_REF_NAME}
echo "Tag ${GITHUB_REF_NAME} aligned with updated metadata"
- name: Compute checksum
id: compute_checksum
run: |
TARBALL="polaris-${{ inputs.version }}.tar.gz"
CHECKSUM=$(sha256sum "$TARBALL" | awk '{print $1}')
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
- name: Commit version bump and metadata
run: |
git add package.json artifacthub-pkg.yml
git commit -m "chore: release v${{ inputs.version }}"
git push origin main
- name: Create and push tag
run: |
git tag "v${{ inputs.version }}"
git push origin "v${{ inputs.version }}"
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: "v${{ inputs.version }}"
files: polaris-${{ inputs.version }}.tar.gz
fail_on_unmatched_files: true
draft: false
prerelease: false
generate_release_notes: true
env:
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"
+31 -32
View File
@@ -31,7 +31,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- App bar badge, settings buttons, and UI elements now use theme-aware CSS variables
### Infrastructure
- Migrated from Gitea to GitHub Actions exclusively
- Added CI workflow for lint, type-check, build, and test
- Enhanced E2E testing documentation with comprehensive guides
- Added documentation-engineer subagent
@@ -243,34 +242,34 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Automated release workflow
- Basic CI/CD pipeline
[Unreleased]: https://github.com/cpfarhood/headlamp-polaris-plugin/compare/v0.3.5...HEAD
[0.3.5]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.3.5
[0.3.4]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.3.4
[0.3.3]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.3.3
[0.3.2]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.3.2
[0.3.1]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.3.1
[0.3.0]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.3.0
[0.2.5]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.2.5
[0.2.4]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.2.4
[0.2.3]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.2.3
[0.2.2]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.2.2
[0.2.1]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.2.1
[0.2.0]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.2.0
[0.1.7]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.1.7
[0.1.6]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.1.6
[0.1.5]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.1.5
[0.1.4]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.1.4
[0.1.3]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.1.3
[0.1.2]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.1.2
[0.1.1]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.1.1
[0.1.0]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.1.0
[0.0.10]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.0.10
[0.0.9]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.0.9
[0.0.8]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.0.8
[0.0.7]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.0.7
[0.0.6]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.0.6
[0.0.5]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.0.5
[0.0.4]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.0.4
[0.0.3]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.0.3
[0.0.2]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.0.2
[0.0.1]: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/tag/v0.0.1
[Unreleased]: https://github.com/privilegedescalation/headlamp-polaris-plugin/compare/v0.3.5...HEAD
[0.3.5]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.3.5
[0.3.4]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.3.4
[0.3.3]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.3.3
[0.3.2]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.3.2
[0.3.1]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.3.1
[0.3.0]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.3.0
[0.2.5]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.2.5
[0.2.4]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.2.4
[0.2.3]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.2.3
[0.2.2]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.2.2
[0.2.1]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.2.1
[0.2.0]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.2.0
[0.1.7]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.1.7
[0.1.6]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.1.6
[0.1.5]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.1.5
[0.1.4]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.1.4
[0.1.3]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.1.3
[0.1.2]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.1.2
[0.1.1]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.1.1
[0.1.0]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.1.0
[0.0.10]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.0.10
[0.0.9]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.0.9
[0.0.8]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.0.8
[0.0.7]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.0.7
[0.0.6]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.0.6
[0.0.5]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.0.5
[0.0.4]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.0.4
[0.0.3]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.0.3
[0.0.2]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.0.2
[0.0.1]: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/tag/v0.0.1
+575
View File
@@ -0,0 +1,575 @@
# CONTEXT.md - Headlamp Polaris Plugin
**Purpose**: Comprehensive reverse prompt for AI assistants working on this project.
---
## Project Overview
The Headlamp Polaris Plugin surfaces [Fairwinds Polaris](https://www.fairwinds.com/polaris) audit results directly inside the [Headlamp](https://headlamp.dev) Kubernetes UI. It provides a read-only dashboard showing cluster-wide security, reliability, and efficiency scores derived from Polaris policy checks.
- **Stack**: React + TypeScript plugin for Headlamp (v0.26+)
- **Data Source**: Polaris dashboard API via Kubernetes service proxy (read-only)
- **Current Version**: v0.4.1
- **Key Constraint**: No direct Kubernetes resource access - all data fetched through service proxy
## Architecture & Data Flow
### Component Hierarchy
```
src/index.tsx # Entry point: registers routes, sidebar, settings
├── PolarisDataContext.tsx # Shared data fetch with auto-refresh
├── components/
│ ├── DashboardView.tsx # Overview (score, checks, top issues)
│ ├── NamespacesListView.tsx # Namespace list with scores
│ ├── NamespaceDetailView.tsx # Per-namespace drill-down (drawer)
│ ├── PolarisSettings.tsx # Settings (refresh interval, URL, test)
│ ├── AppBarScoreBadge.tsx # Cluster score badge in top nav
│ └── InlineAuditSection.tsx # Injected into workload detail views
└── api/
└── polaris.ts # Types, hooks, utilities
```
### Data Source
- **Service Proxy Path**: `/api/v1/namespaces/polaris/services/polaris-dashboard:80/proxy/results.json`
- **Schema**: `AuditData` with `ClusterInfo`, `Results[]` containing nested `PodResult` and `ContainerResults`
- **Method**: `ApiProxy.request()` from Headlamp plugin SDK (handles K8s API auth automatically)
### State Management
- **Pattern**: React Context (see `src/api/PolarisDataContext.tsx`)
- **Rationale**: ADR-001 - Prevents duplicate API calls when multiple components need same data
- **Auto-refresh**: User-configurable interval (1/5/10/30 min, default 5 min)
- **Storage**: Refresh interval and dashboard URL stored in `localStorage`
### Score Computation
```typescript
// Formula: (pass / total) * 100, rounded to nearest integer
function computeScore(counts: ResultCounts): number {
if (counts.total === 0) return 0;
return Math.round((counts.pass / counts.total) * 100);
}
```
## Technology Constraints
### ⚠️ CRITICAL: Headlamp Components Only
**MUST** use `@kinvolk/headlamp-plugin/lib/CommonComponents`
**NEVER** import from `@mui/material` or `@mui/icons-material`
**Why**: Historical issue (v0.3.2) - MUI imports caused plugin load failures. Headlamp provides all needed components as re-exports.
```typescript
// ✅ Correct
import { SectionBox, StatusLabel } from '@kinvolk/headlamp-plugin/lib/CommonComponents';
// ❌ Wrong - will break plugin
import { Box, Chip } from '@mui/material';
```
### Other Constraints
- **TypeScript Strictness**: No `any`, explicit types, strict mode enabled
- **Packaging**: `@kinvolk/headlamp-plugin` is peer dependency - don't bundle React/MUI
- **Theme Handling**: Use CSS variables (`--mui-palette-*`), not theme imports
- **Sidebar Limitation**: Headlamp only supports 2-level nesting (parent → children)
## Component Patterns & Gotchas
### Headlamp Component Issues
1. **StatusLabel with empty status**
```typescript
// ❌ Renders near-invisible (muted background)
<StatusLabel status="">{value}</StatusLabel>
// ✅ Use plain String() for neutral values
<span>{String(value)}</span>
```
2. **Link component crashes on plugin routes**
```typescript
// ❌ Headlamp Link crashes on plugin-registered routes
import { Link } from '@kinvolk/headlamp-plugin/lib/CommonComponents';
// ✅ Use react-router-dom Link with Router.createRouteURL
import { Link } from 'react-router-dom';
import { Router } from '@kinvolk/headlamp-plugin/lib';
<Link to={Router.createRouteURL('/polaris/namespaces')}>View</Link>
```
3. **Visual components that work well**
- `PercentageCircle` - Great for score display
- `PercentageBar` - Great for check distribution
- `SimpleTable` - Fast, clean tables
- `NameValueTable` - Key-value pairs
- `SectionBox` - Card containers with titles
### Code Conventions
- **Functional Components**: Always use function components with hooks
- **Named Exports**: Prefer named exports over default exports
- **Props Interfaces**: Define as TypeScript interfaces, not inline types
- **Import Order**: React → third-party → Headlamp → local (auto-sorted by eslint)
## RBAC & Security
### Minimal Permission Required
The plugin requires **only** this RBAC permission:
| Verb | API Group | Resource | Resource Name | Namespace |
|------|-----------|----------|---------------|-----------|
| `get` | `""` (core) | `services/proxy` | `polaris-dashboard` | `polaris` |
### Example Role
```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: polaris-proxy-reader
namespace: polaris
rules:
- apiGroups: [""]
resources: ["services/proxy"]
resourceNames: ["polaris-dashboard"]
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: headlamp-polaris-proxy
namespace: polaris
subjects:
- kind: ServiceAccount
name: headlamp
namespace: kube-system
roleRef:
kind: Role
name: polaris-proxy-reader
apiGroup: rbac.authorization.k8s.io
```
### Security Notes
- **Namespaced Role**: MUST be namespaced Role, NOT ClusterRole
- **ResourceNames Required**: Always specify `resourceNames: ["polaris-dashboard"]`
- **No Write Operations**: Plugin only performs GET, never create/update/delete
- **Token-Auth Mode**: When Headlamp uses user tokens, each user needs the RoleBinding
- **Network Policy**: If enforced, allow API server → `polaris-dashboard:80` ingress
- **Audit Logging**: Every proxy request logged as K8s API audit event
## Development Workflow
### Commands
```bash
# Install dependencies
npm install
# Start development mode (hot reload at localhost:4466)
npm start
# Build plugin
npm run build
# Create tarball for distribution
npm run package
# Type-check without emitting
npm run tsc
# Lint
npm run lint
# Run unit tests
npm test
# Run E2E tests (requires cluster access)
npm run e2e
# Format code
npm run format
# Check formatting (CI)
npm run format:check
```
### Branching Strategy
- ✅ **ALWAYS use feature branches** for code changes (`feat/*`, `fix/*`, `docs/*`)
- ✅ **MAY push directly to main** for: documentation-only changes, version bump commits
- ❌ **NEVER push code changes directly to main**
### Commit Convention
Use Conventional Commits:
- `feat:` - New feature
- `fix:` - Bug fix
- `docs:` - Documentation only
- `chore:` - Maintenance (deps, config)
- `test:` - Test changes
- `ci:` - CI/CD changes
### PR Process
All PRs must pass:
1. Build (`npm run build`)
2. Lint (`npm run lint`)
3. Type-check (`npm run tsc`)
4. Unit tests (`npm test`)
5. Format check (`npm run format:check`)
**Before committing**: Always run `npx prettier --write src/`
## Testing Strategy
### Unit Tests (Vitest)
```bash
npm test # Run once
npm run test:watch # Watch mode
```
- **Framework**: Vitest with jsdom environment
- **Test files**: `*.test.ts`, `*.test.tsx` in `src/`
- **Setup**: `vitest.setup.ts` with `@testing-library/jest-dom`
- **Coverage**: Focus on meaningful tests, not just numbers
- **Test utilities**: `src/test-utils.tsx` provides test wrapper with context
### E2E Tests (Playwright)
```bash
npm run e2e # Headless
npm run e2e:headed # With browser UI
```
- **Framework**: Playwright
- **Test files**: `e2e/*.spec.ts`
- `polaris.spec.ts` - Sidebar, overview, namespaces, detail drawer
- `settings.spec.ts` - Plugin settings page
- `appbar.spec.ts` - App bar score badge
- **Auth**: Supports both OIDC (Authentik) and token-based auth (see `e2e/auth.setup.ts`)
- **CI**: Runs on GitHub Actions with `k3s-animaniacs` runner
### Local E2E Setup
```bash
# Token-based auth
export HEADLAMP_TOKEN=$(kubectl create token headlamp -n kube-system --duration=24h)
npm run e2e
# OIDC auth (Authentik)
export AUTHENTIK_USERNAME=your-username
export AUTHENTIK_PASSWORD=your-password
npm run e2e
```
## CI/CD & Release
### CI Workflow (`.github/workflows/ci.yaml`)
Runs on push to main and all PRs:
1. Checkout
2. `npm ci`
3. `npm run build`
4. `npm run lint`
5. `npm run tsc`
6. `npm run format:check`
7. `npm test`
Runner: `local-ubuntu-latest`
### E2E Workflow (`.github/workflows/e2e.yaml`)
Runs on push, PR, and manual trigger:
1. Checkout
2. `npm ci`
3. `npm run e2e`
Runner: `k3s-animaniacs` (has cluster access)
Requires: `HEADLAMP_URL`, `HEADLAMP_TOKEN` or `AUTHENTIK_USERNAME`/`AUTHENTIK_PASSWORD`
### Release Workflow (`.github/workflows/release.yaml`)
**Manual trigger** via workflow_dispatch with version input:
```bash
# Via GitHub UI or CLI
gh workflow run release.yaml -f version=0.4.2
```
Steps:
1. Validate version format (semver)
2. Bump `package.json` + `artifacthub-pkg.yml`
3. Build plugin
4. Package tarball
5. Compute SHA256 checksum
6. Commit version bump
7. Create git tag
8. Create GitHub release
9. Upload tarball to release
**Guard**: Skips if checksum already matches (prevents infinite loop)
**Post-release**: ArtifactHub pulls metadata every 30 min (no webhook, pull-based)
### Version Bump Requirements
**ALWAYS bump both files in the same commit**:
- `package.json` - `version` field
- `artifacthub-pkg.yml` - `version` field + `digest` (checksum) + `archive.url`
## Known Issues & Workarounds
### ⚠️ Headlamp v0.39.0 Known Issues
**AutoSizer JavaScript Error**
- **Symptom**: Console shows `TypeError: undefined is not an object (evaluating 'io.AutoSizer')`
- **Impact**: Cosmetic error in Settings page, doesn't break functionality
- **Root Cause**: Headlamp core bug, not plugin-related
- **Workaround**: None needed, can be ignored
**Plugin Loading (RESOLVED)**
- **Old Issue**: Previously thought `config.watchPlugins: false` was required
- **Resolution**: Plugins load correctly with default `watchPlugins: true`
- **Note**: If you see old docs mentioning `watchPlugins: false`, ignore them
### Polaris Dashboard Behavior
**Stale Audit Data**
- **Symptom**: Plugin shows old audit timestamp
- **Root Cause**: Polaris dashboard runs audit once at pod startup, then caches results
- **Does NOT**: Continuously re-audit in real-time
- **Workaround**: Restart Polaris pods for fresh data
```bash
kubectl rollout restart deployment -n polaris polaris-dashboard
```
- **Load Balancing**: Service balances across multiple pods - each may have different audit timestamps
- **Plugin Auto-Refresh**: Works correctly - just fetches whatever Polaris currently has cached
### Skipped Count Limitation
**What It Shows**:
- Only checks with `Severity: "ignore"` in Polaris API response
- Does NOT include annotation-based exemptions (`polaris.fairwinds.com/*-exempt`)
**Why**:
- Polaris omits exempted checks from `results.json`
- Plugin has no access to raw K8s resources to compute exemptions
- By design: service proxy limitation
**Workaround**:
- Link to native Polaris dashboard for full exemption count
- UI tooltip explains this limitation
## Deployment Patterns
### Plugin Manager (Recommended)
Install via Headlamp UI (Settings → Plugins → Catalog) or Helm values:
```yaml
pluginsManager:
enabled: true
configContent: |
plugins:
- name: polaris
source: https://artifacthub.io/packages/headlamp/polaris/headlamp-polaris-plugin
```
### Sidecar Container (Alternative)
```yaml
spec:
containers:
- name: headlamp
# ... main container
- name: headlamp-plugin
image: node:lts-alpine
command:
- /bin/sh
- -c
- |
npx @headlamp-k8s/pluginctl@latest install \
--config /config/plugin.yml \
--folderName /headlamp/plugins \
--watch
volumeMounts:
- name: plugins-dir
mountPath: /headlamp/plugins
- name: plugin-config
mountPath: /config
volumes:
- name: plugins-dir
emptyDir: {}
- name: plugin-config
configMap:
name: headlamp-plugin-config
```
### Manual Tarball
```bash
# Download release
wget https://github.com/cpfarhood/headlamp-polaris-plugin/releases/download/v0.4.1/headlamp-polaris-plugin-0.4.1.tgz
# Extract to plugin directory
tar -xzf headlamp-polaris-plugin-0.4.1.tgz -C /headlamp/plugins/
# Restart Headlamp
kubectl rollout restart deployment headlamp -n kube-system
```
## Project Files Reference
```
src/
index.tsx # Entry point: registers sidebar, routes, settings, etc.
api/
polaris.ts # Core types, usePolarisData hook, utilities
PolarisDataContext.tsx # React Context provider for shared data
components/
DashboardView.tsx # Overview page (score, checks, top issues)
NamespacesListView.tsx # Namespace table with scores
NamespaceDetailView.tsx # Drawer panel with per-namespace drill-down
PolarisSettings.tsx # Settings page (refresh, URL, test)
AppBarScoreBadge.tsx # Cluster score chip in top nav bar
InlineAuditSection.tsx # Injected into resource detail views
test-utils.tsx # Test helpers (wrapper with context)
.github/workflows/
ci.yaml # Lint, type-check, build, test
e2e.yaml # Playwright E2E tests
release.yaml # Automated releases
e2e/ # Playwright tests
polaris.spec.ts # Main plugin functionality
settings.spec.ts # Settings page
appbar.spec.ts # App bar badge
auth.setup.ts # OIDC/token auth setup
docs/ # Comprehensive documentation
architecture/ # Overview, design decisions, ADRs
deployment/ # Helm, Kubernetes, production guides
troubleshooting/ # Common issues, RBAC, network problems
getting-started/ # Quick start, prerequisites, installation
package.json # Version, scripts, dependencies
artifacthub-pkg.yml # ArtifactHub metadata (version, checksum)
tsconfig.json # Extends @kinvolk/headlamp-plugin config
vitest.config.mts # Vitest config (jsdom, excludes e2e/)
.eslintrc.js # Extends @headlamp-k8s/eslint-config
.prettierrc.js # Uses @headlamp-k8s prettier config
```
## MCP Servers (Claude Code)
- **GitHub**: Source control (`github-mcp-server`), repo at `cpfarhood/headlamp-polaris-plugin`
- **Kubernetes (local)**: Cluster access via `kubernetes-mcp-server`
- **Flux (local)**: Flux Operator access via `flux-operator-mcp`
- **Playwright**: Browser automation via `@playwright/mcp`
## Common Tasks Quick Reference
```bash
# Start development
npm install && npm start
# Run all checks before PR
npm run build && npm run lint && npm run tsc && npm test && npm run format
# Create release (maintainers only)
# 1. Edit CHANGELOG.md
# 2. Trigger release workflow:
gh workflow run release.yaml -f version=0.4.2
# Run E2E tests locally
export HEADLAMP_TOKEN=$(kubectl create token headlamp -n kube-system --duration=24h)
npm run e2e
# Fix formatting issues
npx prettier --write src/
# Check Polaris audit freshness
kubectl get --raw "/api/v1/namespaces/polaris/services/polaris-dashboard:80/proxy/results.json" | jq -r '.AuditTime'
# Restart Polaris for fresh audit
kubectl rollout restart deployment -n polaris polaris-dashboard
```
## Anti-Patterns (What NOT to Do)
- ❌ Import from `@mui/material` or `@mui/icons-material` → breaks plugin
- ❌ Use `any` type → strict TypeScript required
- ❌ Push code changes directly to main → always use feature branches
- ❌ Grant broader RBAC than `get services/proxy` → security risk
- ❌ Use ClusterRole instead of namespaced Role → violates least privilege
- ❌ Forget to run `npx prettier --write src/` → CI will fail
- ❌ Use inline styles without CSS variables → breaks dark mode
- ❌ Try to query K8s resources directly → plugin only has service proxy access
- ❌ Import Headlamp `Link` for plugin routes → use react-router-dom `Link` + `Router.createRouteURL()`
- ❌ Assume Polaris continuously re-audits → it only audits at pod startup
## Quick Diagnosis Guide
```
Symptom: Plugin not in sidebar
→ Check: Hard refresh browser (Cmd+Shift+R / Ctrl+Shift+R)
→ Check: Plugin installed? kubectl get configmap headlamp-plugin-config -n kube-system
Symptom: 403 Access Denied
→ Check: RBAC binding exists? kubectl get role,rolebinding -n polaris
→ Fix: Apply RBAC example from docs/deployment/rbac.md
Symptom: 404 or 503
→ Check: Polaris installed? kubectl get pods -n polaris
→ Check: Service exists? kubectl get svc polaris-dashboard -n polaris
Symptom: Stale audit data
→ Fix: kubectl rollout restart deployment -n polaris polaris-dashboard
→ Verify: Check AuditTime in UI matches current date
Symptom: Settings page empty or broken
→ Check: Plugin version ≥ v0.3.3?
→ Fix: Upgrade plugin and hard refresh browser
Symptom: CI prettier check fails
→ Fix: npx prettier --write src/
→ Commit: Include formatting fixes in your PR
Symptom: Dark mode white backgrounds
→ Check: Plugin version ≥ v0.3.5?
→ Fix: Upgrade and hard refresh browser
```
## Historical Context
### Why Service Proxy Instead of ConfigMaps?
Early versions (< v0.0.10) incorrectly documented ConfigMap RBAC. The plugin **never** accessed ConfigMaps - it always used the service proxy. This was clarified in v0.0.10.
### Why No MUI Imports?
v0.3.2 removed direct MUI imports because they caused plugin load failures. Headlamp provides all needed MUI components as re-exports through `CommonComponents`.
### Why React Context?
ADR-001 documents the switch to React Context. Before v0.3.0, each component called `usePolarisData()` independently, causing duplicate API requests. Context ensures a single shared fetch.
### Why No Continuous Polaris Audits?
Polaris dashboard mode runs a one-time audit at pod startup and caches results. This is by design in Polaris itself. For continuous auditing, Polaris would need to be configured in webhook mode (admission controller), which is a different deployment pattern.
---
**Last Updated**: 2026-02-12
**Version**: v0.4.1
**Target Headlamp**: v0.26+
**Target Polaris**: v9.x
+3 -3
View File
@@ -447,11 +447,11 @@ For testing before stable release:
## Getting Help
- **Questions:** Open a [GitHub Discussion](https://github.com/cpfarhood/headlamp-polaris-plugin/discussions)
- **Bugs:** Open a [GitHub Issue](https://github.com/cpfarhood/headlamp-polaris-plugin/issues)
- **Questions:** Open a [GitHub Discussion](https://github.com/privilegedescalation/headlamp-polaris-plugin/discussions)
- **Bugs:** Open a [GitHub Issue](https://github.com/privilegedescalation/headlamp-polaris-plugin/issues)
- **E2E Testing:** See [e2e/README.md](e2e/README.md)
- **Architecture:** See [CLAUDE.md](CLAUDE.md)
## License
By contributing, you agree that your contributions will be licensed under the MIT License.
By contributing, you agree that your contributions will be licensed under the Apache-2.0 License.
+13 -16
View File
@@ -1,13 +1,13 @@
# Headlamp Polaris Plugin
[![Artifact Hub](https://img.shields.io/endpoint?url=https://artifacthub.io/badge/repository/polaris)](https://artifacthub.io/packages/headlamp/polaris/headlamp-polaris-plugin)
[![CI](https://github.com/cpfarhood/headlamp-polaris-plugin/actions/workflows/ci.yaml/badge.svg)](https://github.com/cpfarhood/headlamp-polaris-plugin/actions/workflows/ci.yaml)
[![E2E Tests](https://github.com/cpfarhood/headlamp-polaris-plugin/actions/workflows/e2e.yaml/badge.svg)](https://github.com/cpfarhood/headlamp-polaris-plugin/actions/workflows/e2e.yaml)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![CI](https://github.com/privilegedescalation/headlamp-polaris-plugin/actions/workflows/ci.yaml/badge.svg)](https://github.com/privilegedescalation/headlamp-polaris-plugin/actions/workflows/ci.yaml)
[![E2E Tests](https://github.com/privilegedescalation/headlamp-polaris-plugin/actions/workflows/e2e.yaml/badge.svg)](https://github.com/privilegedescalation/headlamp-polaris-plugin/actions/workflows/e2e.yaml)
[![License: Apache-2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
A [Headlamp](https://headlamp.dev/) plugin that surfaces [Fairwinds Polaris](https://polaris.docs.fairwinds.com/) audit results directly in the Headlamp UI.
**📚 [Documentation](#documentation) | 🚀 [Installation](#installing) | 🔒 [Security](#rbac--security-setup) | 🛠️ [Development](#development)**
**[Documentation](#documentation) | [Installation](#installing) | [Security](#rbac--security-setup) | [Development](#development)**
## What It Does
@@ -62,7 +62,7 @@ config:
pluginsManager:
sources:
- name: headlamp-polaris-plugin
url: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/download/v0.3.5/headlamp-polaris-plugin-0.3.5.tar.gz
url: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/download/v0.3.10/polaris-0.3.10.tar.gz
```
Or install via the Headlamp UI:
@@ -96,17 +96,17 @@ sidecars:
### Option 3: Manual Tarball Install
Download the `.tar.gz` from the [GitHub releases page](https://github.com/cpfarhood/headlamp-polaris-plugin/releases), then extract into Headlamp's plugin directory:
Download the `.tar.gz` from the [GitHub releases page](https://github.com/privilegedescalation/headlamp-polaris-plugin/releases), then extract into Headlamp's plugin directory:
```bash
wget https://github.com/cpfarhood/headlamp-polaris-plugin/releases/download/v0.3.5/headlamp-polaris-plugin-0.3.5.tar.gz
tar xzf headlamp-polaris-plugin-0.3.5.tar.gz -C /headlamp/plugins/
wget https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/download/v0.3.10/polaris-0.3.10.tar.gz
tar xzf polaris-0.3.10.tar.gz -C /headlamp/plugins/
```
### Option 4: Build from Source
```bash
git clone https://github.com/cpfarhood/headlamp-polaris-plugin.git
git clone https://github.com/privilegedescalation/headlamp-polaris-plugin.git
cd headlamp-polaris-plugin
npm install
npm run build
@@ -172,7 +172,7 @@ Every proxied request is recorded in Kubernetes API audit logs as a `get` on `se
## Documentation
📚 **[Complete Documentation](docs/README.md)** - Documentation hub with all guides
**[Complete Documentation](docs/README.md)** - Documentation hub with all guides
### Quick Links
@@ -214,7 +214,7 @@ Quick reference:
```bash
# Clone repository
git clone https://github.com/cpfarhood/headlamp-polaris-plugin.git
git clone https://github.com/privilegedescalation/headlamp-polaris-plugin.git
cd headlamp-polaris-plugin
# Install dependencies
@@ -365,15 +365,12 @@ Contributions are welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md) for:
## Links
- **[GitHub Repository](https://github.com/cpfarhood/headlamp-polaris-plugin)** - Source code, issues, releases
- **[GitHub Repository](https://github.com/privilegedescalation/headlamp-polaris-plugin)** - Source code, issues, releases
- **[Artifact Hub](https://artifacthub.io/packages/headlamp/polaris/headlamp-polaris-plugin)** - Plugin catalog listing
- **[Headlamp](https://headlamp.dev/)** - Kubernetes web UI
- **[Fairwinds Polaris](https://polaris.docs.fairwinds.com/)** - Kubernetes best practices audit tool
## License
[MIT License](LICENSE) - see LICENSE file for details.
[Apache-2.0 License](LICENSE) - see LICENSE file for details.
---
**Made with ❤️ for the Kubernetes community**
+6 -6
View File
@@ -194,7 +194,7 @@ We apply security updates to the latest release only. Please ensure you are runn
If you discover a security vulnerability in this plugin, please report it via:
1. **GitHub Security Advisories**: [Report a vulnerability](https://github.com/cpfarhood/headlamp-polaris-plugin/security/advisories/new)
1. **GitHub Security Advisories**: [Report a vulnerability](https://github.com/privilegedescalation/headlamp-polaris-plugin/security/advisories/new)
2. **Email**: Create a GitHub issue and mark it as "security" if advisories are not available
**Please do not:**
@@ -334,7 +334,7 @@ The plugin processes only technical metadata (resource names, namespaces, check
Subscribe to security updates via:
1. **GitHub Watch**: Click "Watch" → "Custom" → "Security alerts"
2. **GitHub Releases**: Monitor [releases page](https://github.com/cpfarhood/headlamp-polaris-plugin/releases)
2. **GitHub Releases**: Monitor [releases page](https://github.com/privilegedescalation/headlamp-polaris-plugin/releases)
3. **ArtifactHub**: Follow package at [ArtifactHub](https://artifacthub.io/packages/headlamp/headlamp-polaris-plugin/headlamp-polaris-plugin)
### Security Patch Process
@@ -349,10 +349,10 @@ When a security vulnerability is identified:
## Contact
- **Security Issues**: [GitHub Security Advisories](https://github.com/cpfarhood/headlamp-polaris-plugin/security/advisories)
- **General Questions**: [GitHub Discussions](https://github.com/cpfarhood/headlamp-polaris-plugin/discussions)
- **Bug Reports**: [GitHub Issues](https://github.com/cpfarhood/headlamp-polaris-plugin/issues)
- **Security Issues**: [GitHub Security Advisories](https://github.com/privilegedescalation/headlamp-polaris-plugin/security/advisories)
- **General Questions**: [GitHub Discussions](https://github.com/privilegedescalation/headlamp-polaris-plugin/discussions)
- **Bug Reports**: [GitHub Issues](https://github.com/privilegedescalation/headlamp-polaris-plugin/issues)
## License
This plugin is provided under the MIT License. See [LICENSE](LICENSE) for details.
This plugin is provided under the Apache-2.0 License. See [LICENSE](LICENSE) for details.
+7 -7
View File
@@ -1,4 +1,4 @@
version: 0.3.9
version: 0.5.0
name: headlamp-polaris-plugin
displayName: Polaris
createdAt: "2026-02-05T19:00:00Z"
@@ -9,8 +9,8 @@ description: >-
read-only via the Kubernetes service proxy to the Polaris dashboard.
Requires a Role granting `get` on `services/proxy` for the
`polaris-dashboard` service in the `polaris` namespace.
license: MIT
homeURL: "https://github.com/cpfarhood/headlamp-polaris-plugin"
license: Apache-2.0
homeURL: "https://github.com/privilegedescalation/headlamp-polaris-plugin"
category: security
keywords:
- polaris
@@ -21,14 +21,14 @@ keywords:
- kubernetes
links:
- name: Source
url: "https://github.com/cpfarhood/headlamp-polaris-plugin"
url: "https://github.com/privilegedescalation/headlamp-polaris-plugin"
- name: Polaris
url: "https://polaris.docs.fairwinds.com/"
maintainers:
- name: cpfarhood
- name: privilegedescalation
email: "chris@farhood.org"
annotations:
headlamp/plugin/archive-url: "https://github.com/cpfarhood/headlamp-polaris-plugin/releases/download/v0.3.9/polaris-0.3.9.tar.gz"
headlamp/plugin/archive-url: "https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/download/v0.5.0/polaris-0.5.0.tar.gz"
headlamp/plugin/version-compat: ">=0.26"
headlamp/plugin/archive-checksum: sha256:4447bff847623dbab0d0cde739f17e5b2888bf95e1f152fa217274004775823d
headlamp/plugin/archive-checksum: sha256:d00b9d068a32f01cf1584465c24e96b66eec60ea80be14f07433530780584451
headlamp/plugin/distro-compat: in-cluster
+1 -1
View File
@@ -1,4 +1,4 @@
repositoryID: fc3397f6-a75a-4950-ab50-da75c08a8089
owners:
- name: cpfarhood
- name: privilegedescalation
email: "chris@farhood.org"
+2 -1
View File
@@ -104,6 +104,7 @@ Additional considerations:
## MCP Servers
The project has MCP server integrations configured in `.mcp.json`:
- **Gitea** (git.farh.net): Source control via `gitea-mcp-server`
- **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`
+1 -1
View File
@@ -43,7 +43,7 @@ The Headlamp Polaris Plugin is a **read-only dashboard** that surfaces Fairwinds
│ └────────┬────────┘ │
│ │ │
│ ┌─────────────▼──────────────┐ │
│ │ Polaris Plugin (This!) │ │
│ │ Polaris Plugin │ │
│ ├────────────────────────────┤ │
│ │ • registerSidebarEntry │ │
│ │ • registerRoute │ │
+1 -1
View File
@@ -113,7 +113,7 @@ data:
plugin.yml: |
- name: headlamp-polaris-plugin
version: 0.3.4
url: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/download/v0.3.4/headlamp-polaris-plugin-0.3.4.tar.gz
url: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/download/v0.3.10/polaris-0.3.10.tar.gz
```
### Method 3: Volume Mount (Development)
+1 -1
View File
@@ -54,7 +54,7 @@ README.md # Main entry point with badges, quick links
CHANGELOG.md # Keep a Changelog format, semantic versioning
CONTRIBUTING.md # Development workflow, branching, PR process
SECURITY.md # Security model, vulnerability reporting, RBAC
LICENSE # MIT License
LICENSE # Apache-2.0 License
package.json # Plugin metadata
```
+6 -6
View File
@@ -4,11 +4,11 @@ Central hub for Headlamp Polaris Plugin documentation.
## Quick Links
- 🚀 [Quick Start](getting-started/quick-start.md)
- 📖 [Installation Guide](getting-started/installation.md)
- 🔧 [Troubleshooting](troubleshooting/README.md)
- 🏗️ [Architecture](architecture/overview.md)
- 💻 [Development](development/workflow.md)
- [Quick Start](getting-started/quick-start.md)
- [Installation Guide](getting-started/installation.md)
- [Troubleshooting](troubleshooting/README.md)
- [Architecture](architecture/overview.md)
- [Development](development/workflow.md)
## Getting Started
@@ -68,4 +68,4 @@ Production deployment guides:
---
**Need help?** Open an issue on [GitHub](https://github.com/cpfarhood/headlamp-polaris-plugin/issues) or check [CONTRIBUTING.md](../CONTRIBUTING.md) for development guidelines.
**Need help?** Open an issue on [GitHub](https://github.com/privilegedescalation/headlamp-polaris-plugin/issues) or check [CONTRIBUTING.md](../CONTRIBUTING.md) for development guidelines.
+3 -3
View File
@@ -572,7 +572,7 @@ kubectl get configmap headlamp-plugin-config -n kube-system -o yaml
Expected format:
```
https://github.com/cpfarhood/headlamp-polaris-plugin/releases/download/v0.3.5/headlamp-polaris-plugin-0.3.5.tar.gz
https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/download/v0.3.10/polaris-0.3.10.tar.gz
```
---
@@ -672,7 +672,7 @@ If none of these solutions work, gather debugging information and open an issue:
### Where to Get Help
- **GitHub Issues**: [https://github.com/cpfarhood/headlamp-polaris-plugin/issues](https://github.com/cpfarhood/headlamp-polaris-plugin/issues)
- **GitHub Discussions**: [https://github.com/cpfarhood/headlamp-polaris-plugin/discussions](https://github.com/cpfarhood/headlamp-polaris-plugin/discussions)
- **GitHub Issues**: [https://github.com/privilegedescalation/headlamp-polaris-plugin/issues](https://github.com/privilegedescalation/headlamp-polaris-plugin/issues)
- **GitHub Discussions**: [https://github.com/privilegedescalation/headlamp-polaris-plugin/discussions](https://github.com/privilegedescalation/headlamp-polaris-plugin/discussions)
Include the debugging information above when opening an issue.
+1 -1
View File
@@ -32,7 +32,7 @@ The Headlamp Polaris Plugin is a **read-only dashboard** that surfaces Fairwinds
│ └────────┬────────┘ │
│ │ │
│ ┌─────────────▼──────────────┐ │
│ │ Polaris Plugin (This!) │ │
│ │ Polaris Plugin │ │
│ ├────────────────────────────┤ │
│ │ • registerSidebarEntry │ │
│ │ • registerRoute │ │
+2 -2
View File
@@ -185,7 +185,7 @@ data:
plugin.yml: |
- name: headlamp-polaris-plugin
version: 0.3.5
url: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/download/v0.3.5/headlamp-polaris-plugin-0.3.5.tar.gz
url: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/download/v0.3.10/polaris-0.3.10.tar.gz
```
Apply ConfigMap then deploy Headlamp:
@@ -373,7 +373,7 @@ kubectl -n kube-system edit configmap headlamp-plugin-config
# Update version and URL:
# version: 0.3.6
# url: https://github.com/.../v0.3.6/headlamp-polaris-plugin-0.3.6.tar.gz
# url: https://github.com/.../v0.3.6/polaris-0.3.10.tar.gz
# Restart deployment to trigger init container
kubectl -n kube-system rollout restart deployment/headlamp
+2 -2
View File
@@ -98,7 +98,7 @@ data:
plugin.yml: |
- name: headlamp-polaris-plugin
version: 0.3.5
url: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/download/v0.3.5/headlamp-polaris-plugin-0.3.5.tar.gz
url: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/download/v0.3.10/polaris-0.3.10.tar.gz
```
### Headlamp Deployment with Plugin Init Container
@@ -414,7 +414,7 @@ kubectl -n kube-system edit configmap headlamp-plugin-config
# Update version and URL:
# version: 0.3.6
# url: https://github.com/.../v0.3.6/headlamp-polaris-plugin-0.3.6.tar.gz
# url: https://github.com/.../v0.3.6/polaris-0.3.10.tar.gz
# Restart deployment to trigger init container
kubectl -n kube-system rollout restart deployment/headlamp
+3 -3
View File
@@ -143,7 +143,7 @@ data:
plugin.yml: |
- name: headlamp-polaris-plugin
version: 0.3.5
url: https://github.com/cpfarhood/headlamp-polaris-plugin/releases/download/v0.3.5/headlamp-polaris-plugin-0.3.5.tar.gz
url: https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/download/v0.3.10/polaris-0.3.10.tar.gz
```
#### Apply Configuration
@@ -179,7 +179,7 @@ Download the plugin tarball and extract it into Headlamp's plugin directory.
```bash
# Download latest release
VERSION=0.3.5
wget https://github.com/cpfarhood/headlamp-polaris-plugin/releases/download/v${VERSION}/headlamp-polaris-plugin-${VERSION}.tar.gz
wget https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/download/v${VERSION}/headlamp-polaris-plugin-${VERSION}.tar.gz
# Extract to plugin directory
tar xzf headlamp-polaris-plugin-${VERSION}.tar.gz -C /headlamp/plugins/
@@ -225,7 +225,7 @@ Clone the repository and build the plugin from source.
```bash
# Clone repository
git clone https://github.com/cpfarhood/headlamp-polaris-plugin.git
git clone https://github.com/privilegedescalation/headlamp-polaris-plugin.git
cd headlamp-polaris-plugin
# Install dependencies
+4 -6
View File
@@ -6,9 +6,9 @@ Get the Headlamp Polaris Plugin up and running in 5 minutes.
Before starting, ensure:
- Kubernetes cluster is running
- Headlamp v0.26+ is deployed
- Polaris is installed with dashboard enabled
- Kubernetes cluster is running
- Headlamp v0.26+ is deployed
- Polaris is installed with dashboard enabled
Don't have these? See [Prerequisites](prerequisites.md) for installation instructions.
@@ -276,6 +276,4 @@ If test fails, see [Troubleshooting](../troubleshooting/README.md).
---
**Congratulations!** You're now running the Headlamp Polaris Plugin. 🎉
Visit the **Polaris** section in Headlamp to explore your cluster's security, reliability, and efficiency audit results.
You're now running the Headlamp Polaris Plugin. Visit the **Polaris** section in Headlamp to explore your cluster's security, reliability, and efficiency audit results.
+1 -1
View File
@@ -155,7 +155,7 @@ If the quick diagnosis doesn't resolve your issue:
- [Deployment Guide](../deployment/kubernetes.md)
3. **Open a GitHub issue:**
- [GitHub Issues](https://github.com/cpfarhood/headlamp-polaris-plugin/issues)
- [GitHub Issues](https://github.com/privilegedescalation/headlamp-polaris-plugin/issues)
- Include: Headlamp version, plugin version, error messages, logs
## References
+3 -3
View File
@@ -572,7 +572,7 @@ kubectl get configmap headlamp-plugin-config -n kube-system -o yaml
Expected format:
```
https://github.com/cpfarhood/headlamp-polaris-plugin/releases/download/v0.3.5/headlamp-polaris-plugin-0.3.5.tar.gz
https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/download/v0.3.10/polaris-0.3.10.tar.gz
```
---
@@ -672,7 +672,7 @@ If none of these solutions work, gather debugging information and open an issue:
### Where to Get Help
- **GitHub Issues**: [https://github.com/cpfarhood/headlamp-polaris-plugin/issues](https://github.com/cpfarhood/headlamp-polaris-plugin/issues)
- **GitHub Discussions**: [https://github.com/cpfarhood/headlamp-polaris-plugin/discussions](https://github.com/cpfarhood/headlamp-polaris-plugin/discussions)
- **GitHub Issues**: [https://github.com/privilegedescalation/headlamp-polaris-plugin/issues](https://github.com/privilegedescalation/headlamp-polaris-plugin/issues)
- **GitHub Discussions**: [https://github.com/privilegedescalation/headlamp-polaris-plugin/discussions](https://github.com/privilegedescalation/headlamp-polaris-plugin/discussions)
Include the debugging information above when opening an issue.
+2 -2
View File
@@ -117,13 +117,13 @@ Top-right corner of Headlamp shows a persistent cluster score badge.
**Features:**
- **Color-Coded Chip** - Green/Yellow/Red based on score
- **Shield Emoji (🛡️)** - Visual indicator
- **Shield Icon** - Visual indicator
- **Score Percentage** - e.g., "85%"
- **Clickable** - Click to navigate to Polaris overview
- **Real-Time Updates** - Updates on auto-refresh interval
- **Always Visible** - Appears on all Headlamp pages
**Example:** `🛡️ 85%` (green chip)
**Example:** Shield icon with "85%" (green chip)
## Settings & Configuration
+5 -5
View File
@@ -1,16 +1,16 @@
{
"name": "polaris",
"version": "0.3.9",
"version": "0.5.0",
"description": "Headlamp plugin for Fairwinds Polaris audit results",
"repository": {
"type": "git",
"url": "https://github.com/cpfarhood/headlamp-polaris-plugin.git"
"url": "https://github.com/privilegedescalation/headlamp-polaris-plugin.git"
},
"bugs": {
"url": "https://github.com/cpfarhood/headlamp-polaris-plugin/issues"
"url": "https://github.com/privilegedescalation/headlamp-polaris-plugin/issues"
},
"homepage": "https://github.com/cpfarhood/headlamp-polaris-plugin#readme",
"author": "cpfarhood",
"homepage": "https://github.com/privilegedescalation/headlamp-polaris-plugin#readme",
"author": "privilegedescalation",
"license": "Apache-2.0",
"scripts": {
"start": "headlamp-plugin start",
+14 -2
View File
@@ -35,8 +35,20 @@ const PolarisDataContext = React.createContext<PolarisDataContextValue | null>(n
* ```
*/
export function PolarisDataProvider(props: { children: React.ReactNode }) {
const interval = getRefreshInterval();
const state = usePolarisData(interval);
// Re-read interval on every render to pick up changes from settings
const [refreshInterval, setRefreshInterval] = React.useState(getRefreshInterval());
// Poll for interval changes (localStorage changes from settings)
React.useEffect(() => {
const intervalId = window.setInterval(() => {
const newInterval = getRefreshInterval();
setRefreshInterval(prev => (prev !== newInterval ? newInterval : prev));
}, 1000); // Check every second
return () => window.clearInterval(intervalId);
}, []);
const state = usePolarisData(refreshInterval);
// Rename triggerRefresh to refresh for consistency
const value = React.useMemo(
+3 -1
View File
@@ -373,7 +373,9 @@ export function usePolarisData(refreshIntervalSeconds: number): PolarisDataState
result = await response.json();
} else {
// Kubernetes proxy for relative URLs
result = await ApiProxy.request(apiPath);
result = await ApiProxy.request(apiPath, {
method: 'GET',
});
}
if (!cancelled) {
+51 -15
View File
@@ -44,6 +44,7 @@ interface NamespaceDetailPanelProps {
}
function NamespaceDetailPanel({ namespace, onClose }: NamespaceDetailPanelProps) {
const [isMaximized, setIsMaximized] = React.useState(false);
const { data, loading, error } = usePolarisDataContext();
if (loading) {
@@ -107,13 +108,14 @@ function NamespaceDetailPanel({ namespace, onClose }: NamespaceDetailPanelProps)
right: 0;
top: 0;
bottom: 0;
width: 1000px;
width: ${isMaximized ? 'calc(100vw - 240px)' : '1000px'};
background-color: var(--mui-palette-background-default, #fafafa);
color: var(--mui-palette-text-primary);
box-shadow: -2px 0 8px rgba(0,0,0,0.15);
overflow-y: auto;
z-index: 1200;
padding: 20px;
transition: width 0.3s ease;
}
`}
</style>
@@ -129,20 +131,54 @@ function NamespaceDetailPanel({ namespace, onClose }: NamespaceDetailPanelProps)
<h2 style={{ margin: 0, color: 'var(--mui-palette-text-primary)' }}>
Polaris {namespace}
</h2>
<button
onClick={onClose}
style={{
border: 'none',
background: 'transparent',
fontSize: '24px',
cursor: 'pointer',
padding: '0 8px',
color: 'var(--mui-palette-text-primary)',
}}
aria-label="Close panel"
>
×
</button>
<div style={{ display: 'flex', gap: '8px', alignItems: 'center' }}>
<button
onClick={() => setIsMaximized(!isMaximized)}
style={{
border: 'none',
background: 'transparent',
fontSize: '20px',
cursor: 'pointer',
padding: '4px 8px',
color: 'var(--mui-palette-text-secondary, #666)',
borderRadius: '4px',
}}
onMouseEnter={e => {
e.currentTarget.style.backgroundColor =
'var(--mui-palette-action-hover, rgba(0, 0, 0, 0.04))';
}}
onMouseLeave={e => {
e.currentTarget.style.backgroundColor = 'transparent';
}}
aria-label={isMaximized ? 'Minimize panel' : 'Maximize panel'}
title={isMaximized ? 'Minimize' : 'Maximize'}
>
{isMaximized ? '⊟' : '⊡'}
</button>
<button
onClick={onClose}
style={{
border: 'none',
background: 'transparent',
fontSize: '24px',
cursor: 'pointer',
padding: '4px 8px',
color: 'var(--mui-palette-text-secondary, #666)',
borderRadius: '4px',
}}
onMouseEnter={e => {
e.currentTarget.style.backgroundColor =
'var(--mui-palette-action-hover, rgba(0, 0, 0, 0.04))';
}}
onMouseLeave={e => {
e.currentTarget.style.backgroundColor = 'transparent';
}}
aria-label="Close panel"
title="Close"
>
×
</button>
</div>
</div>
<SectionBox title="External">
+3 -1
View File
@@ -58,7 +58,9 @@ export default function PolarisSettings(props: PluginSettingsProps) {
}
result = await response.json();
} else {
result = await ApiProxy.request(apiPath);
result = await ApiProxy.request(apiPath, {
method: 'GET',
});
}
setTestResult({
+1 -1
View File
@@ -66,7 +66,7 @@ registerRoute({
});
// Register plugin settings
registerPluginSettings('headlamp-polaris-plugin', PolarisSettings, true);
registerPluginSettings('polaris', PolarisSettings, true);
// Register details view section for supported controller types
registerDetailsViewSection(({ resource }) => {