mirror of
https://github.com/opentofu/opentofu.git
synced 2024-12-25 16:31:10 -06:00
providercache: Validate provider executable file
At the end of the EnsureProviderVersions process, we generate a lockfile of the selected and installed provider versions. This includes a hash of the unpacked provider directory. When calculating this hash and generating the lockfile, we now also verify that the provider directory contains a valid executable file. If not, we return an error for this provider and trigger the installer's HashPackageFailure event. Note that this event is not yet processed by terraform init; that comes in the next commit.
This commit is contained in:
parent
a18b531b14
commit
3b1347ac1a
@ -400,6 +400,14 @@ NeedProvider:
|
||||
}
|
||||
continue
|
||||
}
|
||||
if _, err := cached.ExecutableFile(); err != nil {
|
||||
err := fmt.Errorf("provider binary not found: %s", err)
|
||||
errs[provider] = err
|
||||
if cb := evts.HashPackageFailure; cb != nil {
|
||||
cb(provider, version, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
hash, err := cached.Hash()
|
||||
if err != nil {
|
||||
errs[provider] = fmt.Errorf("failed to calculate checksum for installed provider %s package: %s", provider, err)
|
||||
|
@ -11,12 +11,102 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
svchost "github.com/hashicorp/terraform-svchost"
|
||||
"github.com/hashicorp/terraform-svchost/disco"
|
||||
"github.com/hashicorp/terraform/addrs"
|
||||
"github.com/hashicorp/terraform/internal/getproviders"
|
||||
)
|
||||
|
||||
func TestEnsureProviderVersions_local_source(t *testing.T) {
|
||||
// create filesystem source using the test provider cache dir
|
||||
source := getproviders.NewFilesystemMirrorSource("testdata/cachedir")
|
||||
|
||||
// create a temporary workdir
|
||||
tmpDirPath, err := ioutil.TempDir("", "terraform-test-providercache")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDirPath)
|
||||
|
||||
// set up the installer using the temporary directory and filesystem source
|
||||
platform := getproviders.Platform{OS: "linux", Arch: "amd64"}
|
||||
dir := NewDirWithPlatform(tmpDirPath, platform)
|
||||
installer := NewInstaller(dir, source)
|
||||
|
||||
tests := map[string]struct {
|
||||
provider string
|
||||
version string
|
||||
installed bool
|
||||
err string
|
||||
}{
|
||||
"install-unpacked": {
|
||||
provider: "null",
|
||||
version: "2.0.0",
|
||||
installed: true,
|
||||
},
|
||||
"invalid-zip-file": {
|
||||
provider: "null",
|
||||
version: "2.1.0",
|
||||
installed: false,
|
||||
err: "zip: not a valid zip file",
|
||||
},
|
||||
"version-constraint-unmet": {
|
||||
provider: "null",
|
||||
version: "2.2.0",
|
||||
installed: false,
|
||||
err: "no available releases match the given constraints 2.2.0",
|
||||
},
|
||||
"missing-executable": {
|
||||
provider: "missing/executable",
|
||||
version: "2.0.0",
|
||||
installed: true,
|
||||
err: "provider binary not found: could not find executable file starting with terraform-provider-executable",
|
||||
},
|
||||
}
|
||||
|
||||
for name, test := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
ctx := context.TODO()
|
||||
|
||||
provider := addrs.MustParseProviderSourceString(test.provider)
|
||||
versionConstraint := getproviders.MustParseVersionConstraints(test.version)
|
||||
version := getproviders.MustParseVersion(test.version)
|
||||
reqs := getproviders.Requirements{
|
||||
provider: versionConstraint,
|
||||
}
|
||||
wantSelected := getproviders.Selections{provider: version}
|
||||
if !test.installed {
|
||||
wantSelected = getproviders.Selections{}
|
||||
}
|
||||
|
||||
selected, err := installer.EnsureProviderVersions(ctx, reqs, InstallNewProvidersOnly)
|
||||
|
||||
if diff := cmp.Diff(wantSelected, selected); diff != "" {
|
||||
t.Errorf("wrong selected\n%s", diff)
|
||||
}
|
||||
|
||||
if test.err == "" && err == nil {
|
||||
return
|
||||
}
|
||||
|
||||
switch err := err.(type) {
|
||||
case InstallerError:
|
||||
providerError, ok := err.ProviderErrors[provider]
|
||||
if !ok {
|
||||
t.Fatalf("did not get error for provider %s", provider)
|
||||
}
|
||||
|
||||
if got := providerError.Error(); got != test.err {
|
||||
t.Fatalf("wrong result\ngot: %s\nwant: %s\n", got, test.err)
|
||||
}
|
||||
default:
|
||||
t.Fatalf("wrong error type. Expected InstallerError, got %T", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// This test only verifies protocol errors and does not try for successfull
|
||||
// installation (at the time of writing, the test files aren't signed so the
|
||||
// signature verification fails); that's left to the e2e tests.
|
||||
|
Loading…
Reference in New Issue
Block a user