e2e: shared volume plugin deployment for CI tests #59
@@ -48,9 +48,14 @@ Polaris must be deployed in the `polaris` namespace with the dashboard component
|
||||
|
||||
## Installing
|
||||
|
||||
### Option 1: Headlamp Plugin Manager (Recommended)
|
||||
The plugin is published on [Artifact Hub](https://artifacthub.io/packages/headlamp/polaris/headlamp-polaris-plugin). Install via the Headlamp UI:
|
||||
|
||||
The plugin is published on [Artifact Hub](https://artifacthub.io/packages/headlamp/polaris/headlamp-polaris-plugin). Configure Headlamp via Helm:
|
||||
1. Go to **Settings → Plugins**
|
||||
2. Click **Catalog** tab
|
||||
3. Search for "Polaris"
|
||||
4. Click **Install**
|
||||
|
||||
Or configure Headlamp via Helm:
|
||||
|
||||
```yaml
|
||||
config:
|
||||
@@ -62,56 +67,6 @@ pluginsManager:
|
||||
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:
|
||||
|
||||
1. Go to **Settings → Plugins**
|
||||
2. Click **Catalog** tab
|
||||
3. Search for "Polaris"
|
||||
4. Click **Install**
|
||||
|
||||
### Option 2: Sidecar Container (Alternative)
|
||||
|
||||
For detailed sidecar installation instructions, see [docs/DEPLOYMENT.md#installation-method-2-sidecar-container](docs/DEPLOYMENT.md#installation-method-2-sidecar-container).
|
||||
|
||||
```yaml
|
||||
sidecars:
|
||||
- name: headlamp-plugin
|
||||
image: node:lts-alpine
|
||||
command: ['/bin/sh']
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
npm install -g @kinvolk/headlamp-plugin
|
||||
headlamp-plugin install --config /config/plugin.yml
|
||||
tail -f /dev/null
|
||||
volumeMounts:
|
||||
- name: plugins
|
||||
mountPath: /headlamp/plugins
|
||||
- name: plugin-config
|
||||
mountPath: /config
|
||||
```
|
||||
|
||||
### Option 3: Manual Tarball Install
|
||||
|
||||
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/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/privilegedescalation/headlamp-polaris-plugin.git
|
||||
cd headlamp-polaris-plugin
|
||||
npm install
|
||||
npm run build
|
||||
npx @kinvolk/headlamp-plugin extract . /headlamp/plugins
|
||||
```
|
||||
|
||||
For complete installation instructions including Helm integration, FluxCD examples, and production deployment checklist, see **[docs/DEPLOYMENT.md](docs/DEPLOYMENT.md)**.
|
||||
|
||||
## RBAC / Security Setup
|
||||
|
||||
The plugin fetches audit data through the Kubernetes API server's **service proxy** sub-resource. The identity making the request (Headlamp's service account, or the user's own token in token-auth mode) must be granted:
|
||||
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
version: "0.7.0"
|
||||
version: "0.7.1"
|
||||
name: headlamp-polaris
|
||||
displayName: Polaris
|
||||
createdAt: "2026-02-05T19:00:00Z"
|
||||
@@ -28,7 +28,7 @@ maintainers:
|
||||
- name: privilegedescalation
|
||||
email: "chris@farhood.org"
|
||||
annotations:
|
||||
headlamp/plugin/archive-url: "https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/download/v0.7.0/headlamp-polaris-0.7.0.tar.gz"
|
||||
headlamp/plugin/archive-url: "https://github.com/privilegedescalation/headlamp-polaris-plugin/releases/download/v0.7.1/headlamp-polaris-0.7.1.tar.gz"
|
||||
headlamp/plugin/version-compat: ">=0.26"
|
||||
headlamp/plugin/archive-checksum: sha256:69b7adf74416d72580981387b1861e2b5fcf7f96ae9f0620f85f623f8b6dab56
|
||||
headlamp/plugin/archive-checksum: sha256:5ea27f3beeab9730a13a752a0a7c2270eca83dcbbe813a6cabeb6a22fa9d5174
|
||||
headlamp/plugin/distro-compat: in-cluster
|
||||
|
||||
@@ -7,13 +7,7 @@ import { makeAuditData, makeResult } from '../test-utils';
|
||||
// Mock Headlamp lib
|
||||
vi.mock('@kinvolk/headlamp-plugin/lib', () => ({
|
||||
ApiProxy: { request: vi.fn() },
|
||||
K8s: {
|
||||
useCluster: () => 'test-cluster',
|
||||
},
|
||||
Router: {
|
||||
createRouteURL: (name: string, params?: { cluster?: string }) =>
|
||||
`/c/${params?.cluster ?? 'default'}/${name}`,
|
||||
},
|
||||
K8s: {},
|
||||
}));
|
||||
|
||||
vi.mock('@mui/material/styles', () => ({
|
||||
@@ -31,6 +25,15 @@ vi.mock('react-router-dom', () => ({
|
||||
useHistory: () => ({ push: mockPush }),
|
||||
}));
|
||||
|
||||
// Set window.location.pathname for cluster extraction
|
||||
beforeEach(() => {
|
||||
Object.defineProperty(window, 'location', {
|
||||
value: { pathname: '/c/test-cluster/some-page' },
|
||||
writable: true,
|
||||
});
|
||||
mockPush.mockClear();
|
||||
});
|
||||
|
||||
const mockUsePolarisDataContext = vi.fn();
|
||||
vi.mock('../api/PolarisDataContext', () => ({
|
||||
usePolarisDataContext: () => mockUsePolarisDataContext(),
|
||||
@@ -97,7 +100,7 @@ describe('AppBarScoreBadge', () => {
|
||||
expect(button.style.backgroundColor).toBe('rgb(244, 67, 54)');
|
||||
});
|
||||
|
||||
it('navigates to /polaris on click', async () => {
|
||||
it('navigates to /c/<cluster>/polaris on click', async () => {
|
||||
const user = userEvent.setup();
|
||||
const data = makeAuditData([
|
||||
makeResult({
|
||||
@@ -120,6 +123,33 @@ describe('AppBarScoreBadge', () => {
|
||||
expect(mockPush).toHaveBeenCalledWith('/c/test-cluster/polaris');
|
||||
});
|
||||
|
||||
it('navigates to /polaris when no cluster in URL', async () => {
|
||||
Object.defineProperty(window, 'location', {
|
||||
value: { pathname: '/settings' },
|
||||
writable: true,
|
||||
});
|
||||
const user = userEvent.setup();
|
||||
const data = makeAuditData([
|
||||
makeResult({
|
||||
Results: {
|
||||
c1: {
|
||||
ID: 'c1',
|
||||
Message: '',
|
||||
Details: [],
|
||||
Success: true,
|
||||
Severity: 'warning',
|
||||
Category: 'X',
|
||||
},
|
||||
},
|
||||
}),
|
||||
]);
|
||||
mockUsePolarisDataContext.mockReturnValue({ data, loading: false });
|
||||
|
||||
render(<AppBarScoreBadge />);
|
||||
await user.click(screen.getByRole('button'));
|
||||
expect(mockPush).toHaveBeenCalledWith('/polaris');
|
||||
});
|
||||
|
||||
it('has correct aria-label', () => {
|
||||
const data = makeAuditData([
|
||||
makeResult({
|
||||
|
||||
@@ -1,10 +1,21 @@
|
||||
import { K8s, Router } from '@kinvolk/headlamp-plugin/lib';
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import React from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { computeScore, countResults } from '../api/polaris';
|
||||
import { usePolarisDataContext } from '../api/PolarisDataContext';
|
||||
|
||||
/**
|
||||
* Extract the cluster name from the current browser URL.
|
||||
* Headlamp cluster routes follow the pattern /c/<cluster>/...
|
||||
* We read window.location.pathname directly because the AppBar renders
|
||||
* outside the cluster route context, so useCluster() returns null and
|
||||
* React Router's useLocation() may not reflect the cluster prefix.
|
||||
*/
|
||||
function getClusterFromUrl(): string | null {
|
||||
const match = window.location.pathname.match(/\/c\/([^/]+)/);
|
||||
return match ? match[1] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* App bar badge showing cluster Polaris score
|
||||
* Clicking navigates to the overview dashboard
|
||||
@@ -13,7 +24,6 @@ export default function AppBarScoreBadge() {
|
||||
const theme = useTheme();
|
||||
const { data, loading } = usePolarisDataContext();
|
||||
const history = useHistory();
|
||||
const cluster = K8s.useCluster();
|
||||
|
||||
if (loading || !data) {
|
||||
return null; // Graceful degradation when Polaris unavailable
|
||||
@@ -36,7 +46,9 @@ export default function AppBarScoreBadge() {
|
||||
};
|
||||
|
||||
const handleClick = () => {
|
||||
history.push(Router.createRouteURL('polaris', { cluster: cluster ?? '' }));
|
||||
const cluster = getClusterFromUrl();
|
||||
const prefix = cluster ? `/c/${cluster}` : '';
|
||||
history.push(`${prefix}/polaris`);
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
+1
-1
@@ -99,7 +99,7 @@ registerRoute({
|
||||
});
|
||||
|
||||
// Register plugin settings
|
||||
registerPluginSettings('headlamp-polaris', PolarisSettings, true);
|
||||
registerPluginSettings('polaris', PolarisSettings, true);
|
||||
|
||||
// Register details view section for supported controller types
|
||||
registerDetailsViewSection(({ resource }) => {
|
||||
|
||||
Reference in New Issue
Block a user