When introduced back in January, the version variable extracted from the
binary name had a typo in its name, and was named `protocolVerionStr'
instead of `protocolVersionStr'.
This commit was already merged into main, so it's too late to fix at
introduction site, but we can fix it today as a separate commit ontop
the stack.
If a plugin is installed manually, its version number could be valid but
non-canonical (ex: 1.2.3 vs 01.002.0003).
Since these two versions refer to the same version, but the looks are
different, this may become ambiguous which version should be loaded.
To avoid such a situation, we reject explicitely non-canonical version
numbers in plugins, but only in path, we're aware that because of
metadata, the version from `describe' may already differ from the file
name.
The former way mock plugin sets were created meant that no API version
was set, and since it's private in the SDK, it cannot be set outside of
the package itself.
Fortunately, there is a NewSet function we can call, which initialises a
set properly so we can fill-in the information later.
However, because all the set maps were created in a `var` section, we
cannot create the set with `NewSet`, and then fill the information in
(outside of if there was a fluent interface, but this isn't the case
here).
We therefore opted to keep the variables defined and accessible
globally, but gone through a `init` function to initialise their values
for tests.
As with versions, API versions are useful possibly for ordering plugin
installations in order for Packer to choose which plugin to load.
This could be unnecessary as API versions are stable, and only in dev
plugins this could be a problem normally (there shouldn't be two same
releases of a plugin), but this cements API version in ordering plugins
so we avoid surprises later down the line.
As with the version of the plugin, the API version should also match
between the path and the self-reported API version from the describe
command.
This was not checked before, so users could masquerade a plugin's use of
an API version that may be incompatible with Packer.
To avoid this problem, we make sure both versions are the same, so that
they work as expected.
When installing plugins with the `packer plugins install --path'
command, the metadata is now scrubbed from the file installed locally.
This is as a protection against collisions in the versions, as metadata
is meaningless for version comparison, so if two versions of the same
plugin are installed, the precedence order between them is undefined.
Therefore to avoid such collisions, we remove the metadata from the file
name, that way if two successive versions of a plugin include metadata
in the version, they won't coexist, and the last installed will be the
only installed version locally.
When installing a plugin from a local binary, Packer builds the name of
the plugin from the results of the `describe' command.
Depending on how the plugin is built, the version reported may or may
not contain a leading `v', which was not taken into account beforehand
and the leading `v' was always injected in the path.
This caused plugins that report a leading `v' in their version to
be installed with two v's in their path, making them impossible to load.
Therefore to fix this issue, we count on the version library to print
out a version without the leading v, and we inject that in the resulting
path.
When Packer discovers binary a bunch of checks are performed, which
ultimately end with a checksum match check.
This however should be the very first thing we do, even before
attempting to run `describe' on the plugin binary we're discovering.
So this commit moves this checksum match to the top of the discovery
process for binaries.
When discovering the installed plugins locally, we perform a couple of
checks on the version, namely that it is valid, if it is a prerelease,
it needs to be a dev, and that the self-reported version matches the one
hinted at through the name of the binary.
This was done through regexes, but those were a wee bit simple when
dealing with versions that have metadata. Those binaries would be
completely ignored by Packer, and never loaded, although they are a
valid use case.
The version library we already used supports those however, and
comparisons are more reliable with them.
So, in order to simplify our code, and make it more reliable, we're
exclusively using this library to perform parsing and comparisons of
versions during the discovery phase.
Since v1.11.0 should fix the version ordering to work with semver
comparison instead of reliying on glob (lexicographic), we should call
out the problem in the CHANGELOG.
The test directory contains artifacts from the project's past which are
never used nowadays. All those remains are therefore removed with this
commit, and we can replace that directory's contents with more
up-to-date contents.
The packer plugins remove command allows users to delete plugins
installed locally.
Previous versions of the command only allowed for the plugins to be
removed using the source for a plugin, and the versions to remove,
optionally.
This commit adds the capability for the plugins to be removed using
their local path, in addition to the regular source+version method, that
way we are able to pipe the results of `packer plugins installed' into
the plugins remove command for quick plugin removal.
The plugin and plugins command had a name that was close, and while
plugin is not supposed to be directly called by Packer users, this could
happen by accident while trying to execute packer plugins subcommands,
and when it does, the error messages are far from explicit, so unless
they understand what Packer is doing here, they'll likely be lost.
To reduce the risk of confusion, we rename the command to run packer
embedded components as execute.
The fmt command reformats HCL2 templates, provided it can parse the file
and reformat its contents according to the standards set by the HCL
library's formatters.
However, if the file is malformed for some reason, the command will fail
with a parse error, but while the parse error message is shown, the
actual errors in the template(s) are not forwarded, making it hard for
users to understand what went wrong with the contents of the file
they're trying to format.
In order to be more helpful with those errors, we now forward those
parsing errors to the UI.
This change addresses vulnerabilities reported by govulncheck
```
Vulnerability #1: GO-2024-2610
Errors returned from JSON marshaling may break template escaping in
html/template
More info: https://pkg.go.dev/vuln/GO-2024-2610
Standard library
Found in: html/template@go1.22
Fixed in: html/template@go1.22.1
Example traces found:
#1: datasource/http/data.go:119:24: http.Datasource.Execute calls http.Client.Do, which eventually calls template.Template.Execute
#2: datasource/http/data.go:119:24: http.Datasource.Execute calls http.Client.Do, which eventually calls template.Template.ExecuteTemplate
Vulnerability #2: GO-2024-2600
Incorrect forwarding of sensitive headers and cookies on HTTP redirect in
net/http
More info: https://pkg.go.dev/vuln/GO-2024-2600
Standard library
Found in: net/http@go1.22
Fixed in: net/http@go1.22.1
Example traces found:
#1: datasource/http/data.go:119:24: http.Datasource.Execute calls http.Client.Do
#2: hcl2template/function/aws_secretetkey.go:38:37: function.init calls template.GetAWSSecret, which eventually calls http.Client.Post
#3: hcl2template/function/aws_secretetkey.go:38:37: function.init calls template.GetAWSSecret, which eventually calls http.Client.PostForm
Vulnerability #3: GO-2024-2599
Memory exhaustion in multipart form parsing in net/textproto and net/http
More info: https://pkg.go.dev/vuln/GO-2024-2599
Standard library
Found in: net/textproto@go1.22
Fixed in: net/textproto@go1.22.1
Example traces found:
#1: internal/hcp/api/service_build.go:81:48: api.Client.UpdateBuild calls packer_service.Client.PackerServiceUpdateBuild, which eventually calls textproto.Reader.ReadLine
#2: datasource/http/data.go:140:26: http.Datasource.Execute calls io.ReadAll, which eventually calls textproto.Reader.ReadMIMEHeader
Vulnerability #4: GO-2024-2598
Verify panics on certificates with an unknown public key algorithm in
crypto/x509
More info: https://pkg.go.dev/vuln/GO-2024-2598
Standard library
Found in: crypto/x509@go1.22
Fixed in: crypto/x509@go1.22.1
Example traces found:
#1: datasource/http/data.go:140:26: http.Datasource.Execute calls io.ReadAll, which eventually calls x509.Certificate.Verify
```
While migrating to a unified approach for loading plugins, the API
major and minor versions were not added to the constraints for
discovering plugins from the environment, leading to Packer potentially
considering plugins that are not compatible with itself.
This should not be possible, but was due to this omission, which we fix
with this commit.
In order to test the Packer subcommands, some tests rely on a plugin:
github.com/sylviamoss/comment.
This plugin is outdated compared to our SDK, and some of the binaries
releases don't match what is expected by Packer, i.e. v1.0.0 vs. v0.2.8.
To fix that, we migrate to use the hashicups plugin, which is our demo
plugin for Packer, and is actually maintained, and up-to-date, which
will make those tests more reliable moving forward.
Since we now support loading pre-releases with Packer subcommands, we
relax the contraints we had placed on the `--path' option, so it will
accept any `-dev' binary, in addition to final releases.
Since we added the capability for the plugin discovery to ignore
installed pre-releases of plugins, we give that capacity to the validate
and build commands, through a new command-line flag: release-only.
Since we now support loading pre-releases, we also want Packer to be
able to ignore them by user demand, so we put in place the
infrastructure to modulate this.
When Packer is loaded, we used to perform plugin discovery.
This was done for every call to Packer, including when it is executed as
a plugin, arguably against what the comments document.
Doing this as early in the loading process makes it harder to change
this behaviour, as we'd need to introduce flags aside from the rest, and
handle them manually, which is not optimal.
Therefore, we change this: now when Packer starts executing, it will not
attempt to discover installed plugins anymore, and instead will only try
to load them when a configuration has been parsed, and is being used to
perform actions (typically build/validate).
When a pre-release version of a plugin is locally installed, it may or
may not be loaded depending on the constraints expressed in the template
being executed.
If the template contains constraints for loading the plugin, it would be
ignored, while if that wasn't present, it would be loaded.
This is inconsistent, and deserves to be addressed, which is what this
commit does.
With this change, plugin pre-releases are now loaded, provided the
version reported matches the constraints, independently from its
pre-release suffix `-dev'.
Also, if a release with the same version is also installed alongside the
pre-release version of a plugin, it will have precedence over the
pre-release.
When Packer orders the plugins by their version, we'd assumed it was
ordered from highest to lowest.
However, this was the case because our implementation of `Less' was
actually returning `>=', which is not what it was supposed to do.
This commit therefore fixes the implementation of `Less' to do what it
is documented to do, and ensures the behaviour is correct through
additional testing.
Changing this requires some changes to the loading process as well
because of the aforementioned assumption with regards to ordering.
Since the plugins remove subcommand now only loads valid plugins, it
cannot run on mock data anymore, and the logic for creating a valid
plugin hierarchy is not present in this repository, but does in another,
so we move those tests from here to that repository in order to continue
testing them.
When a plugin is loaded from Packer, we now check that the version it
reports matches what the name implies. In case there's a mismatch, we
log, and reject the binary.
Right now we had two paths for discovering installed plugins, i.e.
through plugin-getter's `ListInstallations' function, or through the
`Discover' call, which relied on a glob to list the installations.
This was required since we allowed plugins to be installed in multiple
locations, and with different constraints.
Now that we force a certain convention, we can consolidate the logic
into ListInstallations, and rely on that logic in `Discover' to load a
plugin into the PluginConfig for the current Packer run.
The plugin installation list should be sorted according to a name first,
then version second basis.
Right now, we only rely on the glob to add plugin installs to this list,
making the order unreliable since the lexicographical order is not the
order in which we want to see the same plugin ordered (e.g. v1.0.9 >
1.0.10).
To fix this, we implement a logic for sorting a list of installations
that does what's described above with more accuracy.
Since the plugin directory should now be unique instead of a list, we
can use it directly from the receiver's structure instead of as a
parameter to the function.