No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

secrets.js 8.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.checkSpecForSecrets = exports.handleSecretParams = void 0;
  4. const clc = require("colorette");
  5. const secretUtils = require("../../extensions/secretsUtils");
  6. const secretManager = require("../../gcp/secretManager");
  7. const planner_1 = require("./planner");
  8. const askUserForParam_1 = require("../../extensions/askUserForParam");
  9. const types_1 = require("../../extensions/types");
  10. const error_1 = require("../../error");
  11. const logger_1 = require("../../logger");
  12. const utils_1 = require("../../utils");
  13. async function handleSecretParams(payload, have, nonInteractive) {
  14. var _a, _b, _c;
  15. for (const i of (_a = payload.instancesToCreate) !== null && _a !== void 0 ? _a : []) {
  16. if (await checkSpecForSecrets(i)) {
  17. (0, utils_1.logLabeledBullet)("extensions", `Verifying secret params for ${clc.bold(i.instanceId)}`);
  18. await handleSecretsCreateInstance(i, nonInteractive);
  19. }
  20. }
  21. const updates = [...((_b = payload.instancesToUpdate) !== null && _b !== void 0 ? _b : []), ...((_c = payload.instancesToConfigure) !== null && _c !== void 0 ? _c : [])];
  22. for (const i of updates) {
  23. if (await checkSpecForSecrets(i)) {
  24. (0, utils_1.logLabeledBullet)("extensions", `Verifying secret params for ${clc.bold(i.instanceId)}`);
  25. const previousSpec = have.find((h) => h.instanceId === i.instanceId);
  26. await handleSecretsUpdateInstance(i, previousSpec, nonInteractive);
  27. }
  28. }
  29. }
  30. exports.handleSecretParams = handleSecretParams;
  31. async function checkSpecForSecrets(i) {
  32. const extensionSpec = await (0, planner_1.getExtensionSpec)(i);
  33. return secretUtils.usesSecrets(extensionSpec);
  34. }
  35. exports.checkSpecForSecrets = checkSpecForSecrets;
  36. const secretsInSpec = (spec) => {
  37. return spec.params.filter((p) => p.type === types_1.ParamType.SECRET);
  38. };
  39. async function handleSecretsCreateInstance(i, nonInteractive) {
  40. const extensionVersion = await (0, planner_1.getExtensionVersion)(i);
  41. const secretParams = secretsInSpec(extensionVersion.spec);
  42. for (const s of secretParams) {
  43. await handleSecretParamForCreate(s, i, nonInteractive);
  44. }
  45. }
  46. async function handleSecretsUpdateInstance(i, prevSpec, nonInteractive) {
  47. const extensionVersion = await (0, planner_1.getExtensionVersion)(i);
  48. const prevExtensionVersion = await (0, planner_1.getExtensionVersion)(prevSpec);
  49. const secretParams = secretsInSpec(extensionVersion.spec);
  50. for (const s of secretParams) {
  51. const prevParam = prevExtensionVersion.spec.params.find((p) => p.param === s.param);
  52. if ((prevParam === null || prevParam === void 0 ? void 0 : prevParam.type) === types_1.ParamType.SECRET && prevSpec.params[prevParam === null || prevParam === void 0 ? void 0 : prevParam.param]) {
  53. await handleSecretParamForUpdate(s, i, prevSpec.params[prevParam === null || prevParam === void 0 ? void 0 : prevParam.param], nonInteractive);
  54. }
  55. else {
  56. await handleSecretParamForCreate(s, i, nonInteractive);
  57. }
  58. }
  59. }
  60. async function handleSecretParamForCreate(secretParam, i, nonInteractive) {
  61. var _a;
  62. const providedValue = i.params[secretParam.param];
  63. if (!providedValue) {
  64. return;
  65. }
  66. const [, projectId, , secretName, , version] = providedValue.split("/");
  67. if (!projectId || !secretName || !version) {
  68. throw new error_1.FirebaseError(`${clc.bold(i.instanceId)}: Found '${providedValue}' for secret param ${secretParam.param}, but expected a secret version.`);
  69. }
  70. const secretInfo = await getSecretInfo(projectId, secretName, version);
  71. if (!secretInfo.secret) {
  72. await promptForCreateSecret({
  73. projectId,
  74. secretName,
  75. instanceId: i.instanceId,
  76. secretParam,
  77. nonInteractive,
  78. });
  79. return;
  80. }
  81. else if (!secretInfo.secretVersion) {
  82. throw new error_1.FirebaseError(`${clc.bold(i.instanceId)}: Found '${providedValue}' for secret param ${secretParam.param}. ` +
  83. `projects/${projectId}/secrets/${secretName} exists, but version ${version} does not. ` +
  84. `See more information about this secret at ${secretManager.secretManagerConsoleUri(projectId)}`);
  85. }
  86. if (!!((_a = secretInfo === null || secretInfo === void 0 ? void 0 : secretInfo.secret) === null || _a === void 0 ? void 0 : _a.labels) &&
  87. !!(secretInfo === null || secretInfo === void 0 ? void 0 : secretInfo.secret.labels[secretUtils.SECRET_LABEL]) &&
  88. secretInfo.secret.labels[secretUtils.SECRET_LABEL] !== i.instanceId) {
  89. throw new error_1.FirebaseError(`${clc.bold(i.instanceId)}: Found '${providedValue}' for secret param ${secretParam.param}. ` +
  90. `projects/${projectId}/secrets/${secretName} is managed by a different extension instance (${secretInfo.secret.labels[secretUtils.SECRET_LABEL]}), so reusing it here can lead to unexpected behavior. ` +
  91. "Please choose a different name for this secret, and rerun this command.");
  92. }
  93. await secretUtils.grantFirexServiceAgentSecretAdminRole(secretInfo.secret);
  94. }
  95. async function handleSecretParamForUpdate(secretParam, i, prevValue, nonInteractive) {
  96. const providedValue = i.params[secretParam.param];
  97. if (!providedValue) {
  98. return;
  99. }
  100. const [, projectId, , secretName, , version] = providedValue.split("/");
  101. if (!projectId || !secretName || !version) {
  102. throw new error_1.FirebaseError(`${clc.bold(i.instanceId)}: Found '${providedValue}' for secret param ${secretParam.param}, but expected a secret version.`);
  103. }
  104. const [, prevProjectId, , prevSecretName] = prevValue.split("/");
  105. if (prevSecretName !== secretName) {
  106. throw new error_1.FirebaseError(`${clc.bold(i.instanceId)}: Found '${providedValue}' for secret param ${secretParam.param}, ` +
  107. `but this instance was previously using a different secret projects/${prevProjectId}/secrets/${prevSecretName}.\n` +
  108. `Changing secrets is not supported. If you want to change the value of this secret, ` +
  109. `use a new version of projects/${prevProjectId}/secrets/${prevSecretName}.` +
  110. `You can create a new version at ${secretManager.secretManagerConsoleUri(projectId)}`);
  111. }
  112. const secretInfo = await getSecretInfo(projectId, secretName, version);
  113. if (!secretInfo.secret) {
  114. i.params[secretParam.param] = await promptForCreateSecret({
  115. projectId,
  116. secretName,
  117. instanceId: i.instanceId,
  118. secretParam,
  119. nonInteractive,
  120. });
  121. return;
  122. }
  123. else if (!secretInfo.secretVersion) {
  124. throw new error_1.FirebaseError(`${clc.bold(i.instanceId)}: Found '${providedValue}' for secret param ${secretParam.param}. ` +
  125. `projects/${projectId}/secrets/${secretName} exists, but version ${version} does not. ` +
  126. `See more information about this secret at ${secretManager.secretManagerConsoleUri(projectId)}`);
  127. }
  128. i.params[secretParam.param] = secretManager.toSecretVersionResourceName(secretInfo.secretVersion);
  129. await secretUtils.grantFirexServiceAgentSecretAdminRole(secretInfo.secret);
  130. }
  131. async function getSecretInfo(projectId, secretName, version) {
  132. const secretInfo = {};
  133. try {
  134. secretInfo.secret = await secretManager.getSecret(projectId, secretName);
  135. secretInfo.secretVersion = await secretManager.getSecretVersion(projectId, secretName, version);
  136. }
  137. catch (err) {
  138. if (err.status !== 404) {
  139. throw err;
  140. }
  141. }
  142. return secretInfo;
  143. }
  144. async function promptForCreateSecret(args) {
  145. logger_1.logger.info(`${clc.bold(args.instanceId)}: Secret ${args.projectId}/${args.secretName} doesn't exist yet.`);
  146. if (args.nonInteractive) {
  147. throw new error_1.FirebaseError(`To create this secret, run this command in interactive mode, or go to ${secretManager.secretManagerConsoleUri(args.projectId)}`);
  148. }
  149. return (0, askUserForParam_1.promptCreateSecret)(args.projectId, args.instanceId, args.secretParam, args.secretName);
  150. }