This commit is contained in:
NARITA 2026-05-25 07:12:26 +00:00 committed by GitHub
commit 8fc0cc8d08
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 103 additions and 7 deletions

View file

@ -0,0 +1,5 @@
kind: BUG FIXES
body: suppress false-positive plugin_cache_dir error when -chdir is used
time: 2025-05-24T03:56:53.347808+09:00
custom:
Issue: "36881"

View file

@ -325,11 +325,17 @@ func (c *Config) Validate() tfdiags.Diagnostics {
}
if c.PluginCacheDir != "" {
_, err := os.Stat(c.PluginCacheDir)
if err != nil {
diags = diags.Append(
fmt.Errorf("The specified plugin cache dir %s cannot be opened: %s", c.PluginCacheDir, err),
)
// Skip validation for relative paths here, as they may be intended
// to be resolved relative to a directory specified by -chdir, which
// is processed after config loading. Relative paths will be
// re-validated later in main.go after any -chdir option is processed.
if filepath.IsAbs(c.PluginCacheDir) {
_, err := os.Stat(c.PluginCacheDir)
if err != nil {
diags = diags.Append(
fmt.Errorf("The specified plugin cache dir %s cannot be opened: %s", c.PluginCacheDir, err),
)
}
}
}

View file

@ -357,12 +357,18 @@ func TestConfigValidate(t *testing.T) {
},
1, // no more than one provider_installation block allowed
},
"plugin_cache_dir does not exist": {
"plugin_cache_dir absolute path does not exist": {
&Config{
PluginCacheDir: "fake",
PluginCacheDir: "/absolute/fake/path",
},
1, // The specified plugin cache dir %s cannot be opened
},
"plugin_cache_dir relative path": {
&Config{
PluginCacheDir: "../relative/fake/path",
},
0, // Relative paths are not validated in early validation phase
},
}
for name, test := range tests {

22
main.go
View file

@ -23,6 +23,7 @@ import (
"github.com/hashicorp/terraform/internal/httpclient"
"github.com/hashicorp/terraform/internal/logging"
"github.com/hashicorp/terraform/internal/terminal"
"github.com/hashicorp/terraform/internal/tfdiags"
"github.com/hashicorp/terraform/version"
"github.com/mattn/go-shellwords"
"github.com/mitchellh/colorstring"
@ -236,6 +237,27 @@ func realMain() int {
Ui.Error(fmt.Sprintf("Error handling -chdir option: %s", err))
return 1
}
// After changing the working directory with -chdir, we need to re-validate
// any relative plugin cache directory paths, since they are resolved relative
// to the current working directory.
if pluginCacheDir := config.PluginCacheDir; pluginCacheDir != "" && !filepath.IsAbs(pluginCacheDir) {
if _, err := os.Stat(pluginCacheDir); err != nil {
Ui.Error("There are some problems with the CLI configuration:")
earlyColor := &colorstring.Colorize{
Colors: colorstring.DefaultColors,
Disable: true,
Reset: true,
}
diag := tfdiags.Sourceless(
tfdiags.Error,
"Invalid plugin cache directory",
fmt.Sprintf("The specified plugin cache dir %s cannot be opened: %s", pluginCacheDir, err),
)
Ui.Error(format.Diagnostic(diag, nil, earlyColor, 78))
Ui.Error("As a result of the above problems, Terraform may not behave as intended.\n\n")
}
}
}
// In tests, Commands may already be set to provide mock commands

View file

@ -7,12 +7,14 @@ import (
"errors"
"fmt"
"os"
"path/filepath"
"reflect"
"strings"
"testing"
"time"
"github.com/hashicorp/cli"
"github.com/hashicorp/terraform/internal/command/cliconfig"
)
func TestMain_cliArgsFromEnv(t *testing.T) {
@ -373,3 +375,58 @@ func TestWarnOutput(t *testing.T) {
t.Fatalf("unexpected stdout: %q\n", stdout)
}
}
func TestPluginCacheDirWithChdir(t *testing.T) {
// Create a temporary directory structure for testing
tmpDir := t.TempDir()
subDir := filepath.Join(tmpDir, "subdir")
cacheDir := filepath.Join(tmpDir, "cache")
if err := os.MkdirAll(subDir, 0755); err != nil {
t.Fatal(err)
}
if err := os.MkdirAll(cacheDir, 0755); err != nil {
t.Fatal(err)
}
// Save original working directory
originalWd, err := os.Getwd()
if err != nil {
t.Fatal(err)
}
defer os.Chdir(originalWd)
// Change to tmpDir
if err := os.Chdir(tmpDir); err != nil {
t.Fatal(err)
}
// Test case 1: Relative path that exists
config := &cliconfig.Config{
PluginCacheDir: "../cache",
}
// Change to subdir (simulating -chdir)
if err := os.Chdir(subDir); err != nil {
t.Fatal(err)
}
// Validate relative path
if pluginCacheDir := config.PluginCacheDir; pluginCacheDir != "" && !filepath.IsAbs(pluginCacheDir) {
if _, err := os.Stat(pluginCacheDir); err != nil {
t.Errorf("Expected relative plugin cache dir to be accessible after chdir, but got error: %v", err)
}
}
// Test case 2: Relative path that doesn't exist
config2 := &cliconfig.Config{
PluginCacheDir: "../nonexistent",
}
// Validate non-existent relative path
if pluginCacheDir := config2.PluginCacheDir; pluginCacheDir != "" && !filepath.IsAbs(pluginCacheDir) {
if _, err := os.Stat(pluginCacheDir); err == nil {
t.Error("Expected non-existent relative plugin cache dir to fail validation")
}
}
}