addrs: limit source component length to 16

When specifying/installing plugins, a source URI is required for Packer
to be able to locate or install a plugin to the local plugin hierarchy.

The plugin hierarchy is based on the plugin source, where each component
in this hierarchy will become a directory.

In order to avoid sources with too many levels of nesting, causing a lot
of mkdirs, we limit the number of sources to 16 in this commit, this
should be long enough for most of our users.
This commit is contained in:
Lucas Bajolet 2024-05-09 11:30:06 -04:00 committed by Lucas Bajolet
parent 9f3dd5b72a
commit 9b38e0eb5c
3 changed files with 33 additions and 3 deletions

View file

@ -218,7 +218,20 @@ func ParsePluginSourceString(str string) (*Plugin, hcl.Diagnostics) {
})
}
return &Plugin{
plug := &Plugin{
Source: str,
}, diags
}
if len(plug.Parts()) > 16 {
return nil, diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Too many parts to source URL",
Detail: fmt.Sprintf("The source URL must have at most 16 components, and the one provided has %d.\n"+
"This is unsupported by Packer, please consider using a source that has less components to it.\n"+
"If this is a blocking issue for you, please open an issue to ask for supporting more "+
"components to the source URI.",
len(plug.Parts())),
})
}
return plug, diags
}

View file

@ -20,6 +20,7 @@ func TestPluginParseSourceString(t *testing.T) {
{"invalid: only one component, rejected", "potato", nil, true},
{"valid: two components in name", "hashicorp/azr", &Plugin{"hashicorp/azr"}, false},
{"valid: three components, nothing superfluous", "github.com/hashicorp/azr", &Plugin{"github.com/hashicorp/azr"}, false},
{"valid: 16 components, nothing superfluous", "github.com/hashicorp/azr/a/b/c/d/e/f/g/h/i/j/k/l/m", &Plugin{"github.com/hashicorp/azr/a/b/c/d/e/f/g/h/i/j/k/l/m"}, false},
{"invalid: trailing slash", "github.com/hashicorp/azr/", nil, true},
{"invalid: reject because scheme specified", "https://github.com/hashicorp/azr", nil, true},
{"invalid: reject because query non nil", "github.com/hashicorp/azr?arg=1", nil, true},
@ -28,6 +29,7 @@ func TestPluginParseSourceString(t *testing.T) {
{"invalid: leading slashes are removed", "/github.com/hashicorp/azr", nil, true},
{"invalid: plugin name contains packer-", "/github.com/hashicorp/packer-azr", nil, true},
{"invalid: plugin name contains packer-plugin-", "/github.com/hashicorp/packer-plugin-azr", nil, true},
{"invalid: 17 components, too many parts to URL", "github.com/hashicorp/azr/a/b/c/d/e/f/g/h/i/j/k/l/m/n", nil, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {

View file

@ -182,7 +182,22 @@ func (pr Requirement) getPluginBinaries(opts ListInstallationsOptions) ([]string
return nil, err
}
return matches, err
retMatches := make([]string, 0, len(matches))
// Don't keep plugins that are nested too deep in the hierarchy
for _, match := range matches {
dir := strings.Replace(filepath.Dir(match), opts.PluginDirectory, "", 1)
parts := strings.FieldsFunc(dir, func(r rune) bool {
return r == '/'
})
if len(parts) > 16 {
log.Printf("[WARN] plugin %q ignored, too many levels of depth: %d (max 16)", match, len(parts))
continue
}
retMatches = append(retMatches, match)
}
return retMatches, err
}
// ListInstallations lists unique installed versions of plugin Requirement pr