Merge pull request #12475 from hashicorp/backport/nywilken/plugin-scanning/mildly-thankful-yeti

This pull request was automerged via backport-assistant
pull/12480/head
hc-github-team-packer 3 years ago committed by GitHub
commit 8819b9db34
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -16,7 +16,6 @@ import (
"strings"
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
"github.com/hashicorp/packer-plugin-sdk/pathing"
pluginsdk "github.com/hashicorp/packer-plugin-sdk/plugin"
plugingetter "github.com/hashicorp/packer/packer/plugin-getter"
)
@ -80,50 +79,42 @@ func (c *PluginConfig) Discover() error {
return nil
}
// TODO: use KnownPluginFolders here. TODO probably after JSON is deprecated
// so that we can keep the current behavior just the way it is.
// Next, look in the same directory as the executable.
exePath, err := os.Executable()
if err != nil {
log.Printf("[ERR] Error loading exe directory: %s", err)
} else {
if err := c.discoverExternalComponents(filepath.Dir(exePath)); err != nil {
return err
}
if len(c.KnownPluginFolders) == 0 {
c.KnownPluginFolders = PluginFolders()
}
// Next, look in the default plugins directory inside the configdir/.packer.d/plugins.
dir, err := pathing.ConfigDir()
if err != nil {
log.Printf("[ERR] Error loading config directory: %s", err)
} else {
if err := c.discoverExternalComponents(filepath.Join(dir, "plugins")); err != nil {
// TODO after JSON is deprecated remove support for legacy component plugins.
for _, knownFolder := range c.KnownPluginFolders {
if err := c.discoverLegacyMonoComponents(knownFolder); err != nil {
return err
}
}
// Next, look in the CWD.
if err := c.discoverExternalComponents("."); err != nil {
// Pick last folder as it's the one with the highest priority
// This is the same logic used when installing plugins via Packer's plugin installation commands.
pluginInstallationPath := c.KnownPluginFolders[len(c.KnownPluginFolders)-1]
if err := c.discoverInstalledComponents(pluginInstallationPath); err != nil {
return err
}
// Check whether there is a custom Plugin directory defined. This gets
// absolute preference.
if packerPluginPath := os.Getenv("PACKER_PLUGIN_PATH"); packerPluginPath != "" {
sep := ":"
if runtime.GOOS == "windows" {
// on windows, PATH is semicolon-separated
sep = ";"
// Manually installed plugins take precedence over all. Duplicate plugins installed
// prior to the packer plugins install command should be removed by user to avoid overrides.
for _, knownFolder := range c.KnownPluginFolders {
pluginPaths, err := c.discoverSingle(filepath.Join(knownFolder, "packer-plugin-*"))
if err != nil {
return err
}
plugPaths := strings.Split(packerPluginPath, sep)
for _, plugPath := range plugPaths {
if err := c.discoverExternalComponents(plugPath); err != nil {
for pluginName, pluginPath := range pluginPaths {
// Test pluginPath points to an executable
if _, err := exec.LookPath(pluginPath); err != nil {
log.Printf("[WARN] %q is not executable; skipping", pluginPath)
continue
}
if err := c.DiscoverMultiPlugin(pluginName, pluginPath); err != nil {
return err
}
}
}
return nil
}
@ -206,64 +197,86 @@ func (c *PluginConfig) discoverExternalComponents(path string) error {
log.Printf("using external datasource %v", externallyUsed)
}
//Check for installed plugins using the `packer plugins install` command
binInstallOpts := plugingetter.BinaryInstallationOptions{
OS: runtime.GOOS,
ARCH: runtime.GOARCH,
APIVersionMajor: pluginsdk.APIVersionMajor,
APIVersionMinor: pluginsdk.APIVersionMinor,
Checksummers: []plugingetter.Checksummer{
{Type: "sha256", Hash: sha256.New()},
},
}
return nil
}
if runtime.GOOS == "windows" {
binInstallOpts.Ext = ".exe"
func (c *PluginConfig) discoverLegacyMonoComponents(path string) error {
var err error
log.Printf("[TRACE] discovering plugins in %s", path)
if !filepath.IsAbs(path) {
path, err = filepath.Abs(path)
if err != nil {
return err
}
}
var externallyUsed []string
pluginPaths, err = c.discoverSingle(filepath.Join(path, "*", "*", "*", fmt.Sprintf("packer-plugin-*%s", binInstallOpts.FilenameSuffix())))
pluginPaths, err := c.discoverSingle(filepath.Join(path, "packer-builder-*"))
if err != nil {
return err
}
for pluginName, pluginPath := range pluginPaths {
var checksumOk bool
for _, checksummer := range binInstallOpts.Checksummers {
cs, err := checksummer.GetCacheChecksumOfFile(pluginPath)
if err != nil {
log.Printf("[TRACE] GetChecksumOfFile(%q) failed: %v", pluginPath, err)
continue
}
if err := checksummer.ChecksumFile(cs, pluginPath); err != nil {
log.Printf("[TRACE] ChecksumFile(%q) failed: %v", pluginPath, err)
continue
}
checksumOk = true
break
}
if !checksumOk {
log.Printf("[TRACE] No checksum found for %q ignoring possibly unsafe binary", path)
continue
}
newPath := pluginPath // this needs to be stored in a new variable for the func below
c.Builders.Set(pluginName, func() (packersdk.Builder, error) {
return c.Client(newPath).Builder()
})
externallyUsed = append(externallyUsed, pluginName)
}
if len(externallyUsed) > 0 {
sort.Strings(externallyUsed)
log.Printf("[INFO] using external builders: %v", externallyUsed)
externallyUsed = nil
}
if err := c.DiscoverMultiPlugin(pluginName, pluginPath); err != nil {
return err
}
pluginPaths, err = c.discoverSingle(filepath.Join(path, "packer-post-processor-*"))
if err != nil {
return err
}
for pluginName, pluginPath := range pluginPaths {
newPath := pluginPath // this needs to be stored in a new variable for the func below
c.PostProcessors.Set(pluginName, func() (packersdk.PostProcessor, error) {
return c.Client(newPath).PostProcessor()
})
externallyUsed = append(externallyUsed, pluginName)
}
if len(externallyUsed) > 0 {
sort.Strings(externallyUsed)
log.Printf("using external post-processors %v", externallyUsed)
externallyUsed = nil
}
// Manually installed plugins take precedence over all. Duplicate plugins installed
// prior to the packer plugins install command should be removed by user to avoid overrides.
pluginPaths, err = c.discoverSingle(filepath.Join(path, "packer-plugin-*"))
pluginPaths, err = c.discoverSingle(filepath.Join(path, "packer-provisioner-*"))
if err != nil {
return err
}
for pluginName, pluginPath := range pluginPaths {
newPath := pluginPath // this needs to be stored in a new variable for the func below
c.Provisioners.Set(pluginName, func() (packersdk.Provisioner, error) {
return c.Client(newPath).Provisioner()
})
externallyUsed = append(externallyUsed, pluginName)
}
if len(externallyUsed) > 0 {
sort.Strings(externallyUsed)
log.Printf("using external provisioners %v", externallyUsed)
externallyUsed = nil
}
pluginPaths, err = c.discoverSingle(filepath.Join(path, "packer-datasource-*"))
if err != nil {
return err
}
for pluginName, pluginPath := range pluginPaths {
if err := c.DiscoverMultiPlugin(pluginName, pluginPath); err != nil {
return err
}
newPath := pluginPath // this needs to be stored in a new variable for the func below
c.DataSources.Set(pluginName, func() (packersdk.Datasource, error) {
return c.Client(newPath).Datasource()
})
externallyUsed = append(externallyUsed, pluginName)
}
if len(externallyUsed) > 0 {
sort.Strings(externallyUsed)
log.Printf("using external datasource %v", externallyUsed)
}
return nil
@ -291,7 +304,7 @@ func (c *PluginConfig) discoverSingle(glob string) (map[string]string, error) {
// We could do a full PATHEXT parse, but this is probably good enough.
if runtime.GOOS == "windows" && strings.ToLower(filepath.Ext(file)) != ".exe" {
log.Printf(
"[DEBUG] Ignoring plugin match %s, no exe extension",
"[TRACE] Ignoring plugin match %s, no exe extension",
match)
continue
}
@ -307,7 +320,7 @@ func (c *PluginConfig) discoverSingle(glob string) (map[string]string, error) {
// After the split the plugin name is "baz".
pluginName = strings.SplitN(pluginName, "_", 2)[0]
log.Printf("[DEBUG] Discovered plugin: %s = %s", pluginName, match)
log.Printf("[INFO] Discovered potential plugin: %s = %s", pluginName, match)
res[pluginName] = match
}
@ -426,9 +439,9 @@ func (c *PluginConfig) Client(path string, args ...string) *PluginClient {
}
if strings.Contains(originalPath, PACKERSPACE) {
log.Printf("[TRACE] Starting internal plugin %s", args[len(args)-1])
log.Printf("[INFO] Starting internal plugin %s", args[len(args)-1])
} else {
log.Printf("[TRACE] Starting external plugin %s %s", path, strings.Join(args, " "))
log.Printf("[INFO] Starting external plugin %s %s", path, strings.Join(args, " "))
}
var config PluginClientConfig
config.Cmd = exec.Command(path, args...)
@ -437,3 +450,57 @@ func (c *PluginConfig) Client(path string, args ...string) *PluginClient {
config.MaxPort = c.PluginMaxPort
return NewClient(&config)
}
// discoverInstalledComponents scans the provided path for plugins installed by running packer plugins install or packer init.
// Valid plugins contain a matching system binary and valid checksum file.
func (c *PluginConfig) discoverInstalledComponents(path string) error {
//Check for installed plugins using the `packer plugins install` command
binInstallOpts := plugingetter.BinaryInstallationOptions{
OS: runtime.GOOS,
ARCH: runtime.GOARCH,
APIVersionMajor: pluginsdk.APIVersionMajor,
APIVersionMinor: pluginsdk.APIVersionMinor,
Checksummers: []plugingetter.Checksummer{
{Type: "sha256", Hash: sha256.New()},
},
}
if runtime.GOOS == "windows" {
binInstallOpts.Ext = ".exe"
}
pluginPath := filepath.Join(path, "*", "*", "*", fmt.Sprintf("packer-plugin-*%s", binInstallOpts.FilenameSuffix()))
pluginPaths, err := c.discoverSingle(pluginPath)
if err != nil {
return err
}
for pluginName, pluginPath := range pluginPaths {
var checksumOk bool
for _, checksummer := range binInstallOpts.Checksummers {
cs, err := checksummer.GetCacheChecksumOfFile(pluginPath)
if err != nil {
log.Printf("[TRACE] GetChecksumOfFile(%q) failed: %v", pluginPath, err)
continue
}
if err := checksummer.ChecksumFile(cs, pluginPath); err != nil {
log.Printf("[TRACE] ChecksumFile(%q) failed: %v", pluginPath, err)
continue
}
checksumOk = true
break
}
if !checksumOk {
log.Printf("[WARN] No checksum found for %q ignoring possibly unsafe binary", path)
continue
}
if err := c.DiscoverMultiPlugin(pluginName, pluginPath); err != nil {
return err
}
}
return nil
}

@ -16,10 +16,15 @@ import (
func PluginFolders(dirs ...string) []string {
res := []string{}
if packerPluginPath := os.Getenv("PACKER_PLUGIN_PATH"); packerPluginPath != "" {
res = append(res, strings.Split(packerPluginPath, string(os.PathListSeparator))...)
return res
}
if path, err := os.Executable(); err != nil {
log.Printf("[ERR] Error finding executable: %v", err)
} else {
res = append(res, path)
res = append(res, filepath.Dir(path))
}
res = append(res, dirs...)
@ -30,9 +35,5 @@ func PluginFolders(dirs ...string) []string {
res = append(res, filepath.Join(cd, "plugins"))
}
if packerPluginPath := os.Getenv("PACKER_PLUGIN_PATH"); packerPluginPath != "" {
res = append(res, strings.Split(packerPluginPath, string(os.PathListSeparator))...)
}
return res
}

Loading…
Cancel
Save