mirror of
https://github.com/safedep/pmg.git
synced 2026-08-03 07:24:09 +02:00
* fix: fail fast with clear error when package manager is not installed When PMG shims intercept a package manager that isn't installed (e.g. a clean JAMF-provisioned laptop where PMG is set up before dev tooling), real-binary resolution failed with a generic "unknown" error and a bug-report link, making it look like PMG itself had crashed. Introduce a typed BinaryNotFoundError that exits with code 127 (standard "command not found") and maps to a new PackageManagerNotFound error code with an actionable message instead of the Unknown classification. Co-authored-by: Cursor <cursoragent@cursor.com> * fix: improve missing package manager help message Use a concise, dynamic install hint instead of explaining PMG's PATH forwarding internals. Co-authored-by: Cursor <cursoragent@cursor.com> * fix: mention PATH in missing package manager help text Covers the common case where a package manager is installed but its bin directory is not on PATH yet (e.g. after curl | bash install). Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
121 lines
2.9 KiB
Go
121 lines
2.9 KiB
Go
package runner
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/safedep/pmg/config"
|
|
"github.com/safedep/pmg/internal/shim"
|
|
"github.com/safedep/pmg/packagemanager"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestMergeEnvOverridesExistingValues(t *testing.T) {
|
|
env := mergeEnv(
|
|
[]string{
|
|
"PATH=/usr/bin",
|
|
"HTTP_PROXY=http://old-proxy",
|
|
"NO_PROXY=localhost",
|
|
},
|
|
[]string{
|
|
"HTTP_PROXY=http://pmg-proxy",
|
|
"HTTPS_PROXY=http://pmg-proxy",
|
|
"NO_PROXY=localhost,127.0.0.1",
|
|
},
|
|
)
|
|
|
|
assert.Equal(t, []string{
|
|
"PATH=/usr/bin",
|
|
"HTTP_PROXY=http://pmg-proxy",
|
|
"NO_PROXY=localhost,127.0.0.1",
|
|
"HTTPS_PROXY=http://pmg-proxy",
|
|
}, env)
|
|
}
|
|
|
|
func TestModeEnvOverrides(t *testing.T) {
|
|
opts := ExecuteOptions{
|
|
EnvOverrides: []string{"HTTP_PROXY=http://pmg-proxy"},
|
|
DirectEnvOverrides: []string{"CI=true"},
|
|
PTYEnvOverrides: []string{"TERM=xterm-256color"},
|
|
}
|
|
|
|
assert.Equal(t,
|
|
[]string{"HTTP_PROXY=http://pmg-proxy", "CI=true"},
|
|
modeEnvOverrides(opts, ExecutionModeDirect),
|
|
)
|
|
|
|
assert.Equal(t,
|
|
[]string{"HTTP_PROXY=http://pmg-proxy", "TERM=xterm-256color"},
|
|
modeEnvOverrides(opts, ExecutionModePTY),
|
|
)
|
|
}
|
|
|
|
func TestExecutionModeAuto(t *testing.T) {
|
|
assert.Equal(t, ExecutionModePTY, executionMode(ExecuteOptions{
|
|
Mode: ExecutionModeAuto,
|
|
IsInteractive: func() bool { return true },
|
|
}))
|
|
|
|
assert.Equal(t, ExecutionModeDirect, executionMode(ExecuteOptions{
|
|
Mode: ExecutionModeAuto,
|
|
IsInteractive: func() bool { return false },
|
|
}))
|
|
}
|
|
|
|
func TestExecuteWithOptionsRunsDirectHookBeforeSandbox(t *testing.T) {
|
|
cfg := config.Get()
|
|
previous := *cfg
|
|
t.Cleanup(func() {
|
|
*cfg = previous
|
|
})
|
|
|
|
cfg.Config.Sandbox.Enabled = true
|
|
cfg.Config.Sandbox.Policies = map[string]config.SandboxPolicyRef{}
|
|
|
|
exe, err := os.Executable()
|
|
require.NoError(t, err)
|
|
|
|
hookCalled := false
|
|
err = ExecuteWithOptions(context.Background(), &packagemanager.ParsedCommand{
|
|
Command: packagemanager.Command{
|
|
Exe: exe,
|
|
},
|
|
}, ExecuteOptions{
|
|
PackageManagerName: "npm",
|
|
Mode: ExecutionModeDirect,
|
|
BeforeDirectRun: func() error {
|
|
hookCalled = true
|
|
return nil
|
|
},
|
|
})
|
|
|
|
require.Error(t, err)
|
|
assert.True(t, hookCalled)
|
|
}
|
|
|
|
func TestExecuteWithOptionsMissingPackageManager(t *testing.T) {
|
|
tmpDir := t.TempDir()
|
|
pmgBin := filepath.Join(tmpDir, ".pmg", "bin")
|
|
require.NoError(t, os.MkdirAll(pmgBin, 0o755))
|
|
require.NoError(t, os.WriteFile(filepath.Join(pmgBin, "bun"), []byte("#!/bin/sh\necho shim"), 0o755))
|
|
|
|
t.Setenv("PATH", pmgBin)
|
|
|
|
err := ExecuteWithOptions(context.Background(), &packagemanager.ParsedCommand{
|
|
Command: packagemanager.Command{
|
|
Exe: "bun",
|
|
Args: []string{"--version"},
|
|
},
|
|
}, ExecuteOptions{
|
|
PackageManagerName: "bun",
|
|
})
|
|
|
|
var notFound *shim.BinaryNotFoundError
|
|
require.ErrorAs(t, err, ¬Found)
|
|
assert.Equal(t, "bun", notFound.Name)
|
|
assert.Equal(t, 127, notFound.ExitCode())
|
|
}
|