fix: clarify system-install doctor alias and shim path checks

Use UserBinDir for PATH checks and pass aliases as not required under
system install without treating that as active interception.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Sahilb315
2026-07-13 15:37:02 +05:30
co-authored by Cursor
parent ffd0e7e759
commit 8d1a4b60e1
3 changed files with 39 additions and 18 deletions
+9 -11
View File
@@ -30,6 +30,8 @@ const (
checkProtectionNpm = "protection-npm" checkProtectionNpm = "protection-npm"
checkProtectionPip = "protection-pip" checkProtectionPip = "protection-pip"
checkCA = "ca-cert" checkCA = "ca-cert"
aliasesInstalledMessage = "Shell aliases installed"
) )
func NewDoctorCommand() *cobra.Command { func NewDoctorCommand() *cobra.Command {
@@ -100,7 +102,7 @@ func runCoreChecks(cfg *config.RuntimeConfig) []doctor.CheckResult {
if err != nil { if err != nil {
return doctor.CheckResult{ return doctor.CheckResult{
Status: doctor.StatusWarn, Status: doctor.StatusWarn,
Message: "Event log directory not found (PMG still runs without event logs)", Message: "Event log directory not found",
} }
} }
if !info.IsDir() { if !info.IsDir() {
@@ -138,13 +140,13 @@ func runCoreChecks(cfg *config.RuntimeConfig) []doctor.CheckResult {
if installed { if installed {
return doctor.CheckResult{ return doctor.CheckResult{
Status: doctor.StatusPass, Status: doctor.StatusPass,
Message: "Shell aliases installed", Message: aliasesInstalledMessage,
} }
} }
if shim.SystemShimsInstalled() { if shim.SystemShimsInstalled() {
return doctor.CheckResult{ return doctor.CheckResult{
Status: doctor.StatusWarn, Status: doctor.StatusPass,
Message: "Aliases not installed (optional with system shims)", Message: "No aliases (system install)",
} }
} }
return doctor.CheckResult{ return doctor.CheckResult{
@@ -196,11 +198,7 @@ func runCoreChecks(cfg *config.RuntimeConfig) []doctor.CheckResult {
Message: "System shim directory is in PATH", Message: "System shim directory is in PATH",
} }
} }
userDir := "" if userDir, err := shim.UserBinDir(); err == nil && pathContainsDir(pathEntries, userDir) {
if home, err := os.UserHomeDir(); err == nil {
userDir = filepath.Join(home, ".pmg", "bin")
}
if pathContainsDir(pathEntries, userDir) {
return doctor.CheckResult{ return doctor.CheckResult{
Status: doctor.StatusPass, Status: doctor.StatusPass,
Message: "Shim directory is in PATH", Message: "Shim directory is in PATH",
@@ -346,10 +344,10 @@ func runProtectionChecks(coreResults []doctor.CheckResult) []doctor.CheckResult
func isInterceptionActive(coreResults []doctor.CheckResult) bool { func isInterceptionActive(coreResults []doctor.CheckResult) bool {
for _, r := range coreResults { for _, r := range coreResults {
if r.Name == checkShellAliases && r.Status == doctor.StatusPass { if r.Name == checkShimInPath && r.Status == doctor.StatusPass {
return true return true
} }
if r.Name == checkShimInPath && r.Status == doctor.StatusPass { if r.Name == checkShellAliases && r.Status == doctor.StatusPass && r.Message == aliasesInstalledMessage {
return true return true
} }
} }
+11 -2
View File
@@ -13,11 +13,20 @@ func TestPathContainsDir(t *testing.T) {
assert.False(t, pathContainsDir([]string{"/usr/bin"}, "")) assert.False(t, pathContainsDir([]string{"/usr/bin"}, ""))
} }
func TestSystemShimsWithoutPathDoNotActivateInterception(t *testing.T) { func TestSystemInstallAliasesPassDoesNotActivateInterception(t *testing.T) {
results := []doctor.CheckResult{ results := []doctor.CheckResult{
{Name: checkShellAliases, Status: doctor.StatusWarn}, {Name: checkShellAliases, Status: doctor.StatusPass, Message: "No aliases (system install)"},
{Name: checkShimInPath, Status: doctor.StatusFail}, {Name: checkShimInPath, Status: doctor.StatusFail},
} }
assert.False(t, isInterceptionActive(results)) assert.False(t, isInterceptionActive(results))
} }
func TestAliasesInstalledActivatesInterception(t *testing.T) {
results := []doctor.CheckResult{
{Name: checkShellAliases, Status: doctor.StatusPass, Message: aliasesInstalledMessage},
{Name: checkShimInPath, Status: doctor.StatusFail},
}
assert.True(t, isInterceptionActive(results))
}
+19 -5
View File
@@ -48,8 +48,13 @@ func NewDefaultShimManager() (*ShimManager, error) {
return nil, err return nil, err
} }
binDir, err := UserBinDir()
if err != nil {
return nil, err
}
return &ShimManager{config: ShimConfig{ return &ShimManager{config: ShimConfig{
BinDir: filepath.Join(homeDir, ".pmg", "bin"), BinDir: binDir,
HomeDir: homeDir, HomeDir: homeDir,
PMGBin: pmgBin, PMGBin: pmgBin,
PackageManagers: aliasCfg.PackageManagers, PackageManagers: aliasCfg.PackageManagers,
@@ -140,6 +145,15 @@ func (m *ShimManager) GetBinDir() string {
return m.config.BinDir return m.config.BinDir
} }
// UserBinDir returns the per-user PMG shim directory (~/.pmg/bin).
func UserBinDir() (string, error) {
homeDir, err := os.UserHomeDir()
if err != nil {
return "", fmt.Errorf("failed to get home directory: %w", err)
}
return filepath.Join(homeDir, ".pmg", "bin"), nil
}
func (m *ShimManager) writeShimScript(pm string) error { func (m *ShimManager) writeShimScript(pm string) error {
shimPath := filepath.Join(m.config.BinDir, pm) shimPath := filepath.Join(m.config.BinDir, pm)
pmgBin := shellQuote(m.config.PMGBin) pmgBin := shellQuote(m.config.PMGBin)
@@ -236,12 +250,12 @@ func (m *ShimManager) removePathFromShells() error {
return nil return nil
} }
// UserShimsInstalled reports whether the per-user shim directory (~/.pmg/bin) // UserShimsInstalled reports whether the per-user shim directory contains at
// contains at least one shim script. // least one shim script.
func UserShimsInstalled() bool { func UserShimsInstalled() bool {
homeDir, err := os.UserHomeDir() binDir, err := UserBinDir()
if err != nil { if err != nil {
return false return false
} }
return shimsPresent(filepath.Join(homeDir, ".pmg", "bin")) return shimsPresent(binDir)
} }