fix(compose-doctor): resolve effective healthcheck coverage (#1713)

* fix(compose-doctor): resolve effective healthcheck coverage

Compose Doctor now classifies healthcheck coverage from the Compose model, running containers, and local images so image-provided HEALTHCHECKs are not false positives. Update Guard shares the same presence helper so test NONE is not treated as active.

* fix(compose-doctor): fix healthcheck project label and empty compose HC

Use the Compose project name for runtime container listing so stacks whose name: differs from the directory still get runtime evidence. Treat empty or timing-only healthcheck objects as absent rather than active.

* fix(compose-doctor): treat inherited healthcheck as All Clear note

Inherited image healthchecks no longer block All Clear; they surface under a notes section and cannot be acknowledged.
This commit is contained in:
Anso
2026-07-28 14:26:00 -04:00
committed by GitHub
parent c90e9606f1
commit 78475d96ef
27 changed files with 1077 additions and 54 deletions
+5 -1
View File
@@ -27,7 +27,7 @@ import { enforcePolicyPreDeploy } from '../services/PolicyEnforcement';
import { buildStackDriftReport, type DriftFindingKind, type StackDriftReport } from '../services/DriftDetectionService';
import { DriftLedgerService, type DriftTemporal } from '../services/DriftLedgerService';
import { ComposeDoctorService } from '../services/ComposeDoctorService';
import { RULE_IDS } from '../services/preflight/rules';
import { RULE_IDS, isPreflightNoteFinding } from '../services/preflight/rules';
import { parseServiceImages, isPreflightAckActive } from '../utils/preflight-ack-filter';
import type { PreflightAckExpiryMode } from '../services/DatabaseService';
import { buildStackNetworkFacts } from '../services/network/composeNetworkInspector';
@@ -1417,6 +1417,10 @@ stacksRouter.post('/:stackName/preflight/acknowledgements', async (req: Request,
res.status(400).json({ error: 'ruleId must be a known Compose Doctor rule id' });
return;
}
if (isPreflightNoteFinding(ruleId)) {
res.status(400).json({ error: 'Informational notes cannot be acknowledged' });
return;
}
const serviceRaw = body.service == null || body.service === ''
? null
: String(body.service).trim();