mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-24 12:42:49 +00:00
Call plain HTTP critical only when Pulse is publicly reachable
The Security Overview tagged the HTTPS tile red and Critical on every install, directly above a hardening card that calls HTTPS Recommended on a private network and says local HTTP is acceptable. The same flag also counted plain HTTP as a missing critical control in the posture score, so a typical LAN install read 55 percent. The tile now uses the hardening card's rule: critical once the instance is publicly reachable, recommended otherwise. A private install with a password and protected exports reads 79 percent, still Moderate, and a public one still shows HTTPS as Critical.
This commit is contained in:
@@ -859,6 +859,10 @@ tokens, and path-normalization variants.
|
||||
placeholders on the shared `SettingsLoadingSkeleton` primitive. This
|
||||
subsystem owns the security/privacy posture semantics; frontend-primitives
|
||||
owns skeleton animation, fill tokens, and placeholder shell consistency.
|
||||
Posture severity is one rule across the Security Overview: the HTTPS tile
|
||||
counts as critical, in its label and in the posture score, only when the
|
||||
instance is publicly reachable, matching the hardening step that calls
|
||||
HTTPS critical for public access and recommended on a private network.
|
||||
6a. Keep API token refresh/loading indicators on the shared `LoadingSpinner`
|
||||
primitive. Security/privacy owns the token-management trust copy and
|
||||
refresh semantics; frontend-primitives owns spinner shell, tone, and
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"version": 1,
|
||||
"base_sha": "fdcffc64114bd9d7ff7a92324391a09702c3c26a",
|
||||
"verified_at": "2026-10-05T06:03:02Z",
|
||||
"result": "passed",
|
||||
"changed_paths": [
|
||||
"frontend-modern/src/utils/securityScorePresentation.ts"
|
||||
],
|
||||
"content_sha256": {
|
||||
"frontend-modern/src/utils/securityScorePresentation.ts": "8a49852f591edd3e75bf4a2b1288a6ba71bf54259feffddbc0b3659d06ce6e0c"
|
||||
},
|
||||
"routes": [
|
||||
"/settings/security-overview"
|
||||
],
|
||||
"viewports": [
|
||||
{
|
||||
"width": 1440,
|
||||
"height": 1000
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"height": 1000
|
||||
}
|
||||
],
|
||||
"states": [
|
||||
"Private-network instance at 1440: the HTTPS tile is neutral with no Critical tag, matching the Plan HTTPS before live use card below it marked Recommended. Before, the tile was red and tagged Critical above that same Recommended card",
|
||||
"Posture score reads 79 percent Moderate (password and export protection on, plain HTTP on a private network), where before plain HTTP pulled it to 55 percent",
|
||||
"Phone at 390: the same neutral HTTPS tile and 79 percent Moderate header"
|
||||
],
|
||||
"interactions": [
|
||||
"Compared the posture grid with the hardening steps on the same page"
|
||||
]
|
||||
}
|
||||
@@ -47,4 +47,32 @@ describe('SecurityPostureSummary', () => {
|
||||
|
||||
expect(screen.getByText('Weak')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('only calls plain HTTP critical once the instance is publicly reachable', () => {
|
||||
const status = {
|
||||
hasAuthentication: true,
|
||||
ssoEnabled: false,
|
||||
hasProxyAuth: false,
|
||||
apiTokenConfigured: false,
|
||||
exportProtected: true,
|
||||
unprotectedExportAllowed: false,
|
||||
hasHTTPS: false,
|
||||
hasAuditLogging: false,
|
||||
requiresAuth: true,
|
||||
};
|
||||
const { unmount } = render(() => (
|
||||
<SecurityPostureSummary status={{ ...status, publicAccess: false, isPrivateNetwork: true }} />
|
||||
));
|
||||
// Private network: HTTPS is a recommended step, so no Critical tag and the
|
||||
// critical share of the score is complete (0.7 + 2 of 7 x 0.3 = 79).
|
||||
expect(screen.queryByText('Critical')).toBeNull();
|
||||
expect(screen.getByText('79%')).toBeInTheDocument();
|
||||
unmount();
|
||||
|
||||
render(() => (
|
||||
<SecurityPostureSummary status={{ ...status, publicAccess: true, isPrivateNetwork: false }} />
|
||||
));
|
||||
expect(screen.getByText('Critical')).toBeInTheDocument();
|
||||
expect(screen.getByText('55%')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -271,11 +271,12 @@ describe('securityScorePresentation — branch coverage (batch 0718)', () => {
|
||||
description: 'Token + passphrase required',
|
||||
critical: true,
|
||||
});
|
||||
// Private network (publicAccess false): HTTPS is recommended, not critical.
|
||||
expect(byKey.https).toMatchObject({
|
||||
label: 'HTTPS',
|
||||
enabled: false,
|
||||
description: 'HTTP only',
|
||||
critical: true,
|
||||
critical: false,
|
||||
});
|
||||
expect(byKey.audit).toMatchObject({
|
||||
label: 'Audit log',
|
||||
|
||||
@@ -271,6 +271,8 @@ describe('securityScorePresentation', () => {
|
||||
key: 'export',
|
||||
description: 'Token + passphrase required',
|
||||
}),
|
||||
// Publicly reachable, so HTTPS counts as critical.
|
||||
expect.objectContaining({ key: 'https', critical: true }),
|
||||
]),
|
||||
);
|
||||
|
||||
|
||||
@@ -394,7 +394,11 @@ export function getSecurityPostureItems(status: SecurityPostureStatus): Security
|
||||
label: 'HTTPS',
|
||||
enabled: Boolean(status.hasHTTPS),
|
||||
description: status.hasHTTPS ? 'Encrypted' : 'HTTP only',
|
||||
critical: true,
|
||||
// Same rule as the hardening steps below the grid: plain HTTP is
|
||||
// critical once the instance is publicly reachable, and a recommended
|
||||
// step on a private network. Marking it critical there put a red
|
||||
// Critical tile above a Recommended card for the same control.
|
||||
critical: Boolean(status.publicAccess),
|
||||
},
|
||||
{
|
||||
key: 'audit',
|
||||
|
||||
Reference in New Issue
Block a user