feat: frontend audit fixes, README accuracy pass, doc updates

Frontend audit (10 categories): lifecycle fields in types, new API
functions (CRL, OCSP, deployments, updateIssuer/Target, getPolicy),
issuer/owner/profile filters on CertificatesPage, last_renewal_at
column, error_message column on JobsPage, full crypto policy UI on
ProfilesPage (key algorithms, EKUs, SAN patterns), key info + CA
badge on DiscoveryPage, edit modal on TargetDetailPage, tags field
on certificate creation, darwin→macOS mapping on AgentFleetPage.
211 Vitest tests passing.

README accuracy: test counts (1300+ Go, 211 frontend), page count
(24), demo data (32 certs, 7 issuers, 180 days), endpoint count
(97), MCP tools (80), CLI subcommands (10), moved shipped items
out of "Coming in v2.1.0".

Docs: architecture.md diagrams updated (Vault PKI, DigiCert,
Traefik, Caddy added), features.md Vault/DigiCert status updated.
Version bumped to v2.0.20. cli binary removed from git tracking.
Testing guide Part 41 added (12 auto + 9 manual tests).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
shankar0123
2026-03-30 22:10:45 -04:00
parent 836534f2a7
commit 6c8d4eca40
16 changed files with 638 additions and 52 deletions
+29
View File
@@ -122,6 +122,26 @@ export const exportCertificatePKCS12 = (id: string, password: string = '') => {
});
};
// Certificate Deployments
export const getCertificateDeployments = (id: string, params: Record<string, string> = {}) => {
const qs = new URLSearchParams({ page: '1', per_page: '50', ...params }).toString();
return fetchJSON<PaginatedResponse<Job>>(`${BASE}/certificates/${id}/deployments?${qs}`);
};
// CRL / OCSP
export const getCRL = () =>
fetchJSON<{ version: number; entries: unknown[]; total: number; generated_at: string }>(`${BASE}/crl`);
export const getOCSPStatus = (issuerId: string, serial: string) => {
const headers: Record<string, string> = {};
if (apiKey) headers['Authorization'] = `Bearer ${apiKey}`;
return fetch(`${BASE}/ocsp/${issuerId}/${serial}`, { headers })
.then(r => {
if (!r.ok) throw new Error(`OCSP request failed: ${r.status}`);
return r.arrayBuffer();
});
};
// Agents
export const getAgents = (params: Record<string, string> = {}) => {
const qs = new URLSearchParams({ page: '1', per_page: '50', ...params }).toString();
@@ -170,6 +190,9 @@ export const createPolicy = (data: Partial<PolicyRule>) =>
export const updatePolicy = (id: string, data: Partial<PolicyRule>) =>
fetchJSON<PolicyRule>(`${BASE}/policies/${id}`, { method: 'PUT', body: JSON.stringify(data) });
export const getPolicy = (id: string) =>
fetchJSON<PolicyRule>(`${BASE}/policies/${id}`);
export const deletePolicy = (id: string) =>
fetchJSON<{ message: string }>(`${BASE}/policies/${id}`, { method: 'DELETE' });
@@ -188,6 +211,9 @@ export const createIssuer = (data: Partial<Issuer>) =>
export const testIssuerConnection = (id: string) =>
fetchJSON<{ message: string }>(`${BASE}/issuers/${id}/test`, { method: 'POST' });
export const updateIssuer = (id: string, data: Partial<Issuer>) =>
fetchJSON<Issuer>(`${BASE}/issuers/${id}`, { method: 'PUT', body: JSON.stringify(data) });
export const deleteIssuer = (id: string) =>
fetchJSON<{ message: string }>(`${BASE}/issuers/${id}`, { method: 'DELETE' });
@@ -200,6 +226,9 @@ export const getTargets = (params: Record<string, string> = {}) => {
export const createTarget = (data: Partial<Target>) =>
fetchJSON<Target>(`${BASE}/targets`, { method: 'POST', body: JSON.stringify(data) });
export const updateTarget = (id: string, data: Partial<Target>) =>
fetchJSON<Target>(`${BASE}/targets/${id}`, { method: 'PUT', body: JSON.stringify(data) });
export const deleteTarget = (id: string) =>
fetchJSON<{ message: string }>(`${BASE}/targets/${id}`, { method: 'DELETE' });