Include config secret info in Construct calls (#7358)

This commit is contained in:
Evan Boyle 2021-06-24 15:38:01 -07:00 committed by GitHub
parent d525a8b331
commit 634e97cd55
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 341 additions and 169 deletions

View file

@ -106,7 +106,8 @@ func (src *evalSource) Iterate(
regChan := make(chan *registerResourceEvent) regChan := make(chan *registerResourceEvent)
regOutChan := make(chan *registerResourceOutputsEvent) regOutChan := make(chan *registerResourceOutputsEvent)
regReadChan := make(chan *readResourceEvent) regReadChan := make(chan *readResourceEvent)
mon, err := newResourceMonitor(src, providers, regChan, regOutChan, regReadChan, opts, config, tracingSpan) mon, err := newResourceMonitor(
src, providers, regChan, regOutChan, regReadChan, opts, config, configSecretKeys, tracingSpan)
if err != nil { if err != nil {
return nil, result.FromError(errors.Wrap(err, "failed to start resource monitor")) return nil, result.FromError(errors.Wrap(err, "failed to start resource monitor"))
} }
@ -411,7 +412,7 @@ var _ SourceResourceMonitor = (*resmon)(nil)
// newResourceMonitor creates a new resource monitor RPC server. // newResourceMonitor creates a new resource monitor RPC server.
func newResourceMonitor(src *evalSource, provs ProviderSource, regChan chan *registerResourceEvent, func newResourceMonitor(src *evalSource, provs ProviderSource, regChan chan *registerResourceEvent,
regOutChan chan *registerResourceOutputsEvent, regReadChan chan *readResourceEvent, opts Options, regOutChan chan *registerResourceOutputsEvent, regReadChan chan *readResourceEvent, opts Options,
config map[config.Key]string, tracingSpan opentracing.Span) (*resmon, error) { config map[config.Key]string, configSecretKeys []config.Key, tracingSpan opentracing.Span) (*resmon, error) {
// Create our cancellation channel. // Create our cancellation channel.
cancel := make(chan bool) cancel := make(chan bool)
@ -449,12 +450,13 @@ func newResourceMonitor(src *evalSource, provs ProviderSource, regChan chan *reg
} }
resmon.constructInfo = plugin.ConstructInfo{ resmon.constructInfo = plugin.ConstructInfo{
Project: string(src.runinfo.Proj.Name), Project: string(src.runinfo.Proj.Name),
Stack: string(src.runinfo.Target.Name), Stack: string(src.runinfo.Target.Name),
Config: config, Config: config,
DryRun: src.dryRun, ConfigSecretKeys: configSecretKeys,
Parallel: opts.Parallel, DryRun: src.dryRun,
MonitorAddress: fmt.Sprintf("127.0.0.1:%d", port), Parallel: opts.Parallel,
MonitorAddress: fmt.Sprintf("127.0.0.1:%d", port),
} }
resmon.done = done resmon.done = done

View file

@ -222,12 +222,13 @@ type ReadResult struct {
// ConstructInfo contains all of the information required to register resources as part of a call to Construct. // ConstructInfo contains all of the information required to register resources as part of a call to Construct.
type ConstructInfo struct { type ConstructInfo struct {
Project string // the project name housing the program being run. Project string // the project name housing the program being run.
Stack string // the stack name being evaluated. Stack string // the stack name being evaluated.
Config map[config.Key]string // the configuration variables to apply before running. Config map[config.Key]string // the configuration variables to apply before running.
DryRun bool // true if we are performing a dry-run (preview). ConfigSecretKeys []config.Key // the configuration keys that have secret values.
Parallel int // the degree of parallelism for resource operations (<=1 for serial). DryRun bool // true if we are performing a dry-run (preview).
MonitorAddress string // the RPC address to the host resource monitor. Parallel int // the degree of parallelism for resource operations (<=1 for serial).
MonitorAddress string // the RPC address to the host resource monitor.
} }
// ConstructOptions captures options for a call to Construct. // ConstructOptions captures options for a call to Construct.

View file

@ -1102,11 +1102,16 @@ func (p *provider) Construct(info ConstructInfo, typ tokens.Type, name tokens.QN
for k, v := range info.Config { for k, v := range info.Config {
config[k.String()] = v config[k.String()] = v
} }
configSecretKeys := []string{}
for _, k := range info.ConfigSecretKeys {
configSecretKeys = append(configSecretKeys, k.String())
}
resp, err := client.Construct(p.requestContext(), &pulumirpc.ConstructRequest{ resp, err := client.Construct(p.requestContext(), &pulumirpc.ConstructRequest{
Project: info.Project, Project: info.Project,
Stack: info.Stack, Stack: info.Stack,
Config: config, Config: config,
ConfigSecretKeys: configSecretKeys,
DryRun: info.DryRun, DryRun: info.DryRun,
Parallel: int32(info.Parallel), Parallel: int32(info.Parallel),
MonitorEndpoint: info.MonitorAddress, MonitorEndpoint: info.MonitorAddress,

View file

@ -409,13 +409,24 @@ func (p *providerServer) Construct(ctx context.Context,
} }
cfg[configKey] = v cfg[configKey] = v
} }
cfgSecretKeys := []config.Key{}
for _, k := range req.GetConfigSecretKeys() {
key, err := config.ParseKey(k)
if err != nil {
return nil, err
}
cfgSecretKeys = append(cfgSecretKeys, key)
}
info := ConstructInfo{ info := ConstructInfo{
Project: req.GetProject(), Project: req.GetProject(),
Stack: req.GetStack(), Stack: req.GetStack(),
Config: cfg, Config: cfg,
DryRun: req.GetDryRun(), ConfigSecretKeys: cfgSecretKeys,
Parallel: int(req.GetParallel()), DryRun: req.GetDryRun(),
MonitorAddress: req.GetMonitorEndpoint(), Parallel: int(req.GetParallel()),
MonitorAddress: req.GetMonitorEndpoint(),
} }
aliases := make([]resource.URN, len(req.GetAliases())) aliases := make([]resource.URN, len(req.GetAliases()))

View file

@ -37,13 +37,14 @@ func construct(ctx context.Context, req *pulumirpc.ConstructRequest, engineConn
// Configure the RunInfo. // Configure the RunInfo.
runInfo := RunInfo{ runInfo := RunInfo{
Project: req.GetProject(), Project: req.GetProject(),
Stack: req.GetStack(), Stack: req.GetStack(),
Config: req.GetConfig(), Config: req.GetConfig(),
Parallel: int(req.GetParallel()), ConfigSecretKeys: req.GetConfigSecretKeys(),
DryRun: req.GetDryRun(), Parallel: int(req.GetParallel()),
MonitorAddr: req.GetMonitorEndpoint(), DryRun: req.GetDryRun(),
engineConn: engineConn, MonitorAddr: req.GetMonitorEndpoint(),
engineConn: engineConn,
} }
pulumiCtx, err := NewContext(ctx, runInfo) pulumiCtx, err := NewContext(ctx, runInfo)
if err != nil { if err != nil {

View file

@ -5259,7 +5259,7 @@ proto.pulumirpc.DeleteRequest.prototype.setTimeout = function(value) {
* @private {!Array<number>} * @private {!Array<number>}
* @const * @const
*/ */
proto.pulumirpc.ConstructRequest.repeatedFields_ = [14,15]; proto.pulumirpc.ConstructRequest.repeatedFields_ = [14,15,16];
@ -5306,7 +5306,8 @@ proto.pulumirpc.ConstructRequest.toObject = function(includeInstance, msg) {
protect: jspb.Message.getBooleanFieldWithDefault(msg, 12, false), protect: jspb.Message.getBooleanFieldWithDefault(msg, 12, false),
providersMap: (f = msg.getProvidersMap()) ? f.toObject(includeInstance, undefined) : [], providersMap: (f = msg.getProvidersMap()) ? f.toObject(includeInstance, undefined) : [],
aliasesList: (f = jspb.Message.getRepeatedField(msg, 14)) == null ? undefined : f, aliasesList: (f = jspb.Message.getRepeatedField(msg, 14)) == null ? undefined : f,
dependenciesList: (f = jspb.Message.getRepeatedField(msg, 15)) == null ? undefined : f dependenciesList: (f = jspb.Message.getRepeatedField(msg, 15)) == null ? undefined : f,
configsecretkeysList: (f = jspb.Message.getRepeatedField(msg, 16)) == null ? undefined : f
}; };
if (includeInstance) { if (includeInstance) {
@ -5410,6 +5411,10 @@ proto.pulumirpc.ConstructRequest.deserializeBinaryFromReader = function(msg, rea
var value = /** @type {string} */ (reader.readString()); var value = /** @type {string} */ (reader.readString());
msg.addDependencies(value); msg.addDependencies(value);
break; break;
case 16:
var value = /** @type {string} */ (reader.readString());
msg.addConfigsecretkeys(value);
break;
default: default:
reader.skipField(); reader.skipField();
break; break;
@ -5536,6 +5541,13 @@ proto.pulumirpc.ConstructRequest.serializeBinaryToWriter = function(message, wri
f f
); );
} }
f = message.getConfigsecretkeysList();
if (f.length > 0) {
writer.writeRepeatedString(
16,
f
);
}
}; };
@ -6034,6 +6046,43 @@ proto.pulumirpc.ConstructRequest.prototype.clearDependenciesList = function() {
}; };
/**
* repeated string configSecretKeys = 16;
* @return {!Array<string>}
*/
proto.pulumirpc.ConstructRequest.prototype.getConfigsecretkeysList = function() {
return /** @type {!Array<string>} */ (jspb.Message.getRepeatedField(this, 16));
};
/**
* @param {!Array<string>} value
* @return {!proto.pulumirpc.ConstructRequest} returns this
*/
proto.pulumirpc.ConstructRequest.prototype.setConfigsecretkeysList = function(value) {
return jspb.Message.setField(this, 16, value || []);
};
/**
* @param {string} value
* @param {number=} opt_index
* @return {!proto.pulumirpc.ConstructRequest} returns this
*/
proto.pulumirpc.ConstructRequest.prototype.addConfigsecretkeys = function(value, opt_index) {
return jspb.Message.addToRepeatedField(this, 16, value, opt_index);
};
/**
* Clears the list making it empty but non-null.
* @return {!proto.pulumirpc.ConstructRequest} returns this
*/
proto.pulumirpc.ConstructRequest.prototype.clearConfigsecretkeysList = function() {
return this.setConfigsecretkeysList([]);
};

View file

@ -291,7 +291,7 @@ class Server implements grpc.UntypedServiceImplementation {
pulumiConfig[k] = v; pulumiConfig[k] = v;
} }
} }
runtime.setAllConfig(pulumiConfig); runtime.setAllConfig(pulumiConfig, req.getConfigsecretkeysList());
// Deserialize the inputs and apply appropriate dependencies. // Deserialize the inputs and apply appropriate dependencies.
const inputs: Inputs = {}; const inputs: Inputs = {};

View file

@ -1309,6 +1309,7 @@ type ConstructRequest struct {
Providers map[string]string `protobuf:"bytes,13,rep,name=providers,proto3" json:"providers,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` Providers map[string]string `protobuf:"bytes,13,rep,name=providers,proto3" json:"providers,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
Aliases []string `protobuf:"bytes,14,rep,name=aliases,proto3" json:"aliases,omitempty"` Aliases []string `protobuf:"bytes,14,rep,name=aliases,proto3" json:"aliases,omitempty"`
Dependencies []string `protobuf:"bytes,15,rep,name=dependencies,proto3" json:"dependencies,omitempty"` Dependencies []string `protobuf:"bytes,15,rep,name=dependencies,proto3" json:"dependencies,omitempty"`
ConfigSecretKeys []string `protobuf:"bytes,16,rep,name=configSecretKeys,proto3" json:"configSecretKeys,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`
@ -1444,6 +1445,13 @@ func (m *ConstructRequest) GetDependencies() []string {
return nil return nil
} }
func (m *ConstructRequest) GetConfigSecretKeys() []string {
if m != nil {
return m.ConfigSecretKeys
}
return nil
}
// PropertyDependencies describes the resources that a particular property depends on. // PropertyDependencies describes the resources that a particular property depends on.
type ConstructRequest_PropertyDependencies struct { type ConstructRequest_PropertyDependencies struct {
Urns []string `protobuf:"bytes,1,rep,name=urns,proto3" json:"urns,omitempty"` Urns []string `protobuf:"bytes,1,rep,name=urns,proto3" json:"urns,omitempty"`
@ -1686,112 +1694,113 @@ func init() {
func init() { proto.RegisterFile("provider.proto", fileDescriptor_c6a9f3c02af3d1c8) } func init() { proto.RegisterFile("provider.proto", fileDescriptor_c6a9f3c02af3d1c8) }
var fileDescriptor_c6a9f3c02af3d1c8 = []byte{ var fileDescriptor_c6a9f3c02af3d1c8 = []byte{
// 1670 bytes of a gzipped FileDescriptorProto // 1689 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x58, 0xcd, 0x72, 0x1b, 0x45, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x58, 0xcd, 0x72, 0xdb, 0x46,
0x10, 0xf6, 0x4a, 0xb2, 0x6c, 0xb5, 0x7e, 0x22, 0x0f, 0xc1, 0x51, 0x14, 0x1f, 0x5c, 0x0b, 0x55, 0x12, 0x16, 0x48, 0x8a, 0x14, 0x9b, 0x3f, 0xa6, 0x66, 0xbd, 0x32, 0x4d, 0xeb, 0xa0, 0xc2, 0x6e,
0x98, 0x84, 0xc8, 0xc6, 0x39, 0x40, 0x52, 0x4e, 0x05, 0xdb, 0x92, 0x8d, 0x2b, 0x89, 0x63, 0xd6, 0xd5, 0x6a, 0xed, 0x35, 0xa5, 0x95, 0x0f, 0x89, 0x5d, 0x72, 0x39, 0x92, 0x48, 0x29, 0x2a, 0xdb,
0x09, 0x3f, 0xa7, 0x64, 0xb3, 0x1a, 0xc9, 0x8b, 0xa5, 0xdd, 0x65, 0x76, 0x56, 0x29, 0x73, 0xe6, 0xb2, 0x02, 0xd9, 0xf9, 0x39, 0xd9, 0x30, 0x38, 0xa4, 0x10, 0x91, 0x00, 0x32, 0x18, 0xd0, 0xa5,
0xc0, 0x05, 0xae, 0x14, 0x0f, 0x01, 0x54, 0xf1, 0x04, 0x3c, 0x08, 0x1c, 0x79, 0x00, 0x8a, 0x17, 0x9c, 0x73, 0xc8, 0x25, 0xb9, 0xa6, 0x72, 0xca, 0x13, 0x24, 0xa9, 0xca, 0x13, 0xe4, 0x41, 0x92,
0xa0, 0xe6, 0x6f, 0x3d, 0x23, 0xad, 0x7f, 0x49, 0xc1, 0x6d, 0x7b, 0xba, 0xa7, 0xa7, 0xfb, 0x9b, 0x63, 0x1e, 0x20, 0x6f, 0x90, 0x9a, 0x3f, 0x68, 0x86, 0x84, 0x7e, 0xe3, 0x4a, 0x6e, 0xe8, 0xe9,
0x9e, 0xfe, 0x59, 0xa8, 0x45, 0x24, 0x1c, 0xf9, 0x5d, 0x4c, 0x5a, 0x11, 0x09, 0x69, 0x88, 0x4a, 0x9e, 0x9e, 0xee, 0x6f, 0x7a, 0xfa, 0x07, 0x50, 0x8f, 0x48, 0x38, 0xf6, 0x7b, 0x98, 0xb4, 0x23,
0x51, 0x32, 0x48, 0x86, 0x3e, 0x89, 0xbc, 0x66, 0x25, 0x1a, 0x24, 0x7d, 0x3f, 0x10, 0x8c, 0xe6, 0x12, 0xd2, 0x10, 0x95, 0xa3, 0x64, 0x98, 0x8c, 0x7c, 0x12, 0x79, 0xad, 0x6a, 0x34, 0x4c, 0x06,
0x8d, 0x7e, 0x18, 0xf6, 0x07, 0x78, 0x99, 0x53, 0x2f, 0x93, 0xde, 0x32, 0x1e, 0x46, 0xf4, 0x48, 0x7e, 0x20, 0x18, 0xad, 0x5b, 0x83, 0x30, 0x1c, 0x0c, 0xf1, 0x0a, 0xa7, 0x5e, 0x27, 0xfd, 0x15,
0x32, 0x17, 0xc6, 0x99, 0x31, 0x25, 0x89, 0x47, 0x05, 0xd7, 0x7e, 0x0f, 0xea, 0xdb, 0x98, 0xee, 0x3c, 0x8a, 0xe8, 0xb1, 0x64, 0x2e, 0x4e, 0x32, 0x63, 0x4a, 0x12, 0x8f, 0x0a, 0xae, 0xfd, 0x3f,
0x7b, 0x07, 0x78, 0xe8, 0x3a, 0xf8, 0xab, 0x04, 0xc7, 0x14, 0x35, 0x60, 0x66, 0x84, 0x49, 0xec, 0x68, 0xec, 0x60, 0x7a, 0xe0, 0x1d, 0xe2, 0x91, 0xeb, 0xe0, 0xcf, 0x12, 0x1c, 0x53, 0xd4, 0x84,
0x87, 0x41, 0xc3, 0x5a, 0xb4, 0x96, 0xa6, 0x1d, 0x45, 0xda, 0xb7, 0x60, 0x4e, 0x93, 0x8e, 0xa3, 0xd2, 0x18, 0x93, 0xd8, 0x0f, 0x83, 0xa6, 0xb5, 0x64, 0x2d, 0xcf, 0x3a, 0x8a, 0xb4, 0xef, 0xc0,
0x30, 0x88, 0x31, 0x9a, 0x87, 0x62, 0xcc, 0x57, 0xb8, 0x74, 0xc9, 0x91, 0x94, 0xfd, 0x43, 0x0e, 0xbc, 0x26, 0x1d, 0x47, 0x61, 0x10, 0x63, 0xb4, 0x00, 0xc5, 0x98, 0xaf, 0x70, 0xe9, 0xb2, 0x23,
0xea, 0x9b, 0x61, 0xd0, 0xf3, 0xfb, 0x09, 0xc1, 0x4a, 0xf7, 0xc7, 0x50, 0x1a, 0xb9, 0xc4, 0x77, 0x29, 0xfb, 0x9b, 0x1c, 0x34, 0xb6, 0xc2, 0xa0, 0xef, 0x0f, 0x12, 0x82, 0x95, 0xee, 0xf7, 0xa1,
0x5f, 0x0e, 0x70, 0xdc, 0xb0, 0x16, 0xf3, 0x4b, 0xe5, 0xd5, 0x9b, 0xad, 0xd4, 0xaf, 0xd6, 0xb8, 0x3c, 0x76, 0x89, 0xef, 0xbe, 0x1e, 0xe2, 0xb8, 0x69, 0x2d, 0xe5, 0x97, 0x2b, 0x6b, 0xb7, 0xdb,
0x7c, 0xeb, 0x53, 0x25, 0xdc, 0x09, 0x28, 0x39, 0x72, 0x8e, 0x37, 0xa3, 0x5b, 0x50, 0x70, 0x49, 0xa9, 0x5f, 0xed, 0x49, 0xf9, 0xf6, 0x87, 0x4a, 0xb8, 0x1b, 0x50, 0x72, 0xec, 0x9c, 0x6c, 0x46,
0x3f, 0x6e, 0xe4, 0x16, 0xad, 0xa5, 0xf2, 0xea, 0xb5, 0x96, 0x70, 0xb3, 0xa5, 0xdc, 0x6c, 0xed, 0x77, 0xa0, 0xe0, 0x92, 0x41, 0xdc, 0xcc, 0x2d, 0x59, 0xcb, 0x95, 0xb5, 0x1b, 0x6d, 0xe1, 0x66,
0x73, 0x37, 0x1d, 0x2e, 0x84, 0xde, 0x86, 0xaa, 0xeb, 0x79, 0x38, 0xa2, 0xfb, 0xd8, 0x23, 0x98, 0x5b, 0xb9, 0xd9, 0x3e, 0xe0, 0x6e, 0x3a, 0x5c, 0x08, 0xfd, 0x1b, 0x6a, 0xae, 0xe7, 0xe1, 0x88,
0xc6, 0x8d, 0xfc, 0xa2, 0xb5, 0x34, 0xeb, 0x98, 0x8b, 0x68, 0x09, 0xae, 0x88, 0x05, 0x07, 0xc7, 0x1e, 0x60, 0x8f, 0x60, 0x1a, 0x37, 0xf3, 0x4b, 0xd6, 0xf2, 0x9c, 0x63, 0x2e, 0xa2, 0x65, 0xb8,
0x61, 0x42, 0x3c, 0x1c, 0x37, 0x0a, 0x5c, 0x6e, 0x7c, 0xb9, 0xb9, 0x06, 0x35, 0xd3, 0x32, 0x54, 0x26, 0x16, 0x1c, 0x1c, 0x87, 0x09, 0xf1, 0x70, 0xdc, 0x2c, 0x70, 0xb9, 0xc9, 0xe5, 0xd6, 0x3a,
0x87, 0xfc, 0x21, 0x3e, 0x92, 0x10, 0xb0, 0x4f, 0x74, 0x15, 0xa6, 0x47, 0xee, 0x20, 0xc1, 0xdc, 0xd4, 0x4d, 0xcb, 0x50, 0x03, 0xf2, 0x47, 0xf8, 0x58, 0x42, 0xc0, 0x3e, 0xd1, 0x75, 0x98, 0x1d,
0xc2, 0x92, 0x23, 0x88, 0x7b, 0xb9, 0x0f, 0x2d, 0xfb, 0x3b, 0x0b, 0xe6, 0x34, 0x4f, 0x25, 0x8e, 0xbb, 0xc3, 0x04, 0x73, 0x0b, 0xcb, 0x8e, 0x20, 0x1e, 0xe4, 0xde, 0xb5, 0xec, 0xaf, 0x2c, 0x98,
0x13, 0x36, 0x5a, 0x27, 0xd8, 0x18, 0x27, 0x51, 0x14, 0x12, 0x1a, 0xef, 0x11, 0x3c, 0xf2, 0xf1, 0xd7, 0x3c, 0x95, 0x38, 0x4e, 0xd9, 0x68, 0x9d, 0x62, 0x63, 0x9c, 0x44, 0x51, 0x48, 0x68, 0xbc,
0x2b, 0xae, 0x7f, 0xd6, 0x19, 0x5f, 0xce, 0xf2, 0x26, 0x9f, 0xe9, 0x8d, 0xfd, 0xab, 0x05, 0xd7, 0x4f, 0xf0, 0xd8, 0xc7, 0x6f, 0xb8, 0xfe, 0x39, 0x67, 0x72, 0x39, 0xcb, 0x9b, 0x7c, 0xa6, 0x37,
0x53, 0x7b, 0x3a, 0x84, 0x84, 0xe4, 0xb1, 0x1f, 0xc7, 0x7e, 0xd0, 0x7f, 0x88, 0x8f, 0x62, 0xf4, 0xf6, 0x4f, 0x16, 0xdc, 0x4c, 0xed, 0xe9, 0x12, 0x12, 0x92, 0xa7, 0x7e, 0x1c, 0xfb, 0xc1, 0xe0,
0x09, 0x94, 0x87, 0xc7, 0xa4, 0xbc, 0xb4, 0xe5, 0xac, 0x4b, 0x1b, 0xdf, 0xda, 0x3a, 0xfe, 0x76, 0x31, 0x3e, 0x8e, 0xd1, 0x07, 0x50, 0x19, 0x9d, 0x90, 0xf2, 0xd2, 0x56, 0xb2, 0x2e, 0x6d, 0x72,
0x74, 0x1d, 0xcd, 0x0d, 0x80, 0x63, 0x16, 0x42, 0x50, 0x08, 0xdc, 0x21, 0x96, 0xd8, 0xf1, 0x6f, 0x6b, 0xfb, 0xe4, 0xdb, 0xd1, 0x75, 0xb4, 0x36, 0x01, 0x4e, 0x58, 0x08, 0x41, 0x21, 0x70, 0x47,
0xb4, 0x08, 0xe5, 0x2e, 0x8e, 0x3d, 0xe2, 0x47, 0x94, 0xc5, 0xa1, 0x80, 0x50, 0x5f, 0xb2, 0x7f, 0x58, 0x62, 0xc7, 0xbf, 0xd1, 0x12, 0x54, 0x7a, 0x38, 0xf6, 0x88, 0x1f, 0x51, 0x16, 0x87, 0x02,
0xb6, 0xa0, 0xba, 0x13, 0x8c, 0xc2, 0xc3, 0x34, 0xb6, 0xea, 0x90, 0xa7, 0xe1, 0xa1, 0xba, 0x02, 0x42, 0x7d, 0xc9, 0xfe, 0xc1, 0x82, 0xda, 0x6e, 0x30, 0x0e, 0x8f, 0xd2, 0xd8, 0x6a, 0x40, 0x9e,
0x1a, 0x1e, 0x5e, 0x2c, 0x46, 0x9a, 0x30, 0xab, 0x1e, 0x1c, 0x07, 0xaa, 0xe4, 0xa4, 0xb4, 0xfe, 0x86, 0x47, 0xea, 0x0a, 0x68, 0x78, 0x74, 0xb9, 0x18, 0x69, 0xc1, 0x9c, 0x7a, 0x70, 0x1c, 0xa8,
0x24, 0x0a, 0x9c, 0xa5, 0xc8, 0x2c, 0x94, 0xa7, 0xb3, 0x51, 0x1e, 0x41, 0x4d, 0xd9, 0x2b, 0x6f, 0xb2, 0x93, 0xd2, 0xfa, 0x93, 0x28, 0x70, 0x96, 0x22, 0xb3, 0x50, 0x9e, 0xcd, 0x46, 0x79, 0x0c,
0x7c, 0x19, 0x8a, 0x04, 0xd3, 0x84, 0x88, 0x77, 0x76, 0x8a, 0x81, 0x52, 0x0c, 0xdd, 0x81, 0xd9, 0x75, 0x65, 0xaf, 0xbc, 0xf1, 0x15, 0x28, 0x12, 0x4c, 0x13, 0x22, 0xde, 0xd9, 0x19, 0x06, 0x4a,
0x9e, 0xeb, 0x0f, 0x12, 0x82, 0x99, 0x4f, 0x79, 0xbe, 0x45, 0xbb, 0x87, 0x03, 0xec, 0x1d, 0x6e, 0x31, 0x74, 0x0f, 0xe6, 0xfa, 0xae, 0x3f, 0x4c, 0x08, 0x66, 0x3e, 0xe5, 0xf9, 0x16, 0xed, 0x1e,
0x09, 0xbe, 0x93, 0x0a, 0xda, 0x5f, 0x43, 0x85, 0x73, 0x34, 0x98, 0xd4, 0x91, 0x25, 0x87, 0x7d, 0x0e, 0xb1, 0x77, 0xb4, 0x2d, 0xf8, 0x4e, 0x2a, 0x68, 0x7f, 0x0e, 0x55, 0xce, 0xd1, 0x60, 0x52,
0x32, 0x98, 0xc2, 0x41, 0xf7, 0x6c, 0x98, 0x98, 0x10, 0x13, 0x0e, 0xf0, 0x2b, 0x11, 0x4b, 0xa7, 0x47, 0x96, 0x1d, 0xf6, 0xc9, 0x60, 0x0a, 0x87, 0xbd, 0xf3, 0x61, 0x62, 0x42, 0x4c, 0x38, 0xc0,
0x09, 0x33, 0x21, 0x3b, 0x81, 0xaa, 0x3c, 0xfb, 0xd8, 0x65, 0x3f, 0x88, 0x12, 0x19, 0xdd, 0xa7, 0x6f, 0x44, 0x2c, 0x9d, 0x25, 0xcc, 0x84, 0xec, 0x04, 0x6a, 0xf2, 0xec, 0x13, 0x97, 0xfd, 0x20,
0xb9, 0x2c, 0xc4, 0x2e, 0xe7, 0xf2, 0x86, 0x74, 0x59, 0x72, 0xe4, 0xd5, 0x46, 0x98, 0x50, 0xf5, 0x4a, 0x64, 0x74, 0x9f, 0xe5, 0xb2, 0x10, 0xbb, 0x9a, 0xcb, 0x9b, 0xd2, 0x65, 0xc9, 0x91, 0x57,
0x42, 0x53, 0x9a, 0xa5, 0x2f, 0x82, 0xdd, 0x38, 0x0d, 0x32, 0x49, 0xd9, 0xbf, 0x58, 0x50, 0x6e, 0x1b, 0x61, 0x42, 0xd5, 0x0b, 0x4d, 0x69, 0x96, 0xbe, 0x08, 0x76, 0xe3, 0x34, 0xc8, 0x24, 0x65,
0xfb, 0xbd, 0x9e, 0x82, 0xad, 0x06, 0x39, 0xbf, 0x2b, 0x77, 0xe7, 0xfc, 0xae, 0x82, 0x31, 0x37, 0xff, 0x68, 0x41, 0xa5, 0xe3, 0xf7, 0xfb, 0x0a, 0xb6, 0x3a, 0xe4, 0xfc, 0x9e, 0xdc, 0x9d, 0xf3,
0x09, 0x63, 0xfe, 0x22, 0x30, 0x16, 0xce, 0x01, 0x23, 0x4b, 0x0d, 0x7e, 0x3f, 0x08, 0x09, 0xde, 0x7b, 0x0a, 0xc6, 0xdc, 0x34, 0x8c, 0xf9, 0xcb, 0xc0, 0x58, 0xb8, 0x00, 0x8c, 0x2c, 0x35, 0xf8,
0x3c, 0x70, 0x83, 0x3e, 0x0f, 0xb1, 0xfc, 0x52, 0xc9, 0x31, 0x17, 0xed, 0xdf, 0x2c, 0xa8, 0xec, 0x83, 0x20, 0x24, 0x78, 0xeb, 0xd0, 0x0d, 0x06, 0x3c, 0xc4, 0xf2, 0xcb, 0x65, 0xc7, 0x5c, 0xb4,
0x49, 0xb7, 0x98, 0xe5, 0x68, 0x05, 0x0a, 0x87, 0x7e, 0x20, 0x8c, 0xae, 0xad, 0x2e, 0x68, 0xb8, 0x7f, 0xb6, 0xa0, 0xba, 0x2f, 0xdd, 0x62, 0x96, 0xa3, 0x55, 0x28, 0x1c, 0xf9, 0x81, 0x30, 0xba,
0xe9, 0x62, 0xad, 0x87, 0x7e, 0xd0, 0x75, 0xb8, 0x24, 0x5a, 0x80, 0x12, 0xc7, 0x9d, 0xad, 0xcb, 0xbe, 0xb6, 0xa8, 0xe1, 0xa6, 0x8b, 0xb5, 0x1f, 0xfb, 0x41, 0xcf, 0xe1, 0x92, 0x68, 0x11, 0xca,
0xbc, 0x72, 0xbc, 0x60, 0xbf, 0x80, 0x02, 0x93, 0x45, 0x33, 0x90, 0x5f, 0x6f, 0xb7, 0xeb, 0x53, 0x1c, 0x77, 0xb6, 0x2e, 0xf3, 0xca, 0xc9, 0x82, 0xfd, 0x0a, 0x0a, 0x4c, 0x16, 0x95, 0x20, 0xbf,
0xe8, 0x0a, 0x94, 0xd7, 0xdb, 0xed, 0xe7, 0x4e, 0x67, 0xef, 0xd1, 0xfa, 0x66, 0xa7, 0x6e, 0x21, 0xd1, 0xe9, 0x34, 0x66, 0xd0, 0x35, 0xa8, 0x6c, 0x74, 0x3a, 0x2f, 0x9d, 0xee, 0xfe, 0x93, 0x8d,
0x80, 0x62, 0xbb, 0xf3, 0xa8, 0xf3, 0xb4, 0x53, 0xcf, 0x21, 0x04, 0x35, 0xf1, 0x9d, 0xf2, 0xf3, 0xad, 0x6e, 0xc3, 0x42, 0x00, 0xc5, 0x4e, 0xf7, 0x49, 0xf7, 0x79, 0xb7, 0x91, 0x43, 0x08, 0xea,
0x8c, 0xff, 0x6c, 0xaf, 0xbd, 0xfe, 0xb4, 0x53, 0x2f, 0x30, 0xbe, 0xf8, 0x4e, 0xf9, 0xd3, 0xf6, 0xe2, 0x3b, 0xe5, 0xe7, 0x19, 0xff, 0xc5, 0x7e, 0x67, 0xe3, 0x79, 0xb7, 0x51, 0x60, 0x7c, 0xf1,
0x1f, 0x79, 0xa8, 0x08, 0xd0, 0x65, 0xbc, 0x34, 0x61, 0x96, 0xe0, 0x68, 0xe0, 0x7a, 0xb2, 0x5c, 0x9d, 0xf2, 0x67, 0xed, 0x5f, 0xf3, 0x50, 0x15, 0xa0, 0xcb, 0x78, 0x69, 0xc1, 0x1c, 0xc1, 0xd1,
0x94, 0x9c, 0x94, 0x66, 0x8f, 0x32, 0xa6, 0xa2, 0x92, 0xe4, 0x38, 0x4b, 0x91, 0x68, 0x05, 0xde, 0xd0, 0xf5, 0x64, 0xb9, 0x28, 0x3b, 0x29, 0xcd, 0x1e, 0x65, 0x4c, 0x45, 0x25, 0xc9, 0x71, 0x96,
0xe8, 0xe2, 0x01, 0xa6, 0x78, 0x03, 0xf7, 0x42, 0x96, 0x62, 0xf9, 0x0e, 0x99, 0xfe, 0xb2, 0x58, 0x22, 0xd1, 0x2a, 0xfc, 0xa3, 0x87, 0x87, 0x98, 0xe2, 0x4d, 0xdc, 0x0f, 0x59, 0x8a, 0xe5, 0x3b,
0xe8, 0x3e, 0xcc, 0x78, 0x12, 0xdb, 0x02, 0x47, 0xeb, 0x2d, 0x0d, 0x2d, 0xdd, 0x22, 0x4e, 0x48, 0x64, 0xfa, 0xcb, 0x62, 0xa1, 0x87, 0x50, 0xf2, 0x24, 0xb6, 0x05, 0x8e, 0xd6, 0xbf, 0x34, 0xb4,
0xc4, 0x1d, 0xb5, 0x87, 0xe5, 0xfa, 0xae, 0xdf, 0xeb, 0xa9, 0x8b, 0x11, 0x04, 0x7a, 0x0c, 0x95, 0x74, 0x8b, 0x38, 0x21, 0x11, 0x77, 0xd4, 0x1e, 0x96, 0xeb, 0x7b, 0x7e, 0xbf, 0xaf, 0x2e, 0x46,
0x2e, 0xa6, 0xae, 0x3f, 0xc0, 0x5d, 0x0e, 0x68, 0x91, 0xc7, 0xef, 0xbb, 0x27, 0x6a, 0xd6, 0x64, 0x10, 0xe8, 0x29, 0x54, 0x7b, 0x98, 0xba, 0xfe, 0x10, 0xf7, 0x38, 0xa0, 0x45, 0x1e, 0xbf, 0xff,
0x45, 0xb9, 0x33, 0xb6, 0xb3, 0x54, 0x73, 0xe0, 0xc6, 0xba, 0x54, 0x63, 0x46, 0xa4, 0x9a, 0xb1, 0x3d, 0x55, 0xb3, 0x26, 0x2b, 0xca, 0x9d, 0xb1, 0x9d, 0xa5, 0x9a, 0x43, 0x37, 0xd6, 0xa5, 0x9a,
0xe5, 0xe6, 0xe7, 0x30, 0x37, 0xa1, 0x2c, 0xa3, 0x42, 0xdd, 0xd6, 0x2b, 0x94, 0xf9, 0xb0, 0xf4, 0x25, 0x91, 0x6a, 0x26, 0x96, 0x5b, 0x1f, 0xc3, 0xfc, 0x94, 0xb2, 0x8c, 0x0a, 0x75, 0x57, 0xaf,
0x00, 0xd1, 0x4b, 0xd7, 0x7d, 0xf1, 0x28, 0x24, 0x00, 0xa8, 0x0e, 0x95, 0xf6, 0xce, 0xd6, 0xd6, 0x50, 0xe6, 0xc3, 0xd2, 0x03, 0x44, 0x2f, 0x5d, 0x0f, 0xc5, 0xa3, 0x90, 0x00, 0xa0, 0x06, 0x54,
0xf3, 0x67, 0xbb, 0x0f, 0x77, 0x9f, 0x7c, 0xb6, 0x5b, 0x9f, 0x42, 0x55, 0x28, 0xf1, 0x95, 0xdd, 0x3b, 0xbb, 0xdb, 0xdb, 0x2f, 0x5f, 0xec, 0x3d, 0xde, 0x7b, 0xf6, 0xd1, 0x5e, 0x63, 0x06, 0xd5,
0x27, 0xbb, 0x2c, 0x20, 0x14, 0xb9, 0xff, 0xe4, 0x71, 0xa7, 0x9e, 0xb3, 0xbf, 0xb7, 0xa0, 0xba, 0xa0, 0xcc, 0x57, 0xf6, 0x9e, 0xed, 0xb1, 0x80, 0x50, 0xe4, 0xc1, 0xb3, 0xa7, 0xdd, 0x46, 0xce,
0x49, 0xb0, 0x4b, 0xf1, 0xc9, 0xd9, 0xe8, 0x03, 0x00, 0xf9, 0x38, 0x7d, 0x7c, 0x66, 0x4e, 0xd2, 0xfe, 0xda, 0x82, 0xda, 0x16, 0xc1, 0x2e, 0xc5, 0xa7, 0x67, 0xa3, 0x77, 0x00, 0xe4, 0xe3, 0xf4,
0x44, 0x59, 0x3c, 0x50, 0x7f, 0x88, 0xc3, 0x84, 0xf2, 0x9b, 0xb6, 0x1c, 0x45, 0x32, 0x4e, 0x24, 0xf1, 0xb9, 0x39, 0x49, 0x13, 0x65, 0xf1, 0x40, 0xfd, 0x11, 0x0e, 0x13, 0xca, 0x6f, 0xda, 0x72,
0x8b, 0xa5, 0x28, 0xe8, 0x8a, 0xb4, 0xbf, 0x80, 0x9a, 0xb2, 0x47, 0x46, 0xdc, 0xf8, 0x3b, 0xbf, 0x14, 0xc9, 0x38, 0x91, 0x2c, 0x96, 0xa2, 0xa0, 0x2b, 0xd2, 0xfe, 0x04, 0xea, 0xca, 0x1e, 0x19,
0xac, 0x39, 0xf6, 0x8f, 0x16, 0x94, 0x1d, 0xec, 0x76, 0xcf, 0x9f, 0x40, 0xcc, 0xa3, 0xf2, 0xe7, 0x71, 0x93, 0xef, 0xfc, 0xaa, 0xe6, 0xd8, 0xdf, 0x5a, 0x50, 0x71, 0xb0, 0xdb, 0xbb, 0x78, 0x02,
0xf7, 0xfc, 0x38, 0xab, 0x16, 0xce, 0x95, 0x55, 0xed, 0x6f, 0x2d, 0xa8, 0x08, 0xdb, 0x5e, 0xb3, 0x31, 0x8f, 0xca, 0x5f, 0xdc, 0xf3, 0x93, 0xac, 0x5a, 0xb8, 0x50, 0x56, 0xb5, 0xbf, 0xb4, 0xa0,
0xd7, 0x9a, 0x29, 0xf9, 0xf3, 0x99, 0xf2, 0xa7, 0x05, 0xd5, 0x67, 0x51, 0x57, 0x0b, 0x89, 0xff, 0x2a, 0x6c, 0x7b, 0xcb, 0x5e, 0x6b, 0xa6, 0xe4, 0x2f, 0x66, 0xca, 0x6f, 0x16, 0xd4, 0x5e, 0x44,
0x33, 0xd3, 0x6a, 0x31, 0x34, 0x6d, 0xc6, 0xd0, 0x44, 0x0e, 0x2e, 0x66, 0xe4, 0x60, 0x3d, 0xd2, 0x3d, 0x2d, 0x24, 0xfe, 0xce, 0x4c, 0xab, 0xc5, 0xd0, 0xac, 0x19, 0x43, 0x53, 0x39, 0xb8, 0x98,
0x66, 0xcc, 0x48, 0xdb, 0x81, 0x9a, 0x72, 0x53, 0x62, 0x6e, 0x62, 0x6c, 0x9d, 0x3f, 0xb2, 0xbe, 0x91, 0x83, 0xf5, 0x48, 0x2b, 0x99, 0x91, 0xb6, 0x0b, 0x75, 0xe5, 0xa6, 0xc4, 0xdc, 0xc4, 0xd8,
0xb1, 0xa0, 0xda, 0xe6, 0x49, 0xec, 0x3f, 0x88, 0x2d, 0x0d, 0x91, 0x82, 0x81, 0x88, 0xfd, 0x77, 0xba, 0x78, 0x64, 0x7d, 0x61, 0x41, 0xad, 0xc3, 0x93, 0xd8, 0x5f, 0x10, 0x5b, 0x1a, 0x22, 0x05,
0x91, 0x37, 0xf8, 0x62, 0x9e, 0xd0, 0x86, 0x87, 0x88, 0x84, 0x5f, 0x62, 0x8f, 0x4a, 0x73, 0x14, 0x03, 0x11, 0xfb, 0xbb, 0x12, 0x6f, 0xf0, 0xc5, 0x3c, 0xa1, 0x0d, 0x0f, 0x11, 0x09, 0x3f, 0xc5,
0xc9, 0x72, 0x64, 0x4c, 0x5d, 0xef, 0x50, 0xf5, 0xc3, 0x9c, 0x40, 0x0f, 0xa0, 0xe8, 0xf1, 0xfe, 0x1e, 0x95, 0xe6, 0x28, 0x92, 0xe5, 0xc8, 0x98, 0xba, 0xde, 0x91, 0xea, 0x87, 0x39, 0x81, 0x1e,
0xb1, 0x91, 0xe7, 0xd9, 0xf1, 0x1d, 0xb3, 0xb1, 0x34, 0x94, 0xcb, 0x4e, 0x53, 0xe4, 0x46, 0xb9, 0x41, 0xd1, 0xe3, 0xfd, 0x63, 0x33, 0xcf, 0xb3, 0xe3, 0x7f, 0xcc, 0xc6, 0xd2, 0x50, 0x2e, 0x3b,
0x8d, 0xd5, 0xef, 0x2e, 0x39, 0x72, 0x92, 0x40, 0x3e, 0x6d, 0x49, 0xf1, 0x9a, 0xef, 0x12, 0x77, 0x4d, 0x91, 0x1b, 0xe5, 0x36, 0x56, 0xbf, 0x7b, 0xe4, 0xd8, 0x49, 0x02, 0xf9, 0xb4, 0x25, 0xc5,
0x30, 0xc0, 0x03, 0x7e, 0x95, 0xd3, 0x4e, 0x4a, 0xb3, 0x4c, 0x3a, 0x0c, 0x03, 0x9f, 0x86, 0xa4, 0x6b, 0xbe, 0x4b, 0xdc, 0xe1, 0x10, 0x0f, 0xf9, 0x55, 0xce, 0x3a, 0x29, 0xcd, 0x32, 0xe9, 0x28,
0x13, 0x74, 0xa3, 0xd0, 0x0f, 0x68, 0xa3, 0xc8, 0x8d, 0x1a, 0x5f, 0x66, 0xbd, 0x29, 0x3d, 0x8a, 0x0c, 0x7c, 0x1a, 0x92, 0x6e, 0xd0, 0x8b, 0x42, 0x3f, 0xa0, 0xcd, 0x22, 0x37, 0x6a, 0x72, 0x99,
0x30, 0xbf, 0xcc, 0x92, 0xc3, 0xbf, 0xd3, 0x7e, 0x75, 0x56, 0xeb, 0x57, 0xe7, 0xa1, 0x18, 0xb9, 0xf5, 0xa6, 0xf4, 0x38, 0xc2, 0xfc, 0x32, 0xcb, 0x0e, 0xff, 0x4e, 0xfb, 0xd5, 0x39, 0xad, 0x5f,
0x04, 0x07, 0xb4, 0x51, 0x12, 0x5d, 0x84, 0xa0, 0xb4, 0xe7, 0x00, 0xe7, 0xeb, 0x77, 0x5e, 0xc0, 0x5d, 0x80, 0x62, 0xe4, 0x12, 0x1c, 0xd0, 0x66, 0x59, 0x74, 0x11, 0x82, 0xd2, 0x9e, 0x03, 0x5c,
0x9c, 0x28, 0xb8, 0x38, 0xc2, 0x41, 0x17, 0x07, 0x1e, 0xbb, 0xae, 0x32, 0x87, 0x66, 0xf5, 0x34, 0xac, 0xdf, 0x79, 0x05, 0xf3, 0xa2, 0xe0, 0xe2, 0x08, 0x07, 0x3d, 0x1c, 0x78, 0xec, 0xba, 0x2a,
0x68, 0x76, 0xc6, 0x37, 0x09, 0x94, 0x26, 0x95, 0xc9, 0x1b, 0xa2, 0xec, 0x86, 0x2a, 0x2a, 0x44, 0x1c, 0x9a, 0xb5, 0xb3, 0xa0, 0xd9, 0x9d, 0xdc, 0x24, 0x50, 0x9a, 0x56, 0x26, 0x6f, 0x88, 0xb2,
0x39, 0xc9, 0x86, 0x33, 0xd5, 0xf1, 0xc6, 0x8d, 0x6a, 0xd6, 0x70, 0x66, 0x9e, 0xb9, 0xa7, 0x84, 0x1b, 0xaa, 0xaa, 0x10, 0xe5, 0x24, 0x1b, 0xce, 0x54, 0xc7, 0x1b, 0x37, 0x6b, 0x59, 0xc3, 0x99,
0xe5, 0x70, 0x96, 0x6e, 0x66, 0x67, 0xb8, 0x03, 0xdf, 0x8d, 0x71, 0xdc, 0xa8, 0x89, 0xd2, 0x2c, 0x79, 0xe6, 0xbe, 0x12, 0x96, 0xc3, 0x59, 0xba, 0x99, 0x9d, 0xe1, 0x0e, 0x7d, 0x37, 0xc6, 0x71,
0x49, 0x64, 0xb3, 0x9a, 0xa8, 0xb9, 0x76, 0x85, 0xb3, 0x8d, 0xb5, 0xe6, 0x4d, 0xb8, 0x9a, 0xd6, 0xb3, 0x2e, 0x4a, 0xb3, 0x24, 0x91, 0xcd, 0x6a, 0xa2, 0xe6, 0xda, 0x35, 0xce, 0x36, 0xd6, 0xd0,
0x1f, 0xdd, 0x72, 0x04, 0x85, 0x84, 0x04, 0xaa, 0x11, 0xe0, 0xdf, 0xcd, 0xbb, 0x50, 0xd6, 0xa2, 0x6d, 0x68, 0x88, 0xcb, 0x15, 0x43, 0x0f, 0x1f, 0x3b, 0x1a, 0x5c, 0x6e, 0x6a, 0xbd, 0x75, 0x1b,
0xe2, 0x22, 0x63, 0x58, 0x73, 0x04, 0xf3, 0xd9, 0xa8, 0x65, 0x68, 0xd9, 0x32, 0x4b, 0xe5, 0xca, 0xae, 0xa7, 0xb5, 0x4a, 0xd7, 0x81, 0xa0, 0x90, 0x90, 0x40, 0x35, 0x0d, 0xfc, 0xbb, 0x75, 0x1f,
0x19, 0xb0, 0x4c, 0xd8, 0xae, 0x9f, 0xbb, 0x06, 0x35, 0x13, 0xb9, 0x0b, 0x0d, 0x8f, 0xbf, 0xe7, 0x2a, 0x5a, 0x04, 0x5d, 0x66, 0x64, 0x6b, 0x8d, 0x61, 0x21, 0x1b, 0xe1, 0x0c, 0x2d, 0xdb, 0x66,
0xf8, 0xf0, 0xa8, 0x8e, 0x94, 0xb9, 0x64, 0xb2, 0x8c, 0xde, 0xe6, 0xcf, 0x8d, 0xe2, 0xb3, 0x92, 0x59, 0x5d, 0x3d, 0x07, 0xc2, 0x29, 0xdb, 0xf5, 0x73, 0xd7, 0xa1, 0x6e, 0xa2, 0x7c, 0xa9, 0x41,
0xb7, 0x90, 0x42, 0x2e, 0xcc, 0xf1, 0x0f, 0x23, 0xee, 0xc4, 0x93, 0xbc, 0x93, 0xed, 0xac, 0xec, 0xf3, 0x97, 0x1c, 0x1f, 0x34, 0xd5, 0x91, 0x32, 0xef, 0x4c, 0x97, 0xdc, 0xbb, 0xfc, 0x69, 0x52,
0x5a, 0xf6, 0xc7, 0x77, 0xc9, 0xc0, 0x9b, 0xd0, 0x76, 0xa1, 0x6b, 0x7d, 0x05, 0xf3, 0xd9, 0x8a, 0x7c, 0x5e, 0xa2, 0x17, 0x52, 0xc8, 0x85, 0x79, 0xfe, 0x61, 0xc4, 0xa8, 0x78, 0xbe, 0xf7, 0xb2,
0x33, 0xb0, 0xda, 0x36, 0xef, 0xe6, 0xfd, 0x53, 0xcd, 0x3d, 0xe3, 0x72, 0xec, 0x9f, 0x2c, 0xb8, 0x9d, 0x95, 0x1d, 0xce, 0xc1, 0xe4, 0x2e, 0x19, 0xa4, 0x53, 0xda, 0x2e, 0x75, 0xad, 0x6f, 0x60,
0xc6, 0xe7, 0x58, 0x35, 0xb8, 0xed, 0x04, 0x3e, 0xdd, 0xe2, 0xad, 0xd4, 0xeb, 0x2b, 0x92, 0x0d, 0x21, 0x5b, 0x71, 0x06, 0x56, 0x3b, 0xe6, 0xdd, 0xfc, 0xff, 0x4c, 0x73, 0xcf, 0xb9, 0x1c, 0xfb,
0x98, 0x11, 0x53, 0x86, 0x80, 0xb8, 0xe4, 0x28, 0xf2, 0xc2, 0x95, 0x7c, 0xf5, 0xaf, 0x19, 0xa8, 0x7b, 0x0b, 0x6e, 0xf0, 0x99, 0x57, 0x0d, 0x79, 0xbb, 0x81, 0x4f, 0xb7, 0x79, 0xdb, 0xf5, 0xf6,
0x2b, 0x53, 0x55, 0x54, 0xb1, 0x87, 0x9c, 0xfe, 0xa7, 0x41, 0x37, 0x34, 0x3c, 0xc6, 0xff, 0xf5, 0x0a, 0x6a, 0x13, 0x4a, 0x62, 0x22, 0x11, 0x10, 0x97, 0x1d, 0x45, 0x5e, 0xba, 0xea, 0xaf, 0xfd,
0x34, 0x17, 0xb2, 0x99, 0x02, 0x2c, 0x7b, 0x0a, 0x6d, 0x40, 0x99, 0x4f, 0x52, 0xe2, 0x8d, 0xa1, 0x5e, 0x82, 0x86, 0x32, 0x55, 0x45, 0x15, 0x7b, 0xf4, 0xe9, 0x3f, 0x1d, 0x74, 0x4b, 0xc3, 0x63,
0x89, 0xd9, 0x4b, 0xe9, 0x69, 0x4c, 0x32, 0x52, 0x1d, 0x0f, 0x00, 0x78, 0xcf, 0x28, 0xf3, 0xf5, 0xf2, 0xbf, 0x50, 0x6b, 0x31, 0x9b, 0x29, 0xc0, 0xb2, 0x67, 0xd0, 0x26, 0x54, 0xf8, 0xd4, 0x25,
0x44, 0xfb, 0x2b, 0x34, 0x5c, 0x3b, 0xa1, 0x2d, 0xb6, 0xa7, 0x98, 0x3b, 0xe9, 0x3f, 0x06, 0xc3, 0xde, 0x18, 0x9a, 0x9a, 0xd3, 0x94, 0x9e, 0xe6, 0x34, 0x23, 0xd5, 0xf1, 0x08, 0x80, 0xf7, 0x97,
0x9d, 0xf1, 0xdf, 0x45, 0x86, 0x3b, 0x13, 0x7f, 0x58, 0xb8, 0x29, 0x45, 0x31, 0x83, 0x23, 0xdd, 0x32, 0xb7, 0x4f, 0xb5, 0xca, 0x42, 0xc3, 0x8d, 0x53, 0x5a, 0x68, 0x7b, 0x86, 0xb9, 0x93, 0xfe,
0x60, 0xe3, 0x37, 0x42, 0xf3, 0x7a, 0x06, 0x27, 0x55, 0xb0, 0x0d, 0x95, 0x7d, 0x4a, 0xb0, 0x3b, 0x8f, 0x30, 0xdc, 0x99, 0xfc, 0xb5, 0x64, 0xb8, 0x33, 0xf5, 0x37, 0x86, 0x9b, 0x52, 0x14, 0xf3,
0xfc, 0x57, 0x6a, 0x56, 0x2c, 0xb4, 0x06, 0xd3, 0x1c, 0xa7, 0xcb, 0x41, 0x7a, 0x17, 0x0a, 0x7c, 0x3a, 0xd2, 0x0d, 0x36, 0x7e, 0x39, 0xb4, 0x6e, 0x66, 0x70, 0x52, 0x05, 0x3b, 0x50, 0x3d, 0xa0,
0x24, 0xb8, 0x04, 0x98, 0x0f, 0xa0, 0x28, 0x3a, 0x5e, 0xc3, 0x76, 0xa3, 0x29, 0x37, 0x6c, 0x37, 0x04, 0xbb, 0xa3, 0x3f, 0xa5, 0x66, 0xd5, 0x42, 0xeb, 0x30, 0xcb, 0x71, 0xba, 0x1a, 0xa4, 0xf7,
0xdb, 0x63, 0x71, 0x36, 0x6b, 0x1d, 0x8d, 0xb3, 0xb5, 0x3e, 0xd7, 0x38, 0x5b, 0xef, 0x31, 0xc5, 0xa1, 0xc0, 0xc7, 0x87, 0x2b, 0x80, 0xf9, 0x08, 0x8a, 0xa2, 0x3b, 0x36, 0x6c, 0x37, 0x1a, 0x78,
0xd9, 0xa2, 0x07, 0x32, 0xce, 0x36, 0xba, 0x3f, 0xe3, 0x6c, 0xb3, 0x61, 0xb2, 0xa7, 0xd0, 0x1a, 0xc3, 0x76, 0xb3, 0x95, 0x16, 0x67, 0xb3, 0x36, 0xd3, 0x38, 0x5b, 0xeb, 0x89, 0x8d, 0xb3, 0xf5,
0x14, 0x45, 0xe3, 0x63, 0x28, 0x30, 0x7a, 0xa1, 0xe6, 0xfc, 0xc4, 0x93, 0xe9, 0x0c, 0x23, 0x7a, 0x7e, 0x54, 0x9c, 0x2d, 0xfa, 0x25, 0xe3, 0x6c, 0xa3, 0x53, 0x34, 0xce, 0x36, 0x9b, 0x2b, 0x7b,
0x94, 0xc6, 0x91, 0x48, 0x08, 0xe3, 0x71, 0x64, 0xa4, 0xf0, 0xf1, 0x38, 0x32, 0x73, 0x88, 0x3d, 0x06, 0xad, 0x43, 0x51, 0x34, 0x49, 0x86, 0x02, 0xa3, 0x6f, 0x6a, 0x2d, 0x4c, 0x3d, 0x99, 0xee,
0x85, 0xee, 0x41, 0x71, 0xd3, 0x0d, 0x3c, 0x3c, 0x40, 0x27, 0x9c, 0x76, 0x8a, 0x15, 0x1f, 0x41, 0x28, 0xa2, 0xc7, 0x69, 0x1c, 0x89, 0x84, 0x30, 0x19, 0x47, 0x46, 0x0a, 0x9f, 0x8c, 0x23, 0x33,
0x75, 0x1b, 0xd3, 0x3d, 0xfe, 0x03, 0x77, 0x27, 0xe8, 0x85, 0x27, 0xaa, 0x78, 0x53, 0x9f, 0xc7, 0x87, 0xd8, 0x33, 0xe8, 0x01, 0x14, 0xb7, 0xdc, 0xc0, 0xc3, 0x43, 0x74, 0xca, 0x69, 0x67, 0x58,
0x52, 0x71, 0x7b, 0xea, 0x65, 0x91, 0x0b, 0xde, 0xf9, 0x27, 0x00, 0x00, 0xff, 0xff, 0xac, 0xa3, 0xf1, 0x1e, 0xd4, 0x76, 0x30, 0xdd, 0xe7, 0x3f, 0x7b, 0x77, 0x83, 0x7e, 0x78, 0xaa, 0x8a, 0x7f,
0xd1, 0x1f, 0x21, 0x16, 0x00, 0x00, 0xea, 0xb3, 0x5b, 0x2a, 0x6e, 0xcf, 0xbc, 0x2e, 0x72, 0xc1, 0x7b, 0x7f, 0x04, 0x00, 0x00, 0xff,
0xff, 0x02, 0x31, 0x0a, 0x9b, 0x4d, 0x16, 0x00, 0x00,
} }
// Reference imports to suppress errors if they are not otherwise used. // Reference imports to suppress errors if they are not otherwise used.

View file

@ -269,6 +269,7 @@ message ConstructRequest {
map<string, string> providers = 13; // the map of providers to use for this resource's children. map<string, string> providers = 13; // the map of providers to use for this resource's children.
repeated string aliases = 14; // a list of additional URNs that shoud be considered the same. repeated string aliases = 14; // a list of additional URNs that shoud be considered the same.
repeated string dependencies = 15; // a list of URNs that this resource depends on, as observed by the language host. repeated string dependencies = 15; // a list of URNs that this resource depends on, as observed by the language host.
repeated string configSecretKeys = 16; // the configuration keys that have secret values.
} }
message ConstructResponse { message ConstructResponse {

View file

@ -70,7 +70,7 @@ class ProviderServicer(ResourceProviderServicer):
monitor_address=_empty_as_none(request.monitorEndpoint), monitor_address=_empty_as_none(request.monitorEndpoint),
preview=request.dryRun) preview=request.dryRun)
pulumi.runtime.config.set_all_config(dict(request.config)) pulumi.runtime.config.set_all_config(dict(request.config), request.configSecretKeys)
inputs = self._construct_inputs(request) inputs = self._construct_inputs(request)

File diff suppressed because one or more lines are too long

View file

@ -41,6 +41,7 @@ class ConstructRequest:
providers: Dict[str, str] providers: Dict[str, str]
aliases: List[str] aliases: List[str]
dependencies: List[str] dependencies: List[str]
configSecretKeys: List[str]
class ConstructResponse: class ConstructResponse:

View file

@ -16,6 +16,9 @@ class Component : Pulumi.ComponentResource
[Output("childId")] [Output("childId")]
public Output<string> ChildId { get; private set; } = null!; public Output<string> ChildId { get; private set; } = null!;
[Output("secret")]
public Output<string> Secret { get; private set; } = null!;
public Component(string name, ComponentArgs args, ComponentResourceOptions opts = null) public Component(string name, ComponentArgs args, ComponentResourceOptions opts = null)
: base("testcomponent:index:Component", name, args, opts, remote: true) : base("testcomponent:index:Component", name, args, opts, remote: true)
{ {

View file

@ -25,6 +25,7 @@ type Component struct {
Echo pulumi.AnyOutput `pulumi:"echo"` Echo pulumi.AnyOutput `pulumi:"echo"`
ChildID pulumi.StringOutput `pulumi:"childId"` ChildID pulumi.StringOutput `pulumi:"childId"`
Secret pulumi.StringOutput `pulumi:"secret"`
} }
func NewComponent( func NewComponent(

View file

@ -14,6 +14,7 @@ export class Component extends pulumi.ComponentResource {
const inputs: any = {}; const inputs: any = {};
inputs["echo"] = args.echo; inputs["echo"] = args.echo;
inputs["childId"] = undefined /*out*/; inputs["childId"] = undefined /*out*/;
inputs["secret"] = undefined /*out*/;
super("testcomponent:index:Component", name, inputs, opts, true); super("testcomponent:index:Component", name, inputs, opts, true);
} }

View file

@ -12,4 +12,5 @@ class Component(pulumi.ComponentResource):
props = dict() props = dict()
props["echo"] = echo props["echo"] = echo
props["childId"] = None props["childId"] = None
props["secret"] = None
super().__init__("testcomponent:index:Component", name, props, opts, True) super().__init__("testcomponent:index:Component", name, props, opts, True)

View file

@ -13,6 +13,7 @@ import (
"github.com/pulumi/pulumi/sdk/v3/go/common/resource" "github.com/pulumi/pulumi/sdk/v3/go/common/resource"
"github.com/pulumi/pulumi/sdk/v3/go/common/util/cmdutil" "github.com/pulumi/pulumi/sdk/v3/go/common/util/cmdutil"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi" "github.com/pulumi/pulumi/sdk/v3/go/pulumi"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi/config"
pulumiprovider "github.com/pulumi/pulumi/sdk/v3/go/pulumi/provider" pulumiprovider "github.com/pulumi/pulumi/sdk/v3/go/pulumi/provider"
pulumirpc "github.com/pulumi/pulumi/sdk/v3/proto/go" pulumirpc "github.com/pulumi/pulumi/sdk/v3/proto/go"
@ -49,8 +50,9 @@ func NewResource(ctx *pulumi.Context, name string, echo pulumi.Input,
type Component struct { type Component struct {
pulumi.ResourceState pulumi.ResourceState
Echo pulumi.Input `pulumi:"echo"` Echo pulumi.Input `pulumi:"echo"`
ChildID pulumi.IDOutput `pulumi:"childId"` ChildID pulumi.IDOutput `pulumi:"childId"`
Secret pulumi.StringOutput `pulumi:"secret"`
} }
type ComponentArgs struct { type ComponentArgs struct {
@ -63,6 +65,15 @@ func NewComponent(ctx *pulumi.Context, name string, args *ComponentArgs,
return nil, errors.New("args is required") return nil, errors.New("args is required")
} }
secretKey := "secret"
fullSecretKey := fmt.Sprintf("%s:%s", ctx.Project(), secretKey)
if !ctx.IsConfigSecret(fullSecretKey) {
return nil, errors.Errorf("expected configuration key to be secret: %s", fullSecretKey)
}
conf := config.New(ctx, "")
secret := conf.RequireSecret(secretKey)
component := &Component{} component := &Component{}
err := ctx.RegisterComponentResource("testcomponent:index:Component", name, component, opts...) err := ctx.RegisterComponentResource("testcomponent:index:Component", name, component, opts...)
if err != nil { if err != nil {
@ -76,8 +87,13 @@ func NewComponent(ctx *pulumi.Context, name string, args *ComponentArgs,
component.Echo = args.Echo component.Echo = args.Echo
component.ChildID = res.ID() component.ChildID = res.ID()
component.Secret = secret
if err := ctx.RegisterResourceOutputs(component, pulumi.Map{}); err != nil { if err := ctx.RegisterResourceOutputs(component, pulumi.Map{
"secret": component.Secret,
"echo": component.Echo,
"childId": component.ChildID,
}); err != nil {
return nil, err return nil, err
} }

View file

@ -18,6 +18,7 @@ import sys
from pulumi import Input, Inputs, ComponentResource, ResourceOptions from pulumi import Input, Inputs, ComponentResource, ResourceOptions
import pulumi import pulumi
import pulumi.dynamic as dynamic import pulumi.dynamic as dynamic
import pulumi.runtime.config as config
import pulumi.provider as provider import pulumi.provider as provider
@ -38,11 +39,17 @@ class Resource(dynamic.Resource):
class Component(ComponentResource): class Component(ComponentResource):
def __init__(self, name: str, echo: Input[any], opts: Optional[ResourceOptions]=None): def __init__(self, name: str, echo: Input[any], secret: Input[str], opts: Optional[ResourceOptions]=None):
super().__init__('testcomponent:index:Component', name, {}, opts) super().__init__('testcomponent:index:Component', name, {}, opts)
self.echo = pulumi.Output.from_input(echo) self.echo = pulumi.Output.from_input(echo)
resource = Resource('child-{}'.format(name), echo, ResourceOptions(parent=self)) resource = Resource('child-{}'.format(name), echo, ResourceOptions(parent=self))
self.child_id = resource.id self.child_id = resource.id
self.secret = secret
self.register_outputs({
'childId': self.child_id,
'echo': self.echo,
'secret': self.secret
})
class Provider(provider.Provider): class Provider(provider.Provider):
@ -56,14 +63,22 @@ class Provider(provider.Provider):
if resource_type != 'testcomponent:index:Component': if resource_type != 'testcomponent:index:Component':
raise Exception('unknown resource type {}'.format(resource_type)) raise Exception('unknown resource type {}'.format(resource_type))
component = Component(name, inputs['echo'], options) secret_key = "secret"
cfg = pulumi.Config()
full_secret_key = cfg.full_key(secret_key)
if not config.is_config_secret(full_secret_key):
raise Exception('expected config for key to be secret: {}'.format(full_secret_key))
secret = cfg.require_secret('secret')
component = Component(name, inputs['echo'], secret, options)
return provider.ConstructResult( return provider.ConstructResult(
urn=component.urn, urn=component.urn,
state={ state={
'echo': component.echo, 'echo': component.echo,
'childId': component.child_id 'childId': component.child_id,
'secret': component.secret
}) })

View file

@ -20,12 +20,20 @@ class Resource extends dynamic.Resource {
class Component extends pulumi.ComponentResource { class Component extends pulumi.ComponentResource {
public readonly echo: pulumi.Output<any>; public readonly echo: pulumi.Output<any>;
public readonly childId: pulumi.Output<pulumi.ID>; public readonly childId: pulumi.Output<pulumi.ID>;
public readonly secret: pulumi.Output<string>;
constructor(name: string, echo: pulumi.Input<any>, opts?: pulumi.ComponentResourceOptions) { constructor(name: string, echo: pulumi.Input<any>, secret: pulumi.Output<string>, opts?: pulumi.ComponentResourceOptions) {
super("testcomponent:index:Component", name, {}, opts); super("testcomponent:index:Component", name, {}, opts);
this.echo = pulumi.output(echo); this.echo = pulumi.output(echo);
this.childId = (new Resource(`child-${name}`, echo, {parent: this})).id; this.childId = (new Resource(`child-${name}`, echo, {parent: this})).id;
this.secret = secret;
this.registerOutputs({
echo: this.echo,
childId: this.childId,
secret: this.secret,
})
} }
} }
@ -38,12 +46,24 @@ class Provider implements provider.Provider {
throw new Error(`unknown resource type ${type}`); throw new Error(`unknown resource type ${type}`);
} }
const component = new Component(name, inputs["echo"], options); const config = new pulumi.Config();
const secretKey = "secret";
const fullSecretKey = `${config.name}:${secretKey}`;
// use internal pulumi prop to check secretness
const isSecret = (pulumi.runtime as any).isConfigSecret(fullSecretKey);
if (!isSecret) {
throw new Error(`expected config with key "${secretKey}" to be secret.`)
}
const secret = config.requireSecret(secretKey);
const component = new Component(name, inputs["echo"], secret, options);
return Promise.resolve({ return Promise.resolve({
urn: component.urn, urn: component.urn,
state: { state: {
echo: component.echo, echo: component.echo,
childId: component.childId, childId: component.childId,
secret: secret,
}, },
}); });
} }

View file

@ -359,8 +359,11 @@ func optsForConstructDotnet(t *testing.T, expectedResourceCount int, env ...stri
Env: env, Env: env,
Dir: filepath.Join("construct_component", "dotnet"), Dir: filepath.Join("construct_component", "dotnet"),
Dependencies: []string{"Pulumi"}, Dependencies: []string{"Pulumi"},
Quick: true, Secrets: map[string]string{
NoParallel: true, // avoid contention for Dir "secret": "this super secret is encrypted",
},
Quick: true,
NoParallel: true, // avoid contention for Dir
ExtraRuntimeValidation: func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) { ExtraRuntimeValidation: func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) {
assert.NotNil(t, stackInfo.Deployment) assert.NotNil(t, stackInfo.Deployment)
if assert.Equal(t, expectedResourceCount, len(stackInfo.Deployment.Resources)) { if assert.Equal(t, expectedResourceCount, len(stackInfo.Deployment.Resources)) {
@ -383,6 +386,10 @@ func optsForConstructDotnet(t *testing.T, expectedResourceCount int, env ...stri
} }
case "child-c": case "child-c":
assert.Equal(t, []resource.URN{urns["child-a"]}, res.PropertyDependencies["echo"]) assert.Equal(t, []resource.URN{urns["child-a"]}, res.PropertyDependencies["echo"])
case "a", "b", "c":
secretPropValue, ok := res.Outputs["secret"].(map[string]interface{})
assert.Truef(t, ok, "secret output was not serialized as a secret")
assert.Equal(t, resource.SecretSig, secretPropValue[resource.SigKey].(string))
} }
} }
} }

View file

@ -448,6 +448,9 @@ func optsForConstructGo(t *testing.T, expectedResourceCount int, env ...string)
Dependencies: []string{ Dependencies: []string{
"github.com/pulumi/pulumi/sdk/v3", "github.com/pulumi/pulumi/sdk/v3",
}, },
Secrets: map[string]string{
"secret": "this super secret is encrypted",
},
Quick: true, Quick: true,
NoParallel: true, // avoid contention for Dir NoParallel: true, // avoid contention for Dir
ExtraRuntimeValidation: func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) { ExtraRuntimeValidation: func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) {
@ -475,6 +478,10 @@ func optsForConstructGo(t *testing.T, expectedResourceCount int, env ...string)
case "child-c": case "child-c":
assert.ElementsMatch(t, []resource.URN{urns["child-a"], urns["a"]}, assert.ElementsMatch(t, []resource.URN{urns["child-a"], urns["a"]},
res.PropertyDependencies["echo"]) res.PropertyDependencies["echo"])
case "a", "b", "c":
secretPropValue, ok := res.Outputs["secret"].(map[string]interface{})
assert.Truef(t, ok, "secret output was not serialized as a secret")
assert.Equal(t, resource.SecretSig, secretPropValue[resource.SigKey].(string))
} }
} }
} }

View file

@ -887,8 +887,11 @@ func optsForConstructNode(t *testing.T, expectedResourceCount int, env ...string
Env: env, Env: env,
Dir: filepath.Join("construct_component", "nodejs"), Dir: filepath.Join("construct_component", "nodejs"),
Dependencies: []string{"@pulumi/pulumi"}, Dependencies: []string{"@pulumi/pulumi"},
Quick: true, Secrets: map[string]string{
NoParallel: true, "secret": "this super secret is encrypted",
},
Quick: true,
NoParallel: true,
ExtraRuntimeValidation: func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) { ExtraRuntimeValidation: func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) {
assert.NotNil(t, stackInfo.Deployment) assert.NotNil(t, stackInfo.Deployment)
if assert.Equal(t, expectedResourceCount, len(stackInfo.Deployment.Resources)) { if assert.Equal(t, expectedResourceCount, len(stackInfo.Deployment.Resources)) {
@ -911,6 +914,10 @@ func optsForConstructNode(t *testing.T, expectedResourceCount int, env ...string
} }
case "child-c": case "child-c":
assert.Equal(t, []resource.URN{urns["child-a"]}, res.PropertyDependencies["echo"]) assert.Equal(t, []resource.URN{urns["child-a"]}, res.PropertyDependencies["echo"])
case "a", "b", "c":
secretPropValue, ok := res.Outputs["secret"].(map[string]interface{})
assert.Truef(t, ok, "secret output was not serialized as a secret")
assert.Equal(t, resource.SecretSig, secretPropValue[resource.SigKey].(string))
} }
} }
} }

View file

@ -561,6 +561,9 @@ func optsForConstructPython(t *testing.T, expectedResourceCount int, env ...stri
Dependencies: []string{ Dependencies: []string{
filepath.Join("..", "..", "sdk", "python", "env", "src"), filepath.Join("..", "..", "sdk", "python", "env", "src"),
}, },
Secrets: map[string]string{
"secret": "this super secret is encrypted",
},
Quick: true, Quick: true,
NoParallel: true, // avoid contention for Dir NoParallel: true, // avoid contention for Dir
ExtraRuntimeValidation: func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) { ExtraRuntimeValidation: func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) {
@ -588,6 +591,10 @@ func optsForConstructPython(t *testing.T, expectedResourceCount int, env ...stri
case "child-c": case "child-c":
assert.ElementsMatch(t, []resource.URN{urns["child-a"], urns["a"]}, assert.ElementsMatch(t, []resource.URN{urns["child-a"], urns["a"]},
res.PropertyDependencies["echo"]) res.PropertyDependencies["echo"])
case "a", "b", "c":
secretPropValue, ok := res.Outputs["secret"].(map[string]interface{})
assert.Truef(t, ok, "secret output was not serialized as a secret")
assert.Equal(t, resource.SecretSig, secretPropValue[resource.SigKey].(string))
} }
} }
} }