Propagate secretness correctly in Python apply (#4273)

* Propagate secretness correctly in Python `apply`

* Improve `apply` test coverage

* Update CHANGELOG.md
This commit is contained in:
Justin Van Patten 2020-04-02 13:01:29 -07:00 committed by GitHub
parent 9c82975478
commit dd104a00a7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 1291 additions and 12 deletions

View file

@ -5,6 +5,9 @@ CHANGELOG
- Fix handling of `nil` values in Outputs in Go.
[#4268](https://github.com/pulumi/pulumi/pull/4268)
- Fix secretness propagation in Python `apply`.
[#4273](https://github.com/pulumi/pulumi/pull/4273)
## 1.14.0 (2020-04-01)
- Fix error related to side-by-side versions of `@pulumi/pulumi`.
[#4235](https://github.com/pulumi/pulumi/pull/4235)

View file

@ -26,6 +26,39 @@ namespace Pulumi.Tests.Core
Assert.Equal(1, data.Value);
});
[Fact]
public Task ApplyCanRunOnKnownAwaitableValue()
=> RunInPreview(async () =>
{
var o1 = CreateOutput(0, isKnown: true);
var o2 = o1.Apply(a => Task.FromResult("inner"));
var data = await o2.DataTask.ConfigureAwait(false);
Assert.True(data.IsKnown);
Assert.Equal("inner", data.Value);
});
[Fact]
public Task ApplyCanRunOnKnownKnownOutputValue()
=> RunInPreview(async () =>
{
var o1 = CreateOutput(0, isKnown: true);
var o2 = o1.Apply(a => CreateOutput("inner", isKnown: true));
var data = await o2.DataTask.ConfigureAwait(false);
Assert.True(data.IsKnown);
Assert.Equal("inner", data.Value);
});
[Fact]
public Task ApplyCanRunOnKnownUnknownOutputValue()
=> RunInPreview(async () =>
{
var o1 = CreateOutput(0, isKnown: true);
var o2 = o1.Apply(a => CreateOutput("inner", isKnown: false));
var data = await o2.DataTask.ConfigureAwait(false);
Assert.False(data.IsKnown);
Assert.Equal("inner", data.Value);
});
[Fact]
public Task ApplyProducesUnknownDefaultOnUnknown()
=> RunInPreview(async () =>
@ -37,6 +70,39 @@ namespace Pulumi.Tests.Core
Assert.Equal(0, data.Value);
});
[Fact]
public Task ApplyProducesUnknownDefaultOnUnknownAwaitable()
=> RunInPreview(async () =>
{
var o1 = CreateOutput(0, isKnown: false);
var o2 = o1.Apply(a => Task.FromResult("inner"));
var data = await o2.DataTask.ConfigureAwait(false);
Assert.False(data.IsKnown);
Assert.Null(data.Value);
});
[Fact]
public Task ApplyProducesUnknownDefaultOnUnknownKnownOutput()
=> RunInPreview(async () =>
{
var o1 = CreateOutput(0, isKnown: false);
var o2 = o1.Apply(a => CreateOutput("", isKnown: true));
var data = await o2.DataTask.ConfigureAwait(false);
Assert.False(data.IsKnown);
Assert.Null(data.Value);
});
[Fact]
public Task ApplyProducesUnknownDefaultOnUnknownUnknownOutput()
=> RunInPreview(async () =>
{
var o1 = CreateOutput(0, isKnown: false);
var o2 = o1.Apply(a => CreateOutput("", isKnown: false));
var data = await o2.DataTask.ConfigureAwait(false);
Assert.False(data.IsKnown);
Assert.Null(data.Value);
});
[Fact]
public Task ApplyPreservesSecretOnKnown()
=> RunInPreview(async () =>
@ -49,6 +115,42 @@ namespace Pulumi.Tests.Core
Assert.Equal(1, data.Value);
});
[Fact]
public Task ApplyPreservesSecretOnKnownAwaitable()
=> RunInPreview(async () =>
{
var o1 = CreateOutput(0, isKnown: true, isSecret: true);
var o2 = o1.Apply(a => Task.FromResult("inner"));
var data = await o2.DataTask.ConfigureAwait(false);
Assert.True(data.IsKnown);
Assert.True(data.IsSecret);
Assert.Equal("inner", data.Value);
});
[Fact]
public Task ApplyPreservesSecretOnKnownKnownOutput()
=> RunInPreview(async () =>
{
var o1 = CreateOutput(0, isKnown: true, isSecret: true);
var o2 = o1.Apply(a => CreateOutput("inner", isKnown: true));
var data = await o2.DataTask.ConfigureAwait(false);
Assert.True(data.IsKnown);
Assert.True(data.IsSecret);
Assert.Equal("inner", data.Value);
});
[Fact]
public Task ApplyPreservesSecretOnKnownUnknownOutput()
=> RunInPreview(async () =>
{
var o1 = CreateOutput(0, isKnown: true, isSecret: true);
var o2 = o1.Apply(a => CreateOutput("inner", isKnown: false));
var data = await o2.DataTask.ConfigureAwait(false);
Assert.False(data.IsKnown);
Assert.True(data.IsSecret);
Assert.Equal("inner", data.Value);
});
[Fact]
public Task ApplyPreservesSecretOnUnknown()
=> RunInPreview(async () =>
@ -60,6 +162,90 @@ namespace Pulumi.Tests.Core
Assert.True(data.IsSecret);
Assert.Equal(0, data.Value);
});
[Fact]
public Task ApplyPreservesSecretOnUnknownAwaitable()
=> RunInPreview(async () =>
{
var o1 = CreateOutput(0, isKnown: false, isSecret: true);
var o2 = o1.Apply(a => Task.FromResult("inner"));
var data = await o2.DataTask.ConfigureAwait(false);
Assert.False(data.IsKnown);
Assert.True(data.IsSecret);
Assert.Null(data.Value);
});
[Fact]
public Task ApplyPreservesSecretOnUnknownKnownOutput()
=> RunInPreview(async () =>
{
var o1 = CreateOutput(0, isKnown: false, isSecret: true);
var o2 = o1.Apply(a => CreateOutput("inner", isKnown: true));
var data = await o2.DataTask.ConfigureAwait(false);
Assert.False(data.IsKnown);
Assert.True(data.IsSecret);
Assert.Null(data.Value);
});
[Fact]
public Task ApplyPreservesSecretOnUnknownUnknownOutput()
=> RunInPreview(async () =>
{
var o1 = CreateOutput(0, isKnown: false, isSecret: true);
var o2 = o1.Apply(a => CreateOutput("inner", isKnown: false));
var data = await o2.DataTask.ConfigureAwait(false);
Assert.False(data.IsKnown);
Assert.True(data.IsSecret);
Assert.Null(data.Value);
});
[Fact]
public Task ApplyPropagatesSecretOnKnownKnownOutput()
=> RunInPreview(async () =>
{
var o1 = CreateOutput(0, isKnown: true);
var o2 = o1.Apply(a => CreateOutput("inner", isKnown: true, isSecret: true));
var data = await o2.DataTask.ConfigureAwait(false);
Assert.True(data.IsKnown);
Assert.True(data.IsSecret);
Assert.Equal("inner", data.Value);
});
[Fact]
public Task ApplyPropagatesSecretOnKnownUnknownOutput()
=> RunInPreview(async () =>
{
var o1 = CreateOutput(0, isKnown: true);
var o2 = o1.Apply(a => CreateOutput("inner", isKnown: false, isSecret: true));
var data = await o2.DataTask.ConfigureAwait(false);
Assert.False(data.IsKnown);
Assert.True(data.IsSecret);
Assert.Equal("inner", data.Value);
});
[Fact]
public Task ApplyDoesNotPropagateSecretOnUnknownKnownOutput()
=> RunInPreview(async () =>
{
var o1 = CreateOutput(0, isKnown: false);
var o2 = o1.Apply(a => CreateOutput("inner", isKnown: true, isSecret: true));
var data = await o2.DataTask.ConfigureAwait(false);
Assert.False(data.IsKnown);
Assert.False(data.IsSecret);
Assert.Null(data.Value);
});
[Fact]
public Task ApplyDoesNotPropagateSecretOnUnknownUnknownOutput()
=> RunInPreview(async () =>
{
var o1 = CreateOutput(0, isKnown: false);
var o2 = o1.Apply(a => CreateOutput("inner", isKnown: false, isSecret: true));
var data = await o2.DataTask.ConfigureAwait(false);
Assert.False(data.IsKnown);
Assert.False(data.IsSecret);
Assert.Null(data.Value);
});
}
public class NormalTests
@ -75,6 +261,39 @@ namespace Pulumi.Tests.Core
Assert.Equal(1, data.Value);
});
[Fact]
public Task ApplyCanRunOnKnownAwaitableValue()
=> RunInNormal(async () =>
{
var o1 = CreateOutput(0, isKnown: true);
var o2 = o1.Apply(a => Task.FromResult("inner"));
var data = await o2.DataTask.ConfigureAwait(false);
Assert.True(data.IsKnown);
Assert.Equal("inner", data.Value);
});
[Fact]
public Task ApplyCanRunOnKnownKnownOutputValue()
=> RunInNormal(async () =>
{
var o1 = CreateOutput(0, isKnown: true);
var o2 = o1.Apply(a => CreateOutput("inner", isKnown: true));
var data = await o2.DataTask.ConfigureAwait(false);
Assert.True(data.IsKnown);
Assert.Equal("inner", data.Value);
});
[Fact]
public Task ApplyCanRunOnKnownUnknownOutputValue()
=> RunInNormal(async () =>
{
var o1 = CreateOutput(0, isKnown: true);
var o2 = o1.Apply(a => CreateOutput("inner", isKnown: false));
var data = await o2.DataTask.ConfigureAwait(false);
Assert.False(data.IsKnown);
Assert.Equal("inner", data.Value);
});
[Fact]
public Task ApplyProducesKnownOnUnknown()
=> RunInNormal(async () =>
@ -86,6 +305,39 @@ namespace Pulumi.Tests.Core
Assert.Equal(1, data.Value);
});
[Fact]
public Task ApplyProducesKnownOnUnknownAwaitable()
=> RunInNormal(async () =>
{
var o1 = CreateOutput(0, isKnown: false);
var o2 = o1.Apply(a => Task.FromResult("inner"));
var data = await o2.DataTask.ConfigureAwait(false);
Assert.False(data.IsKnown);
Assert.Equal("inner", data.Value);
});
[Fact]
public Task ApplyProducesKnownOnUnknownKnownOutput()
=> RunInNormal(async () =>
{
var o1 = CreateOutput(0, isKnown: false);
var o2 = o1.Apply(a => CreateOutput("inner", isKnown: true));
var data = await o2.DataTask.ConfigureAwait(false);
Assert.False(data.IsKnown);
Assert.Equal("inner", data.Value);
});
[Fact]
public Task ApplyProducesUnknownOnUnknownUnknownOutput()
=> RunInNormal(async () =>
{
var o1 = CreateOutput(0, isKnown: false);
var o2 = o1.Apply(a => CreateOutput("inner", isKnown: false));
var data = await o2.DataTask.ConfigureAwait(false);
Assert.False(data.IsKnown);
Assert.Equal("inner", data.Value);
});
[Fact]
public Task ApplyPreservesSecretOnKnown()
=> RunInNormal(async () =>
@ -98,6 +350,42 @@ namespace Pulumi.Tests.Core
Assert.Equal(1, data.Value);
});
[Fact]
public Task ApplyPreservesSecretOnKnownAwaitable()
=> RunInNormal(async () =>
{
var o1 = CreateOutput(0, isKnown: true, isSecret: true);
var o2 = o1.Apply(a => Task.FromResult("inner"));
var data = await o2.DataTask.ConfigureAwait(false);
Assert.True(data.IsKnown);
Assert.True(data.IsSecret);
Assert.Equal("inner", data.Value);
});
[Fact]
public Task ApplyPreservesSecretOnKnownKnownOutput()
=> RunInNormal(async () =>
{
var o1 = CreateOutput(0, isKnown: true, isSecret: true);
var o2 = o1.Apply(a => CreateOutput("inner", isKnown: true));
var data = await o2.DataTask.ConfigureAwait(false);
Assert.True(data.IsKnown);
Assert.True(data.IsSecret);
Assert.Equal("inner", data.Value);
});
[Fact]
public Task ApplyPreservesSecretOnKnownUnknownOutput()
=> RunInNormal(async () =>
{
var o1 = CreateOutput(0, isKnown: true, isSecret: true);
var o2 = o1.Apply(a => CreateOutput("inner", isKnown: false));
var data = await o2.DataTask.ConfigureAwait(false);
Assert.False(data.IsKnown);
Assert.True(data.IsSecret);
Assert.Equal("inner", data.Value);
});
[Fact]
public Task ApplyPreservesSecretOnUnknown()
=> RunInNormal(async () =>
@ -109,6 +397,90 @@ namespace Pulumi.Tests.Core
Assert.True(data.IsSecret);
Assert.Equal(1, data.Value);
});
[Fact]
public Task ApplyPreservesSecretOnUnknownAwaitable()
=> RunInNormal(async () =>
{
var o1 = CreateOutput(0, isKnown: false, isSecret: true);
var o2 = o1.Apply(a => Task.FromResult("inner"));
var data = await o2.DataTask.ConfigureAwait(false);
Assert.False(data.IsKnown);
Assert.True(data.IsSecret);
Assert.Equal("inner", data.Value);
});
[Fact]
public Task ApplyPreservesSecretOnUnknownKnownOutput()
=> RunInNormal(async () =>
{
var o1 = CreateOutput(0, isKnown: false, isSecret: true);
var o2 = o1.Apply(a => CreateOutput("inner", isKnown: true));
var data = await o2.DataTask.ConfigureAwait(false);
Assert.False(data.IsKnown);
Assert.True(data.IsSecret);
Assert.Equal("inner", data.Value);
});
[Fact]
public Task ApplyPreservesSecretOnUnknownUnknownOutput()
=> RunInNormal(async () =>
{
var o1 = CreateOutput(0, isKnown: false, isSecret: true);
var o2 = o1.Apply(a => CreateOutput("inner", isKnown: false));
var data = await o2.DataTask.ConfigureAwait(false);
Assert.False(data.IsKnown);
Assert.True(data.IsSecret);
Assert.Equal("inner", data.Value);
});
[Fact]
public Task ApplyPropagatesSecretOnKnownKnownOutput()
=> RunInNormal(async () =>
{
var o1 = CreateOutput(0, isKnown: true);
var o2 = o1.Apply(a => CreateOutput("inner", isKnown: true, isSecret: true));
var data = await o2.DataTask.ConfigureAwait(false);
Assert.True(data.IsKnown);
Assert.True(data.IsSecret);
Assert.Equal("inner", data.Value);
});
[Fact]
public Task ApplyPropagatesSecretOnKnownUnknownOutput()
=> RunInNormal(async () =>
{
var o1 = CreateOutput(0, isKnown: true);
var o2 = o1.Apply(a => CreateOutput("inner", isKnown: false, isSecret: true));
var data = await o2.DataTask.ConfigureAwait(false);
Assert.False(data.IsKnown);
Assert.True(data.IsSecret);
Assert.Equal("inner", data.Value);
});
[Fact]
public Task ApplyPropagatesSecretOnUnknownKnownOutput()
=> RunInNormal(async () =>
{
var o1 = CreateOutput(0, isKnown: false);
var o2 = o1.Apply(a => CreateOutput("inner", isKnown: true, isSecret: true));
var data = await o2.DataTask.ConfigureAwait(false);
Assert.False(data.IsKnown);
Assert.True(data.IsSecret);
Assert.Equal("inner", data.Value);
});
[Fact]
public Task ApplyPropagatesSecretOnUnknownUnknownOutput()
=> RunInNormal(async () =>
{
var o1 = CreateOutput(0, isKnown: false);
var o2 = o1.Apply(a => CreateOutput("inner", isKnown: false, isSecret: true));
var data = await o2.DataTask.ConfigureAwait(false);
Assert.False(data.IsKnown);
Assert.True(data.IsSecret);
Assert.Equal("inner", data.Value);
});
}
}
}

View file

@ -19,6 +19,7 @@ import { Output, all, concat, interpolate, output, unknown } from "../output";
import { Resource } from "../resource";
import * as runtime from "../runtime";
import { asyncTest } from "./util";
import { promiseResult } from "../utils";
interface Widget {
type: string; // metric | text
@ -137,6 +138,437 @@ describe("output", () => {
assert.equal(value, "inner");
}));
describe("apply", () => {
function createOutput<T>(val: T, isKnown: boolean, isSecret: boolean = false): Output<T> {
return new Output(new Set(), Promise.resolve(val), Promise.resolve(isKnown), Promise.resolve(isSecret),
Promise.resolve(new Set()));
}
it("can run on known value during preview", asyncTest(async () => {
runtime._setIsDryRun(true);
const out = createOutput(0, true);
const r = out.apply(v => v + 1);
assert.equal(await r.isKnown, true);
assert.equal(await r.promise(), 1);
}));
it("can run on known awaitable value during preview", asyncTest(async () => {
runtime._setIsDryRun(true);
const out = createOutput(0, true);
const r = out.apply(v => Promise.resolve("inner"));
assert.equal(await r.isKnown, true);
assert.equal(await r.promise(), "inner");
}));
it("can run on known known output value during preview", asyncTest(async () => {
runtime._setIsDryRun(true);
const out = createOutput(0, true);
const r = out.apply(v => createOutput("inner", true));
assert.equal(await r.isKnown, true);
assert.equal(await r.promise(), "inner");
}));
it("can run on known unknown output value during preview", asyncTest(async () => {
runtime._setIsDryRun(true);
const out = createOutput(0, true);
const r = out.apply(v => createOutput("inner", false));
assert.equal(await r.isKnown, false);
assert.equal(await r.promise(), "inner");
}));
it("produces unknown default on unknown during preview", asyncTest(async () => {
runtime._setIsDryRun(true);
const out = createOutput(0, false);
const r = out.apply(v => v + 1);
assert.equal(await r.isKnown, false);
assert.equal(await r.promise(), undefined);
}));
it("produces unknown default on unknown awaitable during preview", asyncTest(async () => {
runtime._setIsDryRun(true);
const out = createOutput(0, false);
const r = out.apply(v => Promise.resolve("inner"));
assert.equal(await r.isKnown, false);
assert.equal(await r.promise(), undefined);
}));
it("produces unknown default on unknown known output during preview", asyncTest(async () => {
runtime._setIsDryRun(true);
const out = createOutput(0, false);
const r = out.apply(v => createOutput("inner", true));
assert.equal(await r.isKnown, false);
assert.equal(await r.promise(), undefined);
}));
it("produces unknown default on unknown unknown output during preview", asyncTest(async () => {
runtime._setIsDryRun(true);
const out = createOutput(0, false);
const r = out.apply(v => createOutput("inner", false));
assert.equal(await r.isKnown, false);
assert.equal(await r.promise(), undefined);
}));
it("preserves secret on known during preview", asyncTest(async () => {
runtime._setIsDryRun(true);
const out = createOutput(0, true, true);
const r = out.apply(v => v + 1);
assert.equal(await r.isKnown, true);
assert.equal(await r.isSecret, true);
assert.equal(await r.promise(), 1);
}));
it("preserves secret on known awaitable during preview", asyncTest(async () => {
runtime._setIsDryRun(true);
const out = createOutput(0, true, true);
const r = out.apply(v => Promise.resolve("inner"));
assert.equal(await r.isKnown, true);
assert.equal(await r.isSecret, true);
assert.equal(await r.promise(), "inner");
}));
it("preserves secret on known known output during preview", asyncTest(async () => {
runtime._setIsDryRun(true);
const out = createOutput(0, true, true);
const r = out.apply(v => createOutput("inner", true));
assert.equal(await r.isKnown, true);
assert.equal(await r.isSecret, true);
assert.equal(await r.promise(), "inner");
}));
it("preserves secret on known unknown output during preview", asyncTest(async () => {
runtime._setIsDryRun(true);
const out = createOutput(0, true, true);
const r = out.apply(v => createOutput("inner", false));
assert.equal(await r.isKnown, false);
assert.equal(await r.isSecret, true);
assert.equal(await r.promise(), "inner");
}));
it("preserves secret on unknown during preview", asyncTest(async () => {
runtime._setIsDryRun(true);
const out = createOutput(0, false, true);
const r = out.apply(v => v + 1);
assert.equal(await r.isKnown, false);
assert.equal(await r.isSecret, true);
assert.equal(await r.promise(), undefined);
}));
it("preserves secret on unknown awaitable during preview", asyncTest(async () => {
runtime._setIsDryRun(true);
const out = createOutput(0, false, true);
const r = out.apply(v => Promise.resolve("inner"));
assert.equal(await r.isKnown, false);
assert.equal(await r.isSecret, true);
assert.equal(await r.promise(), undefined);
}));
it("preserves secret on unknown known output during preview", asyncTest(async () => {
runtime._setIsDryRun(true);
const out = createOutput(0, false, true);
const r = out.apply(v => createOutput("inner", true));
assert.equal(await r.isKnown, false);
assert.equal(await r.isSecret, true);
assert.equal(await r.promise(), undefined);
}));
it("preserves secret on unknown unknown output during preview", asyncTest(async () => {
runtime._setIsDryRun(true);
const out = createOutput(0, false, true);
const r = out.apply(v => createOutput("inner", false));
assert.equal(await r.isKnown, false);
assert.equal(await r.isSecret, true);
assert.equal(await r.promise(), undefined);
}));
it("propagates secret on known known output during preview", asyncTest(async () => {
runtime._setIsDryRun(true);
const out = createOutput(0, true);
const r = out.apply(v => createOutput("inner", true, true));
assert.equal(await r.isKnown, true);
assert.equal(await r.isSecret, true);
assert.equal(await r.promise(), "inner");
}));
it("propagates secret on known unknown output during preview", asyncTest(async () => {
runtime._setIsDryRun(true);
const out = createOutput(0, true);
const r = out.apply(v => createOutput("inner", false, true));
assert.equal(await r.isKnown, false);
assert.equal(await r.isSecret, true);
assert.equal(await r.promise(), "inner");
}));
it("does not propagate secret on unknown known output during preview", asyncTest(async () => {
runtime._setIsDryRun(true);
const out = createOutput(0, false);
const r = out.apply(v => createOutput("inner", true, true));
assert.equal(await r.isKnown, false);
assert.equal(await r.isSecret, false);
assert.equal(await r.promise(), undefined);
}));
it("does not propagate secret on unknown unknown output during preview", asyncTest(async () => {
runtime._setIsDryRun(true);
const out = createOutput(0, false);
const r = out.apply(v => createOutput("inner", false, true));
assert.equal(await r.isKnown, false);
assert.equal(await r.isSecret, false);
assert.equal(await r.promise(), undefined);
}));
it("can run on known value", asyncTest(async () => {
runtime._setIsDryRun(false);
const out = createOutput(0, true);
const r = out.apply(v => v + 1);
assert.equal(await r.isKnown, true);
assert.equal(await r.promise(), 1);
}));
it("can run on known awaitable value", asyncTest(async () => {
runtime._setIsDryRun(false);
const out = createOutput(0, true);
const r = out.apply(v => Promise.resolve("inner"));
assert.equal(await r.isKnown, true);
assert.equal(await r.promise(), "inner");
}));
it("can run on known known output value", asyncTest(async () => {
runtime._setIsDryRun(false);
const out = createOutput(0, true);
const r = out.apply(v => createOutput("inner", true));
assert.equal(await r.isKnown, true);
assert.equal(await r.promise(), "inner");
}));
it("can run on unknown known output value", asyncTest(async () => {
runtime._setIsDryRun(false);
const out = createOutput(0, true);
const r = out.apply(v => createOutput("inner", false));
assert.equal(await r.isKnown, false);
assert.equal(await r.promise(), "inner");
}));
it("produces known on unknown", asyncTest(async () => {
runtime._setIsDryRun(false);
const out = createOutput(0, false);
const r = out.apply(v => v + 1);
assert.equal(await r.isKnown, true);
assert.equal(await r.promise(), 1);
}));
it("produces known on unknown awaitable", asyncTest(async () => {
runtime._setIsDryRun(false);
const out = createOutput(0, false);
const r = out.apply(v => Promise.resolve("inner"));
assert.equal(await r.isKnown, true);
assert.equal(await r.promise(), "inner");
}));
it("produces known on unknown known output", asyncTest(async () => {
runtime._setIsDryRun(false);
const out = createOutput(0, false);
const r = out.apply(v => createOutput("inner", true));
assert.equal(await r.isKnown, true);
assert.equal(await r.promise(), "inner");
}));
it("produces unknown on unknown unknown output", asyncTest(async () => {
runtime._setIsDryRun(false);
const out = createOutput(0, false);
const r = out.apply(v => createOutput("inner", false));
assert.equal(await r.isKnown, false);
assert.equal(await r.promise(), "inner");
}));
it("preserves secret on known", asyncTest(async () => {
runtime._setIsDryRun(false);
const out = createOutput(0, true, true);
const r = out.apply(v => v + 1);
assert.equal(await r.isKnown, true);
assert.equal(await r.isSecret, true);
assert.equal(await r.promise(), 1);
}));
it("preserves secret on known awaitable", asyncTest(async () => {
runtime._setIsDryRun(false);
const out = createOutput(0, true, true);
const r = out.apply(v => Promise.resolve("inner"));
assert.equal(await r.isKnown, true);
assert.equal(await r.isSecret, true);
assert.equal(await r.promise(), "inner");
}));
it("preserves secret on known known output", asyncTest(async () => {
runtime._setIsDryRun(false);
const out = createOutput(0, true, true);
const r = out.apply(v => createOutput("inner", true));
assert.equal(await r.isKnown, true);
assert.equal(await r.isSecret, true);
assert.equal(await r.promise(), "inner");
}));
it("preserves secret on known known output", asyncTest(async () => {
runtime._setIsDryRun(false);
const out = createOutput(0, true, true);
const r = out.apply(v => createOutput("inner", false));
assert.equal(await r.isKnown, false);
assert.equal(await r.isSecret, true);
assert.equal(await r.promise(), "inner");
}));
it("preserves secret on unknown", asyncTest(async () => {
runtime._setIsDryRun(false);
const out = createOutput(0, false, true);
const r = out.apply(v => v + 1);
assert.equal(await r.isKnown, true);
assert.equal(await r.isSecret, true);
assert.equal(await r.promise(), 1);
}));
it("preserves secret on unknown awaitable", asyncTest(async () => {
runtime._setIsDryRun(false);
const out = createOutput(0, false, true);
const r = out.apply(v => Promise.resolve("inner"));
assert.equal(await r.isKnown, true);
assert.equal(await r.isSecret, true);
assert.equal(await r.promise(), "inner");
}));
it("preserves secret on unknown known output", asyncTest(async () => {
runtime._setIsDryRun(false);
const out = createOutput(0, false, true);
const r = out.apply(v => createOutput("inner", true));
assert.equal(await r.isKnown, true);
assert.equal(await r.isSecret, true);
assert.equal(await r.promise(), "inner");
}));
it("preserves secret on unknown known output", asyncTest(async () => {
runtime._setIsDryRun(false);
const out = createOutput(0, false, true);
const r = out.apply(v => createOutput("inner", false));
assert.equal(await r.isKnown, false);
assert.equal(await r.isSecret, true);
assert.equal(await r.promise(), "inner");
}));
it("propagates secret on known known output", asyncTest(async () => {
runtime._setIsDryRun(false);
const out = createOutput(0, true);
const r = out.apply(v => createOutput("inner", true, true));
assert.equal(await r.isKnown, true);
assert.equal(await r.isSecret, true);
assert.equal(await r.promise(), "inner");
}));
it("propagates secret on known unknown output", asyncTest(async () => {
runtime._setIsDryRun(false);
const out = createOutput(0, true);
const r = out.apply(v => createOutput("inner", false, true));
assert.equal(await r.isKnown, false);
assert.equal(await r.isSecret, true);
assert.equal(await r.promise(), "inner");
}));
it("propagates secret on unknown known output", asyncTest(async () => {
runtime._setIsDryRun(false);
const out = createOutput(0, false);
const r = out.apply(v => createOutput("inner", true, true));
assert.equal(await r.isKnown, true);
assert.equal(await r.isSecret, true);
assert.equal(await r.promise(), "inner");
}));
it("propagates secret on unknown uknown output", asyncTest(async () => {
runtime._setIsDryRun(false);
const out = createOutput(0, false);
const r = out.apply(v => createOutput("inner", false, true));
assert.equal(await r.isKnown, false);
assert.equal(await r.isSecret, true);
assert.equal(await r.promise(), "inner");
}));
});
describe("isKnown", () => {
function or<T>(output1: Output<T>, output2: Output<T>): Output<T> {
const val1 = output1.promise();

View file

@ -64,7 +64,7 @@ class Output(Generic[T]):
_is_secret: Awaitable[bool]
"""
Where or not this 'Output' should be treated as containing secret data. Secret outputs are tagged when
Whether or not this 'Output' should be treated as containing secret data. Secret outputs are tagged when
flowing across the RPC interface to the resource monitor, such that when they are persisted to disk in
our state file, they are encrypted instead of being in plaintext.
"""
@ -155,16 +155,16 @@ class Output(Generic[T]):
value = await self._future
if runtime.is_dry_run():
# During previews only perform the apply if the engine was able togive us an actual value for this
# During previews only perform the apply if the engine was able to give us an actual value for this
# Output or if the caller is able to tolerate unknown values.
apply_during_preview = is_known or run_with_unknowns
if not apply_during_preview:
# We didn't actually run the function, our new Output is definitely
# **not** known and **not** secret
# **not** known.
result_resources.set_result(resources)
result_is_known.set_result(False)
result_is_secret.set_result(False)
result_is_secret.set_result(is_secret)
return cast(U, None)
# If we are running with unknown values and the value is explicitly unknown but does not actually
@ -187,16 +187,16 @@ class Output(Generic[T]):
# 2. transformed is an Awaitable[U]
if isawaitable(transformed):
# Since transformed is not an Output, it is both known and not a secret.
# Since transformed is not an Output, it is known.
result_resources.set_result(resources)
result_is_known.set_result(True)
result_is_secret.set_result(False)
result_is_secret.set_result(is_secret)
return await cast(Awaitable[U], transformed)
# 3. transformed is U. It is trivially known.
result_resources.set_result(resources)
result_is_known.set_result(True)
result_is_secret.set_result(False)
result_is_secret.set_result(is_secret)
return cast(U, transformed)
finally:
# Always resolve the future if it hasn't been done already.

View file

@ -13,6 +13,7 @@
# limitations under the License.
import asyncio
import unittest
from typing import Any, Optional
from google.protobuf import struct_pb2
from pulumi.resource import CustomResource
@ -291,13 +292,484 @@ class NextSerializationTests(unittest.TestCase):
out = Output(set(), fut, known_fut)
self.assertFalse(await out.is_known())
def create_output(self, val: Any, is_known: bool, is_secret: Optional[bool] = None):
fut = asyncio.Future()
fut.set_result(val)
known_fut = asyncio.Future()
known_fut.set_result(is_known)
if is_secret is not None:
is_secret_fut = asyncio.Future()
is_secret_fut.set_result(True)
return Output(set(), fut, known_fut, is_secret_fut)
return Output(set(), fut, known_fut)
@async_test
async def test_apply_can_run_on_known_value_during_preview(self):
settings.SETTINGS.dry_run = True
out = self.create_output(0, is_known=True)
r = out.apply(lambda v: v + 1)
self.assertTrue(await r.is_known())
self.assertEqual(await r.future(), 1)
@async_test
async def test_apply_can_run_on_known_awaitable_value_during_preview(self):
settings.SETTINGS.dry_run = True
out = self.create_output(0, is_known=True)
def apply(v):
fut = asyncio.Future()
fut.set_result("inner")
return fut
r = out.apply(apply)
self.assertTrue(await r.is_known())
self.assertEqual(await r.future(), "inner")
@async_test
async def test_apply_can_run_on_known_known_output_value_during_preview(self):
settings.SETTINGS.dry_run = True
out = self.create_output(0, is_known=True)
r = out.apply(lambda v: self.create_output("inner", is_known=True))
self.assertTrue(await r.is_known())
self.assertEqual(await r.future(), "inner")
@async_test
async def test_apply_can_run_on_known_unknown_output_value_during_preview(self):
settings.SETTINGS.dry_run = True
out = self.create_output(0, is_known=True)
r = out.apply(lambda v: self.create_output("inner", is_known=False))
self.assertFalse(await r.is_known())
self.assertEqual(await r.future(), "inner")
@async_test
async def test_apply_produces_unknown_default_on_unknown_during_preview(self):
settings.SETTINGS.dry_run = True
out = self.create_output(0, is_known=False)
r = out.apply(lambda v: v + 1)
self.assertFalse(await r.is_known())
self.assertEqual(await r.future(), None)
@async_test
async def test_apply_produces_unknown_default_on_unknown_awaitable_during_preview(self):
settings.SETTINGS.dry_run = True
out = self.create_output(0, is_known=False)
def apply(v):
fut = asyncio.Future()
fut.set_result("inner")
return fut
r = out.apply(apply)
self.assertFalse(await r.is_known())
self.assertEqual(await r.future(), None)
@async_test
async def test_apply_produces_unknown_default_on_unknown_known_output_during_preview(self):
settings.SETTINGS.dry_run = True
out = self.create_output(0, is_known=False)
r = out.apply(lambda v: self.create_output("inner", is_known=True))
self.assertFalse(await r.is_known())
self.assertEqual(await r.future(), None)
@async_test
async def test_apply_produces_unknown_default_on_unknown_unknown_output_during_preview(self):
settings.SETTINGS.dry_run = True
out = self.create_output(0, is_known=False)
r = out.apply(lambda v: self.create_output("inner", is_known=False))
self.assertFalse(await r.is_known())
self.assertEqual(await r.future(), None)
@async_test
async def test_apply_preserves_secret_on_known_during_preview(self):
settings.SETTINGS.dry_run = True
out = self.create_output(0, is_known=True, is_secret=True)
r = out.apply(lambda v: v + 1)
self.assertTrue(await r.is_known())
self.assertTrue(await r.is_secret())
self.assertEqual(await r.future(), 1)
@async_test
async def test_apply_preserves_secret_on_known_awaitable_during_preview(self):
settings.SETTINGS.dry_run = True
out = self.create_output(0, is_known=True, is_secret=True)
def apply(v):
fut = asyncio.Future()
fut.set_result("inner")
return fut
r = out.apply(apply)
self.assertTrue(await r.is_known())
self.assertTrue(await r.is_secret())
self.assertEqual(await r.future(), "inner")
@async_test
async def test_apply_preserves_secret_on_known_known_output_during_preview(self):
settings.SETTINGS.dry_run = True
out = self.create_output(0, is_known=True, is_secret=True)
r = out.apply(lambda v: self.create_output("inner", is_known=True))
self.assertTrue(await r.is_known())
self.assertTrue(await r.is_secret())
self.assertEqual(await r.future(), "inner")
@async_test
async def test_apply_preserves_secret_on_known_unknown_output_during_preview(self):
settings.SETTINGS.dry_run = True
out = self.create_output(0, is_known=True, is_secret=True)
r = out.apply(lambda v: self.create_output("inner", is_known=False))
self.assertFalse(await r.is_known())
self.assertTrue(await r.is_secret())
self.assertEqual(await r.future(), "inner")
@async_test
async def test_apply_preserves_secret_on_unknown_during_preview(self):
settings.SETTINGS.dry_run = True
out = self.create_output(0, is_known=False, is_secret=True)
r = out.apply(lambda v: v + 1)
self.assertFalse(await r.is_known())
self.assertTrue(await r.is_secret())
self.assertEqual(await r.future(), None)
@async_test
async def test_apply_preserves_secret_on_unknown_awaitable_during_preview(self):
settings.SETTINGS.dry_run = True
out = self.create_output(0, is_known=False, is_secret=True)
def apply(v):
fut = asyncio.Future()
fut.set_result("inner")
return fut
r = out.apply(apply)
self.assertFalse(await r.is_known())
self.assertTrue(await r.is_secret())
self.assertEqual(await r.future(), None)
@async_test
async def test_apply_preserves_secret_on_unknown_known_output_during_preview(self):
settings.SETTINGS.dry_run = True
out = self.create_output(0, is_known=False, is_secret=True)
r = out.apply(lambda v: self.create_output("inner", is_known=True))
self.assertFalse(await r.is_known())
self.assertTrue(await r.is_secret())
self.assertEqual(await r.future(), None)
@async_test
async def test_apply_preserves_secret_on_unknown_unknown_output_during_preview(self):
settings.SETTINGS.dry_run = True
out = self.create_output(0, is_known=False, is_secret=True)
r = out.apply(lambda v: self.create_output("inner", is_known=False))
self.assertFalse(await r.is_known())
self.assertTrue(await r.is_secret())
self.assertEqual(await r.future(), None)
@async_test
async def test_apply_propagates_secret_on_known_known_output_during_preview(self):
settings.SETTINGS.dry_run = True
out = self.create_output(0, is_known=True)
r = out.apply(lambda v: self.create_output("inner", is_known=True, is_secret=True))
self.assertTrue(await r.is_known())
self.assertTrue(await r.is_secret())
self.assertEqual(await r.future(), "inner")
@async_test
async def test_apply_propagates_secret_on_known_unknown_output_during_preview(self):
settings.SETTINGS.dry_run = True
out = self.create_output(0, is_known=True)
r = out.apply(lambda v: self.create_output("inner", is_known=False, is_secret=True))
self.assertFalse(await r.is_known())
self.assertTrue(await r.is_secret())
self.assertEqual(await r.future(), "inner")
@async_test
async def test_apply_does_not_propagate_secret_on_unknown_known_output_during_preview(self):
settings.SETTINGS.dry_run = True
out = self.create_output(0, is_known=False)
r = out.apply(lambda v: self.create_output("inner", is_known=True, is_secret=True))
self.assertFalse(await r.is_known())
self.assertFalse(await r.is_secret())
self.assertEqual(await r.future(), None)
@async_test
async def test_apply_does_not_propagate_secret_on_unknown_unknown_output_during_preview(self):
settings.SETTINGS.dry_run = True
out = self.create_output(0, is_known=False)
r = out.apply(lambda v: self.create_output("inner", is_known=false, is_secret=True))
self.assertFalse(await r.is_known())
self.assertFalse(await r.is_secret())
self.assertEqual(await r.future(), None)
@async_test
async def test_apply_can_run_on_known_value(self):
settings.SETTINGS.dry_run = False
out = self.create_output(0, is_known=True)
r = out.apply(lambda v: v + 1)
self.assertTrue(await r.is_known())
self.assertEqual(await r.future(), 1)
@async_test
async def test_apply_can_run_on_known_awaitable_value(self):
settings.SETTINGS.dry_run = False
out = self.create_output(0, is_known=True)
def apply(v):
fut = asyncio.Future()
fut.set_result("inner")
return fut
r = out.apply(apply)
self.assertTrue(await r.is_known())
self.assertEqual(await r.future(), "inner")
@async_test
async def test_apply_can_run_on_known_known_output_value(self):
settings.SETTINGS.dry_run = False
out = self.create_output(0, is_known=True)
r = out.apply(lambda v: self.create_output("inner", is_known=True))
self.assertTrue(await r.is_known())
self.assertEqual(await r.future(), "inner")
@async_test
async def test_apply_can_run_on_known_unknown_output_value(self):
settings.SETTINGS.dry_run = False
out = self.create_output(0, is_known=True)
r = out.apply(lambda v: self.create_output("inner", is_known=False))
self.assertFalse(await r.is_known())
self.assertEqual(await r.future(), "inner")
@async_test
async def test_apply_produces_known_on_unknown(self):
settings.SETTINGS.dry_run = False
out = self.create_output(0, is_known=False)
r = out.apply(lambda v: v + 1)
self.assertTrue(await r.is_known())
self.assertEqual(await r.future(), 1)
@async_test
async def test_apply_produces_known_on_unknown_awaitable(self):
settings.SETTINGS.dry_run = False
out = self.create_output(0, is_known=False)
def apply(v):
fut = asyncio.Future()
fut.set_result("inner")
return fut
r = out.apply(apply)
self.assertTrue(await r.is_known())
self.assertEqual(await r.future(), "inner")
@async_test
async def test_apply_produces_known_on_unknown_known_output(self):
settings.SETTINGS.dry_run = False
out = self.create_output(0, is_known=False)
r = out.apply(lambda v: self.create_output("inner", is_known=True))
self.assertTrue(await r.is_known())
self.assertEqual(await r.future(), "inner")
@async_test
async def test_apply_produces_unknown_on_unknown_unknown_output(self):
settings.SETTINGS.dry_run = False
out = self.create_output(0, is_known=False)
r = out.apply(lambda v: self.create_output("inner", is_known=False))
self.assertFalse(await r.is_known())
self.assertEqual(await r.future(), "inner")
@async_test
async def test_apply_preserves_secret_on_known(self):
settings.SETTINGS.dry_run = False
out = self.create_output(0, is_known=True, is_secret=True)
r = out.apply(lambda v: v + 1)
self.assertTrue(await r.is_known())
self.assertTrue(await r.is_secret())
self.assertEqual(await r.future(), 1)
@async_test
async def test_apply_preserves_secret_on_known_awaitable(self):
settings.SETTINGS.dry_run = False
out = self.create_output(0, is_known=True, is_secret=True)
def apply(v):
fut = asyncio.Future()
fut.set_result("inner")
return fut
r = out.apply(apply)
self.assertTrue(await r.is_known())
self.assertTrue(await r.is_secret())
self.assertEqual(await r.future(), "inner")
@async_test
async def test_apply_preserves_secret_on_known_known_output(self):
settings.SETTINGS.dry_run = False
out = self.create_output(0, is_known=True, is_secret=True)
r = out.apply(lambda v: self.create_output("inner", is_known=True))
self.assertTrue(await r.is_known())
self.assertTrue(await r.is_secret())
self.assertEqual(await r.future(), "inner")
@async_test
async def test_apply_preserves_secret_on_known_unknown_output(self):
settings.SETTINGS.dry_run = False
out = self.create_output(0, is_known=True, is_secret=True)
r = out.apply(lambda v: self.create_output("inner", is_known=False))
self.assertFalse(await r.is_known())
self.assertTrue(await r.is_secret())
self.assertEqual(await r.future(), "inner")
@async_test
async def test_apply_preserves_secret_on_unknown(self):
settings.SETTINGS.dry_run = False
out = self.create_output(0, is_known=False, is_secret=True)
r = out.apply(lambda v: v + 1)
self.assertTrue(await r.is_known())
self.assertTrue(await r.is_secret())
self.assertEqual(await r.future(), 1)
@async_test
async def test_apply_preserves_secret_on_unknown_awaitable(self):
settings.SETTINGS.dry_run = False
out = self.create_output(0, is_known=False, is_secret=True)
def apply(v):
fut = asyncio.Future()
fut.set_result("inner")
return fut
r = out.apply(apply)
self.assertTrue(await r.is_known())
self.assertTrue(await r.is_secret())
self.assertEqual(await r.future(), "inner")
@async_test
async def test_apply_preserves_secret_on_unknown_known_output(self):
settings.SETTINGS.dry_run = False
out = self.create_output(0, is_known=False, is_secret=True)
r = out.apply(lambda v: self.create_output("inner", is_known=True))
self.assertTrue(await r.is_known())
self.assertTrue(await r.is_secret())
self.assertEqual(await r.future(), "inner")
@async_test
async def test_apply_preserves_secret_on_unknown_unknown_output(self):
settings.SETTINGS.dry_run = False
out = self.create_output(0, is_known=False, is_secret=True)
r = out.apply(lambda v: self.create_output("inner", is_known=False))
self.assertFalse(await r.is_known())
self.assertTrue(await r.is_secret())
self.assertEqual(await r.future(), "inner")
@async_test
async def test_apply_propagates_secret_on_known_known_output(self):
settings.SETTINGS.dry_run = False
out = self.create_output(0, is_known=True)
r = out.apply(lambda v: self.create_output("inner", is_known=True, is_secret=True))
self.assertTrue(await r.is_known())
self.assertTrue(await r.is_secret())
self.assertEqual(await r.future(), "inner")
@async_test
async def test_apply_propagates_secret_on_known_unknown_output(self):
settings.SETTINGS.dry_run = False
out = self.create_output(0, is_known=True)
r = out.apply(lambda v: self.create_output("inner", is_known=False, is_secret=True))
self.assertFalse(await r.is_known())
self.assertTrue(await r.is_secret())
self.assertEqual(await r.future(), "inner")
@async_test
async def test_apply_propagates_secret_on_unknown_known_output(self):
settings.SETTINGS.dry_run = False
out = self.create_output(0, is_known=False)
r = out.apply(lambda v: self.create_output("inner", is_known=True, is_secret=True))
self.assertTrue(await r.is_known())
self.assertTrue(await r.is_secret())
self.assertEqual(await r.future(), "inner")
@async_test
async def test_apply_propagates_secret_on_unknown_unknown_output(self):
settings.SETTINGS.dry_run = False
out = self.create_output(0, is_known=False)
r = out.apply(lambda v: self.create_output("inner", is_known=False, is_secret=True))
self.assertFalse(await r.is_known())
self.assertTrue(await r.is_secret())
self.assertEqual(await r.future(), "inner")
@async_test
async def test_apply_unknown_output(self):
fut = asyncio.Future()
fut.set_result("foo")
known_fut = asyncio.Future()
known_fut.set_result(True)
out = Output(set(), fut, known_fut)
out = self.create_output("foo", is_known=True)
r1 = out.apply(lambda v: UNKNOWN)
r2 = out.apply(lambda v: [v, UNKNOWN])