Skip to content

Commit

Permalink
Make IsSecret threadsafe
Browse files Browse the repository at this point in the history
  • Loading branch information
iwahbe committed Oct 28, 2022
1 parent 3707c92 commit 7175ccd
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
changes:
- type: fix
scope: sdk/go,yaml
description: Block IsSecret until secretness is known
27 changes: 26 additions & 1 deletion sdk/go/pulumi/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -519,8 +519,33 @@ func (o *OutputState) ApplyTWithContext(ctx context.Context, applier interface{}
}

// IsSecret returns a bool representing the secretness of the Output
//
// IsSecret may return an inaccurate results if the Output is unknowable (during a
// preview) or contains an error.
func IsSecret(o Output) bool {
return o.getState().secret
_, _, secret, _, _ := o.getState().await(context.Background())
// We intentionally ignore both the `known` and `error` values returned by `await`:
//
// If a value is not known, it is possible that we will return the wrong result. This
// is unavoidable. Consider the example:
//
// ```go
// bucket, _ := s3.Bucket("bucket", &s3.BucketArgs{})
// unknowable := bucket.Bucket.ApplyT(func(b string) OutputString {
// if strings.ContainsRune(b, '9') {
// return ToSecret(String(b))
// else {
// return String(b)
// }
// })
// ```
//
// Until we resolve values from the cloud, we can't know the correct value of
// `IsSecret(unknowable)`. We have the same problem for outputs with non-nil errors.
//
// This is tolerable because users will never be able to retrieve values (secret or
// otherwise) that are unknown or erred.
return secret
}

// Unsecret will unwrap a secret output as a new output with a resolved value and no secretness
Expand Down
19 changes: 19 additions & 0 deletions sdk/go/pulumi/types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"fmt"
"reflect"
"testing"
"time"

"github.com/stretchr/testify/assert"
)
Expand Down Expand Up @@ -618,7 +619,25 @@ func TestSecretApply(t *testing.T) {
break
}
}
}

// Test that secretness is properly bubbled up with all/apply that delays its execution.
func TestSecretApplyDelayed(t *testing.T) {
t.Parallel()

// We run multiple tests here to increase the likelihood of a hypothetical race
// condition triggering. As with all concurrency tests, its not a 100% guarantee.
for i := 0; i < 10 && !t.Failed(); i++ {
t.Run("", func(t *testing.T) {
t.Parallel()
s1 := String("foo").ToStringOutput().ApplyT(func(s string) StringOutput {
time.Sleep(time.Millisecond * 5)
return ToSecret(String("bar")).(StringOutput)
})
// assert that s1 is secret.
assert.True(t, IsSecret(s1))
})
}
}

func TestNil(t *testing.T) {
Expand Down

0 comments on commit 7175ccd

Please sign in to comment.