fix: comprehensive code quality, theming, and test coverage improvements

- Fix ExemptionManager apiVersion bug (apps/batch resources used wrong API path)
- Replace resource: any with proper KubeResource interface (strict TypeScript)
- Replace all var(--mui-palette-*) CSS variables with useTheme() + theme.palette.*
- Replace custom drawer with MUI Drawer component (proper a11y and theming)
- Replace alert() calls with StatusLabel-based inline feedback
- Add PolarisErrorBoundary wrapping all registered plugin components
- Export getPolarisApiPath/isFullUrl from polaris.ts, deduplicate in PolarisSettings
- Fix PolarisDataContext test mock missing triggerRefresh
- Fix DashboardView test SimpleTable mock using any
- Remove dead NamespaceDetailView (replaced by drawer), unused MockPolarisProvider,
  unused getSeverityColor export
- Add tests for InlineAuditSection, AppBarScoreBadge, topIssues, checkMapping (32 new)
- Update CLAUDE.md, CHANGELOG.md, README.md for v0.6.0

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
DevContainer User
2026-03-04 16:59:50 +00:00
parent 6dd64e87ce
commit 514de78ba7
23 changed files with 1087 additions and 729 deletions
+2
View File
@@ -16,6 +16,7 @@ vi.mock('./polaris', async importOriginal => {
data: makeAuditData([makeResult()]),
loading: false,
error: null,
triggerRefresh: vi.fn(),
})),
};
});
@@ -44,5 +45,6 @@ describe('usePolarisDataContext', () => {
expect(result.current.data).not.toBeNull();
expect(result.current.loading).toBe(false);
expect(result.current.error).toBeNull();
expect(result.current.refresh).toBeDefined();
});
});
+77
View File
@@ -0,0 +1,77 @@
import { describe, expect, it } from 'vitest';
import {
CHECK_MAPPING,
getCheckCategory,
getCheckDescription,
getCheckName,
getSeverityStatus,
} from './checkMapping';
describe('checkMapping', () => {
describe('getCheckName', () => {
it('returns human-readable name for known check IDs', () => {
expect(getCheckName('hostIPCSet')).toBe('Host IPC');
expect(getCheckName('cpuRequestsMissing')).toBe('CPU Requests');
expect(getCheckName('readinessProbeMissing')).toBe('Readiness Probe');
});
it('returns the raw check ID for unknown checks', () => {
expect(getCheckName('unknownCheck')).toBe('unknownCheck');
});
});
describe('getCheckDescription', () => {
it('returns description for known checks', () => {
expect(getCheckDescription('hostIPCSet')).toBe('Host IPC should not be configured');
});
it('returns "Unknown check" for unknown checks', () => {
expect(getCheckDescription('unknownCheck')).toBe('Unknown check');
});
});
describe('getCheckCategory', () => {
it('returns correct category for each type', () => {
expect(getCheckCategory('hostIPCSet')).toBe('Security');
expect(getCheckCategory('cpuRequestsMissing')).toBe('Efficiency');
expect(getCheckCategory('readinessProbeMissing')).toBe('Reliability');
});
it('defaults to Security for unknown checks', () => {
expect(getCheckCategory('unknownCheck')).toBe('Security');
});
});
describe('getSeverityStatus', () => {
it('maps danger to error', () => {
expect(getSeverityStatus('danger')).toBe('error');
});
it('maps warning to warning', () => {
expect(getSeverityStatus('warning')).toBe('warning');
});
it('defaults to success for other values', () => {
expect(getSeverityStatus('ignore')).toBe('success');
expect(getSeverityStatus('unknown')).toBe('success');
});
});
describe('CHECK_MAPPING', () => {
it('has entries for all expected categories', () => {
const categories = new Set(Object.values(CHECK_MAPPING).map(c => c.category));
expect(categories).toContain('Security');
expect(categories).toContain('Efficiency');
expect(categories).toContain('Reliability');
});
it('all entries have required fields', () => {
for (const [id, info] of Object.entries(CHECK_MAPPING)) {
expect(info.name, `${id} missing name`).toBeTruthy();
expect(info.description, `${id} missing description`).toBeTruthy();
expect(['Security', 'Efficiency', 'Reliability']).toContain(info.category);
expect(['danger', 'warning', 'ignore']).toContain(info.defaultSeverity);
}
});
});
});
-16
View File
@@ -207,22 +207,6 @@ export function getCheckCategory(checkId: string): 'Security' | 'Efficiency' | '
return CHECK_MAPPING[checkId]?.category || 'Security';
}
/**
* Get color for severity
*/
export function getSeverityColor(severity: string): string {
switch (severity) {
case 'danger':
return '#f44336';
case 'warning':
return '#ff9800';
case 'ignore':
return '#9e9e9e';
default:
return '#9e9e9e';
}
}
/**
* Get status for StatusLabel component
*/
+2 -2
View File
@@ -300,7 +300,7 @@ export function computeScore(counts: ResultCounts): number {
*
* @returns Full path to results.json endpoint
*/
function getPolarisApiPath(): string {
export function getPolarisApiPath(): string {
const baseUrl = getDashboardUrl();
return baseUrl.endsWith('/') ? `${baseUrl}results.json` : `${baseUrl}/results.json`;
}
@@ -311,7 +311,7 @@ function getPolarisApiPath(): string {
* @param url - URL to check
* @returns true if full URL, false if relative path
*/
function isFullUrl(url: string): boolean {
export function isFullUrl(url: string): boolean {
return url.startsWith('http://') || url.startsWith('https://');
}
+216
View File
@@ -0,0 +1,216 @@
import { describe, expect, it } from 'vitest';
import { makeAuditData, makeResult } from '../test-utils';
import { getTopIssues } from './topIssues';
describe('getTopIssues', () => {
it('returns empty array when no results', () => {
const data = makeAuditData([]);
expect(getTopIssues(data)).toEqual([]);
});
it('returns empty array when all checks pass', () => {
const data = makeAuditData([
makeResult({
Results: {
c1: {
ID: 'c1',
Message: '',
Details: [],
Success: true,
Severity: 'warning',
Category: 'X',
},
},
}),
]);
expect(getTopIssues(data)).toEqual([]);
});
it('aggregates failing checks from controller-level results', () => {
const data = makeAuditData([
makeResult({
Results: {
cpuRequestsMissing: {
ID: 'cpuRequestsMissing',
Message: 'missing',
Details: [],
Success: false,
Severity: 'warning',
Category: 'Efficiency',
},
},
}),
]);
const issues = getTopIssues(data);
expect(issues).toHaveLength(1);
expect(issues[0].checkId).toBe('cpuRequestsMissing');
expect(issues[0].checkName).toBe('CPU Requests');
expect(issues[0].severity).toBe('warning');
expect(issues[0].count).toBe(1);
});
it('aggregates failing checks from pod and container results', () => {
const data = makeAuditData([
makeResult({
Results: {},
PodResult: {
Name: 'pod-1',
Results: {
hostIPCSet: {
ID: 'hostIPCSet',
Message: '',
Details: [],
Success: false,
Severity: 'danger',
Category: 'Security',
},
},
ContainerResults: [
{
Name: 'container-1',
Results: {
cpuLimitsMissing: {
ID: 'cpuLimitsMissing',
Message: '',
Details: [],
Success: false,
Severity: 'warning',
Category: 'Efficiency',
},
},
},
],
},
}),
]);
const issues = getTopIssues(data);
expect(issues).toHaveLength(2);
// Danger first
expect(issues[0].checkId).toBe('hostIPCSet');
expect(issues[0].severity).toBe('danger');
expect(issues[1].checkId).toBe('cpuLimitsMissing');
});
it('counts same check across multiple workloads', () => {
const data = makeAuditData([
makeResult({
Name: 'deploy-1',
Results: {
cpuRequestsMissing: {
ID: 'cpuRequestsMissing',
Message: '',
Details: [],
Success: false,
Severity: 'warning',
Category: 'Efficiency',
},
},
}),
makeResult({
Name: 'deploy-2',
Results: {
cpuRequestsMissing: {
ID: 'cpuRequestsMissing',
Message: '',
Details: [],
Success: false,
Severity: 'warning',
Category: 'Efficiency',
},
},
}),
]);
const issues = getTopIssues(data);
expect(issues).toHaveLength(1);
expect(issues[0].count).toBe(2);
});
it('ignores checks with severity "ignore"', () => {
const data = makeAuditData([
makeResult({
Results: {
c1: {
ID: 'c1',
Message: '',
Details: [],
Success: false,
Severity: 'ignore',
Category: 'X',
},
},
}),
]);
expect(getTopIssues(data)).toEqual([]);
});
it('sorts danger before warning, then by count descending', () => {
const data = makeAuditData([
makeResult({
Name: 'deploy-1',
Results: {
cpuRequestsMissing: {
ID: 'cpuRequestsMissing',
Message: '',
Details: [],
Success: false,
Severity: 'warning',
Category: 'Efficiency',
},
},
}),
makeResult({
Name: 'deploy-2',
Results: {
cpuRequestsMissing: {
ID: 'cpuRequestsMissing',
Message: '',
Details: [],
Success: false,
Severity: 'warning',
Category: 'Efficiency',
},
hostIPCSet: {
ID: 'hostIPCSet',
Message: '',
Details: [],
Success: false,
Severity: 'danger',
Category: 'Security',
},
},
}),
]);
const issues = getTopIssues(data);
// Danger first regardless of count
expect(issues[0].severity).toBe('danger');
expect(issues[1].severity).toBe('warning');
expect(issues[1].count).toBe(2);
});
it('returns at most 10 issues', () => {
const results: Record<
string,
{
ID: string;
Message: string;
Details: string[];
Success: boolean;
Severity: 'warning';
Category: string;
}
> = {};
for (let i = 0; i < 15; i++) {
results[`check${i}`] = {
ID: `check${i}`,
Message: '',
Details: [],
Success: false,
Severity: 'warning',
Category: 'X',
};
}
const data = makeAuditData([makeResult({ Results: results })]);
expect(getTopIssues(data)).toHaveLength(10);
});
});