diff --git a/internal/lang/funcs/descriptions.go b/internal/lang/funcs/descriptions.go index 6a96394f3906..a8cb3bfa63f5 100644 --- a/internal/lang/funcs/descriptions.go +++ b/internal/lang/funcs/descriptions.go @@ -233,6 +233,10 @@ var DescriptionList = map[string]descriptionEntry{ Description: "`index` finds the element index for a given value in a list.", ParamDescription: []string{"", ""}, }, + "issensitive": { + Description: "`issensitive` takes a value and returns a boolean indicating if the value is sensitive.", + ParamDescription: []string{""}, + }, "join": { Description: "`join` produces a string by concatenating together all elements of a given list of strings with the given delimiter.", ParamDescription: []string{ diff --git a/internal/lang/funcs/sensitive.go b/internal/lang/funcs/sensitive.go index 97703a4f1326..b30e2fa579c3 100644 --- a/internal/lang/funcs/sensitive.go +++ b/internal/lang/funcs/sensitive.go @@ -58,6 +58,24 @@ var NonsensitiveFunc = function.New(&function.Spec{ }, }) +var IssensitiveFunc = function.New(&function.Spec{ + Params: []function.Parameter{{ + Name: "value", + Type: cty.DynamicPseudoType, + AllowUnknown: true, + AllowNull: true, + AllowMarked: true, + AllowDynamicType: true, + }}, + Type: func(args []cty.Value) (cty.Type, error) { + return cty.Bool, nil + }, + Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) { + s := args[0].HasMark(marks.Sensitive) + return cty.BoolVal(s), nil + }, +}) + func Sensitive(v cty.Value) (cty.Value, error) { return SensitiveFunc.Call([]cty.Value{v}) } @@ -65,3 +83,7 @@ func Sensitive(v cty.Value) (cty.Value, error) { func Nonsensitive(v cty.Value) (cty.Value, error) { return NonsensitiveFunc.Call([]cty.Value{v}) } + +func Issensitive(v cty.Value) (cty.Value, error) { + return IssensitiveFunc.Call([]cty.Value{v}) +} diff --git a/internal/lang/funcs/sensitive_test.go b/internal/lang/funcs/sensitive_test.go index 96e647d05348..4a2b807f73fb 100644 --- a/internal/lang/funcs/sensitive_test.go +++ b/internal/lang/funcs/sensitive_test.go @@ -180,3 +180,75 @@ func TestNonsensitive(t *testing.T) { }) } } + +func TestIssensitive(t *testing.T) { + tests := []struct { + Input cty.Value + Sensitive bool + WantErr string + }{ + { + cty.NumberIntVal(1).Mark(marks.Sensitive), + true, + ``, + }, + { + cty.NumberIntVal(1), + false, + ``, + }, + { + cty.DynamicVal.Mark(marks.Sensitive), + true, + ``, + }, + { + cty.UnknownVal(cty.String).Mark(marks.Sensitive), + true, + ``, + }, + { + cty.NullVal(cty.EmptyObject).Mark(marks.Sensitive), + true, + ``, + }, + { + cty.NullVal(cty.String), + false, + ``, + }, + { + cty.DynamicVal, + false, + ``, + }, + { + cty.UnknownVal(cty.String), + false, + ``, + }, + } + + for _, test := range tests { + t.Run(fmt.Sprintf("issensitive(%#v)", test.Input), func(t *testing.T) { + got, err := Issensitive(test.Input) + + if test.WantErr != "" { + if err == nil { + t.Fatal("succeeded; want error") + } + if got, want := err.Error(), test.WantErr; got != want { + t.Fatalf("wrong error\ngot: %s\nwant: %s", got, want) + } + return + } else if err != nil { + t.Fatalf("unexpected error: %s", err) + } + + if (got.True() && !test.Sensitive) || (got.False() && test.Sensitive) { + t.Errorf("wrong result \ngot: %#v\nwant: %#v", got, test.Sensitive) + } + }) + } + +} diff --git a/internal/lang/functions.go b/internal/lang/functions.go index 337f3ff54fb9..10c72981a66b 100644 --- a/internal/lang/functions.go +++ b/internal/lang/functions.go @@ -103,6 +103,7 @@ func (s *Scope) Functions() map[string]function.Function { "rsadecrypt": funcs.RsaDecryptFunc, "sensitive": funcs.SensitiveFunc, "nonsensitive": funcs.NonsensitiveFunc, + "issensitive": funcs.IssensitiveFunc, "setintersection": stdlib.SetIntersectionFunc, "setproduct": stdlib.SetProductFunc, "setsubtract": stdlib.SetSubtractFunc, @@ -301,6 +302,7 @@ func baseFunctions(baseDir string) map[string]function.Function { "rsadecrypt": funcs.RsaDecryptFunc, "sensitive": funcs.SensitiveFunc, "nonsensitive": funcs.NonsensitiveFunc, + "issensitive": funcs.IssensitiveFunc, "setintersection": stdlib.SetIntersectionFunc, "setproduct": stdlib.SetProductFunc, "setsubtract": stdlib.SetSubtractFunc, diff --git a/internal/lang/functions_test.go b/internal/lang/functions_test.go index 7add47b247ad..bdf1b16de73d 100644 --- a/internal/lang/functions_test.go +++ b/internal/lang/functions_test.go @@ -515,6 +515,13 @@ func TestFunctions(t *testing.T) { }, }, + "issensitive": { + { + `issensitive(1)`, + cty.False, + }, + }, + "join": { { `join(" ", ["Hello", "World"])`, diff --git a/website/data/language-nav-data.json b/website/data/language-nav-data.json index 5760c710bd86..be2c59026813 100644 --- a/website/data/language-nav-data.json +++ b/website/data/language-nav-data.json @@ -690,6 +690,10 @@ "title": "Type Conversion Functions", "routes": [ { "title": "can", "href": "/language/functions/can" }, + { + "title": "issensitive", + "href": "/language/functions/issensitive" + }, { "title": "nonsensitive", "href": "/language/functions/nonsensitive" diff --git a/website/docs/language/functions/issensitive.mdx b/website/docs/language/functions/issensitive.mdx new file mode 100644 index 000000000000..6647af1d442d --- /dev/null +++ b/website/docs/language/functions/issensitive.mdx @@ -0,0 +1,27 @@ +--- +page_title: issensitive - Functions - Configuration Language +description: The issensitive function true if the value passed is marked as sensitive +--- + +# `issensitive` Function + +-> **Note:** This function is only available in Terraform v1.8 and later. + +`issensitive` takes any value and returns true if Terraform +treats it as sensitive, with the same meaning and behavior as for +[sensitive input variables](/terraform/language/values/variables#suppressing-values-in-cli-output). + +If a value not marked as sensitive is passed the function returns false. + +See [`sensitive`](/terraform/language/functions/sensitive), [`nonsensitive`](/terraform/language/functions/nonsensitive), and [sensitive input variables](/terraform/language/values/variables#suppressing-values-in-cli-output) for more information on sensitive values. + +## Examples + +``` +> issensitive(sensitive("secret")) +true +> issensitive("hello") +false +> sensitive(var.my-var-with-sensitive-set-to-true) +true +```