mirror of
https://github.com/safedep/pmg.git
synced 2026-08-03 07:24:09 +02:00
* feat: add doctor check runner core types and logic * feat: add doctor checks for config, binary, directory, and aliases * feat: add doctor checks for sandbox and security features * feat: add protection verification check using test malicious packages * feat: add summarized package manager availability check * feat: add pmg setup doctor command with compact output * feat: add PATH shim verification to doctor command * fix: improve doctor command UX and alias detection - Capitalize all check messages for consistent output - Dim passing checks, color warn/fail for visual clarity - Silence empty Cobra error output on doctor failure - Remove redundant pmg binary check (self-evident) - Fix alias IsInstalled to skip commented-out source lines - Improve protection failure message * refactor: remove package manager availability check from doctor * fix: handle os.RemoveAll error in doctor protection check * refactor: use table layout for setup doctor, extract shared table renderer Move renderTable, truncate, and visibleWidth helpers from cmd/sandbox to internal/ui so both sandbox and setup doctor share them. Rewrite setup doctor output to use the same table structure as sandbox doctor. Fix VisibleWidth to count runes instead of bytes for correct alignment with multi-byte UTF-8 characters. * docs: add pmg setup doctor to README, remove manual verification step * refactor: use constants for check names, rename and inline doctor helpers Address PR review comments: extract check name constants, rename CheckConfigFile to CheckFileExists and CheckDirectoryWritable to CheckDirectoryExists for reusability, inline trivial wrappers (CheckSandbox, CheckSecurityFeature, CheckProxyMode), and add fix hints for all checks with correct config keys. * refactor: inline simple doctor checks into command layer * fix: skip protection check when aliases and shims are inactive Protection checks now fail immediately when shell aliases and shims are both inactive, instead of falsely passing by running through the pmg binary directly. Also clean up summary messages to remove redundant fix hints and truncated paths.
138 lines
4.1 KiB
Go
138 lines
4.1 KiB
Go
package setup
|
||
|
||
import (
|
||
"fmt"
|
||
"runtime"
|
||
|
||
"github.com/safedep/pmg/config"
|
||
"github.com/safedep/pmg/internal/alias"
|
||
"github.com/safedep/pmg/internal/shim"
|
||
"github.com/safedep/pmg/internal/ui"
|
||
"github.com/safedep/pmg/internal/version"
|
||
"github.com/spf13/cobra"
|
||
)
|
||
|
||
var setupRemoveConfigFile = false
|
||
|
||
func NewSetupCommand() *cobra.Command {
|
||
setupCmd := &cobra.Command{
|
||
Use: "setup",
|
||
Short: "Manage PMG shell integration (aliases and shims)",
|
||
Long: "Setup and manage PMG config, shell aliases and PATH shims that allow you to use package manager commands with security guardrails.",
|
||
RunE: func(cmd *cobra.Command, args []string) error {
|
||
return cmd.Help()
|
||
},
|
||
}
|
||
|
||
setupCmd.AddCommand(NewInstallCommand())
|
||
setupCmd.AddCommand(NewRemoveCommand())
|
||
setupCmd.AddCommand(NewInfoCommand())
|
||
setupCmd.AddCommand(NewDoctorCommand())
|
||
|
||
return setupCmd
|
||
}
|
||
|
||
func NewInstallCommand() *cobra.Command {
|
||
return &cobra.Command{
|
||
Use: "install",
|
||
Short: "Setup PMG config, aliases, and shims for package managers (npm, pnpm, pip, and more)",
|
||
SilenceUsage: true,
|
||
RunE: func(cmd *cobra.Command, args []string) error {
|
||
fmt.Print(ui.GeneratePMGBanner(version.Version, version.Commit))
|
||
return install()
|
||
},
|
||
}
|
||
}
|
||
|
||
func install() error {
|
||
if err := config.WriteTemplateConfig(); err != nil {
|
||
return fmt.Errorf("failed to write template config: %w", err)
|
||
}
|
||
|
||
if config.Get().IsManaged() {
|
||
fmt.Printf("%s %s\n", ui.Colors.Dim("ℹ"),
|
||
fmt.Sprintf("Using globally managed config: %s", config.Get().ConfigFilePath()))
|
||
}
|
||
|
||
if runtime.GOOS == "windows" {
|
||
fmt.Printf("%s %s\n", ui.Colors.Green("✓"), "PMG config written successfully")
|
||
fmt.Printf(" %s\n", ui.Colors.Dim(fmt.Sprintf("Config: %s", config.Get().ConfigDir())))
|
||
fmt.Printf("\n%s Shell aliases and PATH shims are not supported on Windows. Use WSL for full shell integration.\n",
|
||
ui.Colors.Yellow("⚠"))
|
||
return nil
|
||
}
|
||
|
||
cfg := alias.DefaultConfig()
|
||
rcFileManager, err := alias.NewDefaultRcFileManager(cfg.RcFileName)
|
||
if err != nil {
|
||
return fmt.Errorf("failed to create alias manager: %w", err)
|
||
}
|
||
|
||
aliasManager := alias.New(cfg, rcFileManager)
|
||
if err := aliasManager.Install(); err != nil {
|
||
return fmt.Errorf("failed to install aliases: %w", err)
|
||
}
|
||
|
||
shimMgr, err := shim.NewDefaultShimManager()
|
||
if err != nil {
|
||
return fmt.Errorf("failed to create shim manager: %w", err)
|
||
}
|
||
|
||
if err := shimMgr.Install(); err != nil {
|
||
return fmt.Errorf("failed to install shims: %w", err)
|
||
}
|
||
|
||
ui.PrintSetupInstallCmdInfo(aliasManager.GetRcPath(), shimMgr.GetBinDir(), config.Get().ConfigDir())
|
||
return nil
|
||
}
|
||
|
||
func NewRemoveCommand() *cobra.Command {
|
||
cmd := &cobra.Command{
|
||
Use: "remove",
|
||
Short: "Removes pmg aliases and shims from the user's shell config.",
|
||
SilenceUsage: true,
|
||
RunE: func(cmd *cobra.Command, args []string) error {
|
||
fmt.Print(ui.GeneratePMGBanner(version.Version, version.Commit))
|
||
|
||
if setupRemoveConfigFile {
|
||
// Only ever remove the per-user file; the globally managed
|
||
// config is not ours to delete from a per-user uninstall.
|
||
if err := config.RemoveUserConfigFile(); err != nil {
|
||
return err
|
||
}
|
||
}
|
||
|
||
if runtime.GOOS == "windows" {
|
||
fmt.Printf("%s %s\n", ui.Colors.Green("✓"), "PMG config removed. No aliases or shims to clean up on Windows.")
|
||
return nil
|
||
}
|
||
|
||
cfg := alias.DefaultConfig()
|
||
rcFileManager, err := alias.NewDefaultRcFileManager(cfg.RcFileName)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
aliasManager := alias.New(cfg, rcFileManager)
|
||
if err := aliasManager.Remove(); err != nil {
|
||
return fmt.Errorf("failed to remove aliases: %w", err)
|
||
}
|
||
|
||
shimMgr, err := shim.NewDefaultShimManager()
|
||
if err != nil {
|
||
return fmt.Errorf("failed to create shim manager: %w", err)
|
||
}
|
||
|
||
if err := shimMgr.Remove(); err != nil {
|
||
return fmt.Errorf("failed to remove shims: %w", err)
|
||
}
|
||
|
||
fmt.Printf("%s %s\n", ui.Colors.Green("✓"), "PMG aliases and shims removed. Restart your terminal for changes to take effect")
|
||
return nil
|
||
},
|
||
}
|
||
|
||
cmd.Flags().BoolVar(&setupRemoveConfigFile, "config-file", false, "Remove the config file")
|
||
return cmd
|
||
}
|