Files
pmg/cmd/setup/doctor_test.go
T
Sahilb315 e0580b1f79 ci: pin XDG_CONFIG_HOME for the cross-user e2e step; terse doctor fix
GitHub runners export XDG_CONFIG_HOME=/home/runner/.config and it leaks
through sudo -u, so the pmgtest pmg resolved the runner user's config
dir and fail-closed on its runner-owned log file (run 29289868727 shows
the triaged error catching exactly this). Set it inside the login shell
so it wins regardless of how the leak is delivered.

The remedy now returns a full-help and doctor-table pair from a single
triage, and drops the do-not-chown tail from the leak message.
2026-07-14 04:12:27 +05:30

154 lines
4.5 KiB
Go

package setup
import (
"os"
"os/exec"
"path/filepath"
"testing"
"github.com/safedep/pmg/config"
"github.com/safedep/pmg/internal/doctor"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestPathContainsDir(t *testing.T) {
assert.True(t, pathContainsDir([]string{"/usr/local/lib/pmg/bin/"}, "/usr/local/lib/pmg/bin"))
assert.False(t, pathContainsDir([]string{"/usr/local/bin"}, "/usr/local/lib/pmg/bin"))
assert.False(t, pathContainsDir([]string{"/usr/bin"}, ""))
}
func TestPathIsUnderDir(t *testing.T) {
assert.True(t, pathIsUnderDir("/usr/local/lib/pmg/bin/npm", "/usr/local/lib/pmg/bin"))
assert.False(t, pathIsUnderDir("/usr/local/bin/npm", "/usr/local/lib/pmg/bin"))
assert.False(t, pathIsUnderDir("/usr/local/lib/pmg/bin-extra/npm", "/usr/local/lib/pmg/bin"))
}
func TestSystemInstallAliasesPassDoesNotActivateInterception(t *testing.T) {
results := []doctor.CheckResult{
{Name: checkShellAliases, Status: doctor.StatusPass, Message: "No aliases (system install)"},
{Name: checkShimInPath, Status: doctor.StatusFail},
}
assert.False(t, isInterceptionActive(results))
}
func TestAliasesInstalledActivatesInterception(t *testing.T) {
results := []doctor.CheckResult{
{
Name: checkShellAliases,
Status: doctor.StatusPass,
Message: aliasesInstalledMessage,
ImpliesInterception: true,
},
{Name: checkShimInPath, Status: doctor.StatusFail},
}
assert.True(t, isInterceptionActive(results))
}
func TestShimInPathImpliesInterception(t *testing.T) {
results := []doctor.CheckResult{
{
Name: checkShimInPath,
Status: doctor.StatusPass,
Message: "Package managers resolve to System shim directory",
ImpliesInterception: true,
},
}
assert.True(t, isInterceptionActive(results))
}
func TestClassifyPackageManagerResolutions(t *testing.T) {
shimDir := "/usr/local/lib/pmg/bin"
lookPath := func(name string) (string, error) {
switch name {
case "npm":
return shimDir + "/npm", nil
case "pip":
return "/usr/bin/pip", nil
case "uv":
return "", exec.ErrNotFound
default:
return "", exec.ErrNotFound
}
}
under, shadowed := classifyPackageManagerResolutions(
[]string{"npm", "pip", "uv"},
[]string{shimDir},
lookPath,
)
assert.Equal(t, []string{"npm"}, under)
assert.Equal(t, []string{"pip"}, shadowed)
}
func TestClassifyPackageManagerResolutionsAcceptsEitherShimDir(t *testing.T) {
systemDir := "/usr/local/lib/pmg/bin"
userDir := "/home/dev/.pmg/bin"
lookPath := func(name string) (string, error) {
switch name {
case "npm":
return systemDir + "/npm", nil
case "pip":
return userDir + "/pip", nil
default:
return "/usr/bin/" + name, nil
}
}
under, shadowed := classifyPackageManagerResolutions(
[]string{"npm", "pip", "yarn"},
[]string{systemDir, userDir},
lookPath,
)
assert.ElementsMatch(t, []string{"npm", "pip"}, under)
assert.Equal(t, []string{"yarn"}, shadowed)
}
func TestCheckEventLogDirResult(t *testing.T) {
configDir := "/home/dev/.config/safedep/pmg"
t.Run("skipped when event logging disabled", func(t *testing.T) {
result := checkEventLogDirResult(true, t.TempDir(), configDir)
assert.Equal(t, doctor.StatusWarn, result.Status)
})
t.Run("missing directory fails", func(t *testing.T) {
result := checkEventLogDirResult(false, filepath.Join(t.TempDir(), "absent"), configDir)
assert.Equal(t, doctor.StatusFail, result.Status)
assert.Equal(t, "Event log directory not found", result.Message)
})
t.Run("file instead of directory fails", func(t *testing.T) {
path := filepath.Join(t.TempDir(), "logs")
require.NoError(t, os.WriteFile(path, []byte("x"), 0o644))
result := checkEventLogDirResult(false, path, configDir)
assert.Equal(t, doctor.StatusFail, result.Status)
})
t.Run("writable directory passes", func(t *testing.T) {
result := checkEventLogDirResult(false, t.TempDir(), configDir)
assert.Equal(t, doctor.StatusPass, result.Status)
})
t.Run("unwritable directory fails with triaged remedy", func(t *testing.T) {
if os.Geteuid() == 0 {
t.Skip("running as root: directory permissions are not enforced")
}
dir := t.TempDir()
require.NoError(t, os.Chmod(dir, 0o555))
t.Cleanup(func() {
require.NoError(t, os.Chmod(dir, 0o755))
})
result := checkEventLogDirResult(false, dir, configDir)
assert.Equal(t, doctor.StatusFail, result.Status)
assert.Equal(t, "Event log directory not writable", result.Message)
_, expectedFix := config.UnwritableConfigDirRemedy(configDir)
assert.Equal(t, expectedFix, result.Fix)
})
}