Do not flow secrets from NodeJS SDK to older CLIs

When serializing values, if the other end of the resource monitor
interface does not support secrets (e.g. it is an older CLI), don't
pass secrets to it.
This commit is contained in:
Matt Ellis 2019-04-12 18:25:33 -07:00
parent 87bc7d443f
commit fab74d19c9
2 changed files with 34 additions and 3 deletions

View file

@ -17,7 +17,7 @@ import * as log from "../log";
import { Input, Inputs, Output } from "../output";
import { ComponentResource, CustomResource, Resource } from "../resource";
import { debuggablePromise, errorString } from "./debuggable";
import { excessiveDebugOutput, isDryRun } from "./settings";
import { excessiveDebugOutput, isDryRun, monitorSupportsSecrets } from "./settings";
const gstruct = require("google-protobuf/google/protobuf/struct_pb.js");
@ -290,8 +290,7 @@ export async function serializeProperty(ctx: string, prop: Input<any>, dependent
if (!isKnown) {
return unknownValue;
}
if (isSecret) {
// TODO(ellismg): We should only do this when we know the resource monitor can understand secrets
if (isSecret && await monitorSupportsSecrets()) {
return {
[specialSigKey]: specialSecretSig,
value: value,

View file

@ -21,6 +21,7 @@ import { debuggablePromise } from "./debuggable";
const engrpc = require("../proto/engine_grpc_pb.js");
const engproto = require("../proto/engine_pb.js");
const resrpc = require("../proto/resource_grpc_pb.js");
const resproto = require("../proto/resource_pb.js");
/**
* excessiveDebugOutput enables, well, pretty excessive debug output pertaining to resources and properties.
@ -349,3 +350,34 @@ export async function setRootResource(res: ComponentResource): Promise<void> {
});
});
}
/**
* monitorSupportsSecrets returns a promise that when resolved tells you if the resource monitor we are connected
* to is able to support secrets across it's RPC interface. When it does, we marshal outputs marked with the secret
* bit in a special way.
*/
export function monitorSupportsSecrets(): Promise<boolean> {
const monitorRef: any = getMonitor();
if (!monitorRef) {
return Promise.resolve(false);
}
const req = new resproto.SupportsFeatureRequest();
req.setId("secrets");
return new Promise<boolean>((resolve, reject) => {
monitorRef.supportsFeature(req, (err: grpc.ServiceError, resp: any) => {
// Back-compat case - if the monitor doesn't let us ask if it supports a feature, it doesn't support
// secrets.
if (err && err.code === grpc.status.UNIMPLEMENTED) {
return resolve(false);
}
if (err) {
return reject(err);
}
return resolve(resp.getHassupport());
});
});
}