fix(doctor): stop npm protection passing when the real package manager is absent (#378)

`pmg setup doctor` reported npm protection as OK on a machine with no npm
installed. Two compounding defects:

1. The availability gate used a plain `exec.LookPath`, which resolves the PMG
   shim on PATH rather than the real binary, so the "skip" branch never fired.
   It now uses `shim.ResolveRealBinary` (PATH with shim dirs stripped), matching
   the runner, so a missing real binary correctly yields WARN "not available".

2. The result was inferred purely from a non-zero exit, so PackageManagerNotFound
   (exit 127) and other failures were misread as a successful block. The check
   now requires PMG's block headline in the captured output before reporting
   PASS; other non-zero exits report WARN with the error surfaced.

The block headline is extracted into `ui.MalwareBlockedHeadline` so the doctor's
marker stays in sync with what PMG prints across its block-output sites.
This commit is contained in:
Sahil Bansal
2026-07-15 09:11:52 +05:30
committed by GitHub
parent dc0e3202cc
commit 46803f8e70
5 changed files with 76 additions and 19 deletions
+1 -1
View File
@@ -36,7 +36,7 @@ func (p ProxyPresenter) BlockMessage(reason proxy.BlockReason, blockCtx *proxy.B
var message string
switch reason {
case proxy.BlockReasonMalware, proxy.BlockReasonUserDeclined:
prefix := "Malicious package blocked"
prefix := MalwareBlockedHeadline
if reason == proxy.BlockReasonUserDeclined {
prefix = "Installation blocked by user"
}
+7 -1
View File
@@ -139,13 +139,19 @@ func Report(data *ReportData) {
}
}
// MalwareBlockedHeadline is the headline printed when a malicious package is
// blocked. Exported so out-of-process consumers (e.g. `pmg setup doctor`) can
// detect a genuine block from captured output instead of inferring it from a
// non-zero exit code, which any failure would also produce.
const MalwareBlockedHeadline = "Malicious package blocked"
func printMalwareBlockSection(data *ReportData) {
if len(data.BlockedPackages) == 0 {
return
}
fmt.Println()
fmt.Printf("%s %s\n", Colors.Red("✗"), Colors.Red("Malicious package blocked"))
fmt.Printf("%s %s\n", Colors.Red("✗"), Colors.Red(MalwareBlockedHeadline))
printMaliciousPackagesList(data.BlockedPackages)
fmt.Println()
}
+1 -1
View File
@@ -70,7 +70,7 @@ func blockWithExit(config *BlockConfig, exit bool) error {
// already shown to the user in verbose mode as part of the reporting.
if verbosityLevel != VerbosityLevelVerbose {
fmt.Println()
fmt.Printf("%s %s\n", Colors.Red("✗"), Colors.Red("Malicious package blocked"))
fmt.Printf("%s %s\n", Colors.Red("✗"), Colors.Red(MalwareBlockedHeadline))
if config.ShowReference {
printMaliciousPackagesList(config.MalwarePackages)