@actuate-media/cms-admin 0.27.0 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/dist/__tests__/views/security-settings.render.test.d.ts +2 -0
  2. package/dist/__tests__/views/security-settings.render.test.d.ts.map +1 -0
  3. package/dist/__tests__/views/security-settings.render.test.js +175 -0
  4. package/dist/__tests__/views/security-settings.render.test.js.map +1 -0
  5. package/dist/actuate-admin.css +1 -1
  6. package/dist/views/Settings.d.ts.map +1 -1
  7. package/dist/views/Settings.js +3 -11
  8. package/dist/views/Settings.js.map +1 -1
  9. package/dist/views/settings/AccessProtectionCard.d.ts +10 -0
  10. package/dist/views/settings/AccessProtectionCard.d.ts.map +1 -0
  11. package/dist/views/settings/AccessProtectionCard.js +20 -0
  12. package/dist/views/settings/AccessProtectionCard.js.map +1 -0
  13. package/dist/views/settings/AuthMfaCard.d.ts +10 -0
  14. package/dist/views/settings/AuthMfaCard.d.ts.map +1 -0
  15. package/dist/views/settings/AuthMfaCard.js +33 -0
  16. package/dist/views/settings/AuthMfaCard.js.map +1 -0
  17. package/dist/views/settings/SecretsAuditCard.d.ts +11 -0
  18. package/dist/views/settings/SecretsAuditCard.d.ts.map +1 -0
  19. package/dist/views/settings/SecretsAuditCard.js +22 -0
  20. package/dist/views/settings/SecretsAuditCard.js.map +1 -0
  21. package/dist/views/settings/SecurityStatusCard.d.ts +6 -0
  22. package/dist/views/settings/SecurityStatusCard.d.ts.map +1 -0
  23. package/dist/views/settings/SecurityStatusCard.js +35 -0
  24. package/dist/views/settings/SecurityStatusCard.js.map +1 -0
  25. package/dist/views/settings/SecurityTab.d.ts +5 -0
  26. package/dist/views/settings/SecurityTab.d.ts.map +1 -0
  27. package/dist/views/settings/SecurityTab.js +41 -0
  28. package/dist/views/settings/SecurityTab.js.map +1 -0
  29. package/dist/views/settings/SessionPolicyCard.d.ts +11 -0
  30. package/dist/views/settings/SessionPolicyCard.d.ts.map +1 -0
  31. package/dist/views/settings/SessionPolicyCard.js +21 -0
  32. package/dist/views/settings/SessionPolicyCard.js.map +1 -0
  33. package/dist/views/settings/securityPrimitives.d.ts +21 -0
  34. package/dist/views/settings/securityPrimitives.d.ts.map +1 -0
  35. package/dist/views/settings/securityPrimitives.js +31 -0
  36. package/dist/views/settings/securityPrimitives.js.map +1 -0
  37. package/dist/views/settings/useSecuritySettings.d.ts +37 -0
  38. package/dist/views/settings/useSecuritySettings.d.ts.map +1 -0
  39. package/dist/views/settings/useSecuritySettings.js +154 -0
  40. package/dist/views/settings/useSecuritySettings.js.map +1 -0
  41. package/package.json +2 -2
  42. package/src/__tests__/views/security-settings.render.test.tsx +212 -0
  43. package/src/views/Settings.tsx +3 -33
  44. package/src/views/settings/AccessProtectionCard.tsx +143 -0
  45. package/src/views/settings/AuthMfaCard.tsx +118 -0
  46. package/src/views/settings/SecretsAuditCard.tsx +129 -0
  47. package/src/views/settings/SecurityStatusCard.tsx +110 -0
  48. package/src/views/settings/SecurityTab.tsx +162 -0
  49. package/src/views/settings/SessionPolicyCard.tsx +123 -0
  50. package/src/views/settings/securityPrimitives.tsx +75 -0
  51. package/src/views/settings/useSecuritySettings.ts +197 -0
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=security-settings.render.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security-settings.render.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/views/security-settings.render.test.tsx"],"names":[],"mappings":""}
@@ -0,0 +1,175 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ // @vitest-environment happy-dom
3
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
4
+ import { fireEvent, render, screen, waitFor } from '@testing-library/react';
5
+ // The Security tab reads `/security` (computed posture + summaries + editable
6
+ // policy), saves via PUT `/security`, and revokes sessions via POST.
7
+ let securityData;
8
+ const cmsApi = vi.fn(async (endpoint, options) => {
9
+ const method = options?.method ?? 'GET';
10
+ if (endpoint === '/security' && method === 'GET')
11
+ return { data: securityData, status: 200 };
12
+ if (endpoint === '/security' && method === 'PUT') {
13
+ const body = JSON.parse(String(options?.body ?? '{}'));
14
+ securityData = {
15
+ ...securityData,
16
+ settings: {
17
+ mfa: { required: body.mfa.required, gracePeriodDays: body.mfa.gracePeriodDays },
18
+ session: { maxConcurrentSessions: body.session.maxConcurrentSessions },
19
+ },
20
+ };
21
+ return { data: securityData, status: 200 };
22
+ }
23
+ if (endpoint === '/security/sessions/revoke-all' && method === 'POST')
24
+ return { data: { revoked: 2 }, status: 200 };
25
+ return { data: {}, status: 200 };
26
+ });
27
+ vi.mock('../../lib/api.js', () => ({ cmsApi: (e, o) => cmsApi(e, o) }));
28
+ const { SecurityTab } = await import('../../views/settings/SecurityTab.js');
29
+ function baseData(overrides = {}) {
30
+ return {
31
+ settings: {
32
+ mfa: { required: false, gracePeriodDays: 7 },
33
+ session: { maxConcurrentSessions: 5 },
34
+ },
35
+ status: {
36
+ status: 'needs_attention',
37
+ score: 88,
38
+ label: 'Needs attention',
39
+ description: 'Some recommended controls are missing.',
40
+ checks: [
41
+ { key: 'mfa', label: 'MFA coverage', status: 'warning', value: '1 of 2 admins' },
42
+ { key: 'csrf', label: 'CSRF protection', status: 'pass', value: 'Enabled' },
43
+ ],
44
+ warnings: [
45
+ {
46
+ id: 'mfa-not-required',
47
+ severity: 'warning',
48
+ category: 'auth',
49
+ title: 'MFA is not required in production',
50
+ description: 'Requiring MFA reduces account-takeover risk.',
51
+ },
52
+ ],
53
+ lastCheckedAt: '2026-06-01T00:00:00.000Z',
54
+ },
55
+ users: {
56
+ totalUsers: 3,
57
+ totalAdmins: 2,
58
+ withMfa: 1,
59
+ withoutMfa: 2,
60
+ adminsWithoutMfa: 1,
61
+ inactive: 0,
62
+ },
63
+ apiKeys: { active: 1, withoutExpiration: 0, broadScope: 0, staleUnused90d: 0 },
64
+ secrets: {
65
+ cmsSecret: 'pass',
66
+ encryptionKey: 'pass',
67
+ rateLimitBackend: 'distributed',
68
+ apiKeysHashed: true,
69
+ webhookSecretsEncrypted: true,
70
+ },
71
+ ipAllowlist: {
72
+ enabled: false,
73
+ source: 'none',
74
+ ranges: [],
75
+ currentIp: '1.2.3.4',
76
+ currentIpAllowed: null,
77
+ },
78
+ failedLogins24h: 0,
79
+ activeSessions: 2,
80
+ csrfEnabled: true,
81
+ uploadValidation: true,
82
+ auditEnabled: true,
83
+ sessionMaxAgeHours: 168,
84
+ viewerHasMfa: true,
85
+ environment: 'production',
86
+ sources: {
87
+ ipAllowlist: { source: 'config', editable: false },
88
+ csrf: { source: 'computed', editable: false },
89
+ rateLimiting: { source: 'environment', editable: false },
90
+ uploadValidation: { source: 'computed', editable: false },
91
+ cmsSecret: { source: 'environment', editable: false },
92
+ encryptionKey: { source: 'environment', editable: false },
93
+ audit: { source: 'computed', editable: false },
94
+ },
95
+ ...overrides,
96
+ };
97
+ }
98
+ beforeEach(() => {
99
+ cmsApi.mockClear();
100
+ securityData = baseData();
101
+ });
102
+ describe('SecurityTab', () => {
103
+ it('renders the status card and all security sections with a disabled save bar', async () => {
104
+ render(_jsx(SecurityTab, { role: "ADMIN" }));
105
+ await screen.findByText('Security Status');
106
+ expect(screen.getByText('Authentication & MFA')).toBeTruthy();
107
+ expect(screen.getByText('Session Policy')).toBeTruthy();
108
+ expect(screen.getByText('Access & Request Protection')).toBeTruthy();
109
+ expect(screen.getByText('Secrets, Encryption & Audit')).toBeTruthy();
110
+ // Status badge + warning surfaced.
111
+ expect(screen.getByText('Needs attention')).toBeTruthy();
112
+ expect(screen.getByText('MFA is not required in production')).toBeTruthy();
113
+ expect(screen.getByRole('button', { name: 'Save Changes' }).disabled).toBe(true);
114
+ });
115
+ it('enables Save when concurrent-session cap changes and persists via PUT /security', async () => {
116
+ render(_jsx(SecurityTab, { role: "ADMIN" }));
117
+ await screen.findByText('Security Status');
118
+ const select = screen.getByLabelText(/Maximum concurrent sessions/);
119
+ fireEvent.change(select, { target: { value: '3' } });
120
+ const save = screen.getByRole('button', { name: 'Save Changes' });
121
+ expect(save.disabled).toBe(false);
122
+ fireEvent.click(save);
123
+ await waitFor(() => expect(cmsApi).toHaveBeenCalledWith('/security', expect.objectContaining({
124
+ method: 'PUT',
125
+ body: expect.stringContaining('"maxConcurrentSessions":3'),
126
+ })));
127
+ });
128
+ it('blocks enabling Require MFA (lockout-safe) when the acting admin has no MFA', async () => {
129
+ securityData = baseData({ viewerHasMfa: false });
130
+ render(_jsx(SecurityTab, { role: "ADMIN" }));
131
+ await screen.findByText('Security Status');
132
+ const toggle = screen.getByRole('switch', {
133
+ name: 'Require MFA for admin users',
134
+ });
135
+ // Toggle is disabled until the admin sets up their own MFA.
136
+ expect(toggle.disabled).toBe(true);
137
+ expect(screen.getByText(/Set up MFA on your own account/i)).toBeTruthy();
138
+ });
139
+ it('confirms before requiring MFA and then persists it (admin has MFA)', async () => {
140
+ render(_jsx(SecurityTab, { role: "ADMIN" }));
141
+ await screen.findByText('Security Status');
142
+ fireEvent.click(screen.getByRole('switch', { name: 'Require MFA for admin users' }));
143
+ // Confirmation dialog appears; nothing saved yet.
144
+ const confirm = await screen.findByRole('button', { name: 'Require MFA' });
145
+ fireEvent.click(confirm);
146
+ const save = screen.getByRole('button', { name: 'Save Changes' });
147
+ expect(save.disabled).toBe(false);
148
+ fireEvent.click(save);
149
+ await waitFor(() => expect(cmsApi).toHaveBeenCalledWith('/security', expect.objectContaining({
150
+ method: 'PUT',
151
+ body: expect.stringContaining('"required":true'),
152
+ })));
153
+ });
154
+ it('revokes other sessions through a confirmation flow', async () => {
155
+ render(_jsx(SecurityTab, { role: "ADMIN" }));
156
+ await screen.findByText('Security Status');
157
+ fireEvent.click(screen.getByRole('button', { name: 'Revoke other sessions' }));
158
+ const confirm = await screen.findByRole('button', { name: 'Revoke sessions' });
159
+ fireEvent.click(confirm);
160
+ await waitFor(() => expect(cmsApi).toHaveBeenCalledWith('/security/sessions/revoke-all', expect.objectContaining({ method: 'POST' })));
161
+ await screen.findByText('Other sessions revoked.');
162
+ });
163
+ it('is read-only for non-admin roles', async () => {
164
+ render(_jsx(SecurityTab, { role: "EDITOR" }));
165
+ await screen.findByText('Security Status');
166
+ expect(screen.getByText(/read-only access/i)).toBeTruthy();
167
+ const toggle = screen.getByRole('switch', {
168
+ name: 'Require MFA for admin users',
169
+ });
170
+ expect(toggle.disabled).toBe(true);
171
+ const select = screen.getByLabelText(/Maximum concurrent sessions/);
172
+ expect(select.disabled).toBe(true);
173
+ });
174
+ });
175
+ //# sourceMappingURL=security-settings.render.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security-settings.render.test.js","sourceRoot":"","sources":["../../../src/__tests__/views/security-settings.render.test.tsx"],"names":[],"mappings":"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"}