Skip to content

Commit

Permalink
Drop support for plugin SDK v0.14/v0.15 (#2203)
Browse files Browse the repository at this point in the history
  • Loading branch information
wata727 authored Jan 12, 2025
1 parent b638d2f commit 7a23f6a
Show file tree
Hide file tree
Showing 5 changed files with 17 additions and 146 deletions.
7 changes: 1 addition & 6 deletions docs/developer-guide/api_compatibility.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,9 @@
This is an internal documentation summarizing the currently supported SDK and TFLint versions and any compatibility caveats.

Protocol version: 11
SDK version: v0.14.0+
SDK version: v0.16.0+
TFLint version: v0.42.0+

- Client-side value handling is introduced in SDK v0.16.0 and TFLint v0.46.0. TFLint v0.45.0 returns an error instead of a value.
- https://github.com/terraform-linters/tflint/pull/1700
- https://github.com/terraform-linters/tflint/pull/1722
- https://github.com/terraform-linters/tflint-plugin-sdk/pull/235
- https://github.com/terraform-linters/tflint-plugin-sdk/pull/239
- Ephemeral value is introduced in SDK v0.22.0 and TFLint v0.55.0. TFLint returns ErrSensitive instead of ephemeral values to plugins built with SDK v0.21.0.
- https://github.com/terraform-linters/tflint/pull/2178
- https://github.com/terraform-linters/tflint-plugin-sdk/pull/358
2 changes: 1 addition & 1 deletion plugin/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ var (
)

// SDKVersionConstraints is the version constraint of the supported SDK version.
var SDKVersionConstraints = version.MustConstraints(version.NewConstraint(">= 0.14.0"))
var SDKVersionConstraints = version.MustConstraints(version.NewConstraint(">= 0.16.0"))

// Plugin is an object handling plugins
// Basically, it is a wrapper for go-plugin and provides an API to handle them collectively.
Expand Down
63 changes: 13 additions & 50 deletions plugin/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,59 +144,22 @@ func (s *GRPCServer) EvaluateExpr(expr hcl.Expression, opts sdk.EvaluateExprOpti
return val, diags
}

// SDK v0.16+ introduces client-side handling of unknown/NULL/sensitive values.
if s.clientSDKVersion != nil && s.clientSDKVersion.GreaterThanOrEqual(version.Must(version.NewVersion("0.16.0"))) {
// Before SDK v0.22, ephemeral marks are ignored, so retrun ErrSensitive to prevent secrets ​​from being leaked.
if !marks.Contains(val, marks.Ephemeral) || s.clientSDKVersion.GreaterThanOrEqual(version.Must(version.NewVersion("0.22.0"))) {
return val, nil
}
}

if val.ContainsMarked() {
err := fmt.Errorf(
"sensitive value found in %s:%d%w",
expr.Range().Filename,
expr.Range().Start.Line,
sdk.ErrSensitive,
)
log.Printf("[INFO] %s. TFLint ignores expressions with sensitive values.", err)
return cty.NullVal(cty.NilType), err
}

if *opts.WantType == cty.DynamicPseudoType {
// If an ephemeral mark is contained, cty.Value will not be returned
// unless the plugin is built with SDK 0.22+ which supports ephemeral marks.
if !marks.Contains(val, marks.Ephemeral) || s.clientSDKVersion.GreaterThanOrEqual(version.Must(version.NewVersion("0.22.0"))) {
return val, nil
}

err := cty.Walk(val, func(path cty.Path, v cty.Value) (bool, error) {
if !v.IsKnown() {
err := fmt.Errorf(
"unknown value found in %s:%d%w",
expr.Range().Filename,
expr.Range().Start.Line,
sdk.ErrUnknownValue,
)
log.Printf("[INFO] %s. TFLint can only evaluate provided variables and skips dynamic values.", err)
return false, err
}

if v.IsNull() {
err := fmt.Errorf(
"null value found in %s:%d%w",
expr.Range().Filename,
expr.Range().Start.Line,
sdk.ErrNullValue,
)
log.Printf("[INFO] %s. TFLint ignores expressions with null values.", err)
return false, err
}

return true, nil
})
if err != nil {
return cty.NullVal(cty.NilType), err
}

return val, nil
// Plugins that do not support ephemeral marks will return ErrSensitive to prevent secrets from being exposed.
// Do not return ErrEphemeral as it is not supported by plugins.
err := fmt.Errorf(
"ephemeral value found in %s:%d%w",
expr.Range().Filename,
expr.Range().Start.Line,
sdk.ErrSensitive,
)
log.Printf("[INFO] %s. TFLint ignores ephemeral values for plugins built with SDK versions earlier than v0.22.", err)
return cty.NullVal(cty.NilType), err
}

// EmitIssue stores an issue in the server based on passed rule, message, and location.
Expand Down
88 changes: 0 additions & 88 deletions plugin/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,6 @@ variable "foo" {

server := NewGRPCServer(runner, rootRunner, runner.Files(), SDKVersion)

sdkv15 := version.Must(version.NewVersion("0.15.0"))
sdkv21 := version.Must(version.NewVersion("0.21.0"))

// test util functions
Expand Down Expand Up @@ -525,29 +524,6 @@ variable "foo" {
Want: cty.StringVal("foo").Mark(marks.Sensitive),
ErrCheck: neverHappend,
},
{
Name: "sensitive value (SDK v0.15)",
Args: func() (hcl.Expression, sdk.EvaluateExprOption) {
return hclExpr(`var.sensitive`), sdk.EvaluateExprOption{WantType: &cty.String, ModuleCtx: sdk.SelfModuleCtxType}
},
Want: cty.NullVal(cty.NilType),
SDKVersion: sdkv15,
ErrCheck: func(err error) bool {
return err == nil || !errors.Is(err, sdk.ErrSensitive)
},
},
{
Name: "sensitive value in object (SDK v0.15)",
Args: func() (hcl.Expression, sdk.EvaluateExprOption) {
ty := cty.Object(map[string]cty.Type{"value": cty.String})
return hclExpr(`{ value = var.sensitive }`), sdk.EvaluateExprOption{WantType: &ty, ModuleCtx: sdk.SelfModuleCtxType}
},
Want: cty.NullVal(cty.NilType),
SDKVersion: sdkv15,
ErrCheck: func(err error) bool {
return err == nil || !errors.Is(err, sdk.ErrSensitive)
},
},
{
Name: "sensitive value (SDK v0.21)",
Args: func() (hcl.Expression, sdk.EvaluateExprOption) {
Expand All @@ -565,38 +541,6 @@ variable "foo" {
Want: cty.UnknownVal(cty.String),
ErrCheck: neverHappend,
},
{
Name: "no default (SDK v0.15)",
Args: func() (hcl.Expression, sdk.EvaluateExprOption) {
return hclExpr(`var.no_default`), sdk.EvaluateExprOption{WantType: &cty.String, ModuleCtx: sdk.SelfModuleCtxType}
},
SDKVersion: sdkv15,
Want: cty.NullVal(cty.NilType),
ErrCheck: func(err error) bool {
return err == nil || !errors.Is(err, sdk.ErrUnknownValue)
},
},
{
Name: "no default as cty.Value (SDK v0.15)",
Args: func() (hcl.Expression, sdk.EvaluateExprOption) {
return hclExpr(`var.no_default`), sdk.EvaluateExprOption{WantType: &cty.DynamicPseudoType, ModuleCtx: sdk.SelfModuleCtxType}
},
SDKVersion: sdkv15,
Want: cty.DynamicVal,
ErrCheck: neverHappend,
},
{
Name: "no default value in object (SDK v0.15)",
Args: func() (hcl.Expression, sdk.EvaluateExprOption) {
ty := cty.Object(map[string]cty.Type{"value": cty.String})
return hclExpr(`{ value = var.no_default }`), sdk.EvaluateExprOption{WantType: &ty, ModuleCtx: sdk.SelfModuleCtxType}
},
SDKVersion: sdkv15,
Want: cty.NullVal(cty.NilType),
ErrCheck: func(err error) bool {
return err == nil || !errors.Is(err, sdk.ErrUnknownValue)
},
},
{
Name: "null",
Args: func() (hcl.Expression, sdk.EvaluateExprOption) {
Expand All @@ -605,38 +549,6 @@ variable "foo" {
Want: cty.NullVal(cty.String),
ErrCheck: neverHappend,
},
{
Name: "null (SDK v0.15)",
Args: func() (hcl.Expression, sdk.EvaluateExprOption) {
return hclExpr(`var.null`), sdk.EvaluateExprOption{WantType: &cty.String, ModuleCtx: sdk.SelfModuleCtxType}
},
SDKVersion: sdkv15,
Want: cty.NullVal(cty.NilType),
ErrCheck: func(err error) bool {
return err == nil || !errors.Is(err, sdk.ErrNullValue)
},
},
{
Name: "null as cty.Value (SDK v0.15)",
Args: func() (hcl.Expression, sdk.EvaluateExprOption) {
return hclExpr(`var.null`), sdk.EvaluateExprOption{WantType: &cty.DynamicPseudoType, ModuleCtx: sdk.SelfModuleCtxType}
},
SDKVersion: sdkv15,
Want: cty.NullVal(cty.String),
ErrCheck: neverHappend,
},
{
Name: "null value in object (SDK v0.15)",
Args: func() (hcl.Expression, sdk.EvaluateExprOption) {
ty := cty.Object(map[string]cty.Type{"value": cty.String})
return hclExpr(`{ value = var.null }`), sdk.EvaluateExprOption{WantType: &ty, ModuleCtx: sdk.SelfModuleCtxType}
},
Want: cty.NullVal(cty.NilType),
SDKVersion: sdkv15,
ErrCheck: func(err error) bool {
return err == nil || !errors.Is(err, sdk.ErrNullValue)
},
},
{
Name: "ephemeral value",
Args: func() (hcl.Expression, sdk.EvaluateExprOption) {
Expand Down
3 changes: 2 additions & 1 deletion terraform/tfhcl/expand_body.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,8 @@ func (b *expandBody) prepareAttributes(rawAttrs hcl.Attributes) (hcl.Attributes,
diags = append(diags, evalDiags...)
continue
}
// Marked values (e.g. sensitive values) are unbound for serialization.
// Marked values (e.g. ephemeral values) are unbound for serialization.
// TODO: Update the minimum supported SDK version to v0.22+ and then remove this condition.
if !val.ContainsMarked() {
attr.Expr = hclext.BindValue(val, expr)
}
Expand Down

0 comments on commit 7a23f6a

Please sign in to comment.