feat: implement issensitive function (#1381)

Signed-off-by: Jonas Bakken <jonasbakken@protonmail.com>
This commit is contained in:
Jonas Bakken 2024-03-13 11:22:58 +01:00 committed by GitHub
parent ff79db26c8
commit fc5ffe4edd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 145 additions and 1 deletions

View File

@ -12,6 +12,7 @@ ENHANCEMENTS:
* Added `base64gunzip` function that takes a base64 encoded gzip string and returns the decompressed data as a string. ([#800](https://github.com/opentofu/opentofu/issues/800))
* Added `cidrcontains` function that determines if an address belongs to a certain prefix. ([#366](https://github.com/opentofu/opentofu/issues/366))
* Added `urldecode` function that will decode a url-encoded string. ([#1234](https://github.com/opentofu/opentofu/issues/1234))
* Added `issensitive` function that returns whether or not a value is sensitive. ([#1370](https://github.com/opentofu/opentofu/issues/1370))
* Added `-concise` flag to omit the refreshing state logs when tofu plan is run. ([#1225](https://github.com/opentofu/opentofu/pull/1225))
* `nonsensitive` function no longer returns error when applied to values that are not sensitive ([#369](https://github.com/opentofu/opentofu/pull/369))
* Managing large local terraform.tfstate files is now much faster. ([#579](https://github.com/opentofu/opentofu/pull/579))

View File

@ -244,6 +244,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 any value and returns `true` if the value is marked as sensitive, and `false` otherwise.",
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{

View File

@ -60,6 +60,26 @@ var NonsensitiveFunc = function.New(&function.Spec{
},
})
// IsSensitiveFunc returns whether or not the value is sensitive.
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) (ret cty.Value, err error) {
return cty.BoolVal(args[0].HasMark(marks.Sensitive)), nil
},
})
func Sensitive(v cty.Value) (cty.Value, error) {
return SensitiveFunc.Call([]cty.Value{v})
}
@ -67,3 +87,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})
}

View File

@ -182,3 +182,57 @@ func TestNonsensitive(t *testing.T) {
})
}
}
func TestIsSensitive(t *testing.T) {
tests := []struct {
Input cty.Value
IsSensitive bool
}{
{
cty.NumberIntVal(1).Mark(marks.Sensitive),
true,
},
{
cty.NumberIntVal(1),
false,
},
{
cty.DynamicVal.Mark(marks.Sensitive),
true,
},
{
cty.DynamicVal,
false,
},
{
cty.UnknownVal(cty.String).Mark(marks.Sensitive),
true,
},
{
cty.UnknownVal(cty.String),
false,
},
{
cty.NullVal(cty.EmptyObject).Mark(marks.Sensitive),
true,
},
{
cty.NullVal(cty.EmptyObject),
false,
},
}
for _, test := range tests {
t.Run(fmt.Sprintf("issensitive(%#v)", test.Input), func(t *testing.T) {
got, err := IsSensitive(test.Input)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
if got.Equals(cty.BoolVal(test.IsSensitive)).False() {
t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, cty.BoolVal(test.IsSensitive))
}
})
}
}

View File

@ -112,6 +112,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,

View File

@ -529,6 +529,17 @@ func TestFunctions(t *testing.T) {
},
},
"issensitive": {
{
`issensitive(1)`,
cty.False,
},
{
`issensitive(sensitive(1))`,
cty.True,
},
},
"join": {
{
`join(" ", ["Hello", "World"])`,

View File

@ -715,6 +715,10 @@
"title": "<code>sensitive</code>",
"path": "language/functions/sensitive"
},
{
"title": "<code>issensitive</code>",
"path": "language/functions/issensitive",
},
{
"title": "<code>tobool</code>",
"path": "language/functions/tobool"
@ -954,6 +958,11 @@
"path": "language/functions/index_function",
"hidden": true
},
{
"title": "issensitive",
"path": "language/functions/issensitive",
"hidden": true
},
{ "title": "join", "path": "language/functions/join", "hidden": true },
{
"title": "jsondecode",
@ -1367,4 +1376,4 @@
"title": "v1.x Compatibility Promises",
"path": "language/v1-compatibility-promises"
}
]
]

View File

@ -0,0 +1,40 @@
---
sidebar_label: issensitive
description: >-
The issensitive function returns a boolean saying whether or not a value is
marked as sensitive.
---
# `issensitive` Function
`issensitive` takes any value and returns `true` if the value is marked as
sensitive, and `false` otherwise.
The `issensitive` function might be useful if you need to programmatically
determine whether or not a value is sensitive, for example if you have a value
containing both sensitive and non-sensitive values and you need to separate the
two parts:
```hcl
variable "environment_variables" {
description = "A list of environment variables that may contain both sensitive and non-sensitive values"
type = map(string)
sensitive = true
}
locals {
sensitive_variables = [for key, value in var.environment_variables: key if issensitive(value)]
nonsensitive_variables = [for key, value in var.environment_variables: key if !issensitive(value)]
}
```
## Examples
```
> issensitive(1)
false
> issensitive("hello")
false
> issensitive(sensitive("hello"))
true
```