"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.checkSpecForSecrets = exports.handleSecretParams = void 0; const clc = require("colorette"); const secretUtils = require("../../extensions/secretsUtils"); const secretManager = require("../../gcp/secretManager"); const planner_1 = require("./planner"); const askUserForParam_1 = require("../../extensions/askUserForParam"); const types_1 = require("../../extensions/types"); const error_1 = require("../../error"); const logger_1 = require("../../logger"); const utils_1 = require("../../utils"); async function handleSecretParams(payload, have, nonInteractive) { var _a, _b, _c; for (const i of (_a = payload.instancesToCreate) !== null && _a !== void 0 ? _a : []) { if (await checkSpecForSecrets(i)) { (0, utils_1.logLabeledBullet)("extensions", `Verifying secret params for ${clc.bold(i.instanceId)}`); await handleSecretsCreateInstance(i, nonInteractive); } } const updates = [...((_b = payload.instancesToUpdate) !== null && _b !== void 0 ? _b : []), ...((_c = payload.instancesToConfigure) !== null && _c !== void 0 ? _c : [])]; for (const i of updates) { if (await checkSpecForSecrets(i)) { (0, utils_1.logLabeledBullet)("extensions", `Verifying secret params for ${clc.bold(i.instanceId)}`); const previousSpec = have.find((h) => h.instanceId === i.instanceId); await handleSecretsUpdateInstance(i, previousSpec, nonInteractive); } } } exports.handleSecretParams = handleSecretParams; async function checkSpecForSecrets(i) { const extensionSpec = await (0, planner_1.getExtensionSpec)(i); return secretUtils.usesSecrets(extensionSpec); } exports.checkSpecForSecrets = checkSpecForSecrets; const secretsInSpec = (spec) => { return spec.params.filter((p) => p.type === types_1.ParamType.SECRET); }; async function handleSecretsCreateInstance(i, nonInteractive) { const extensionVersion = await (0, planner_1.getExtensionVersion)(i); const secretParams = secretsInSpec(extensionVersion.spec); for (const s of secretParams) { await handleSecretParamForCreate(s, i, nonInteractive); } } async function handleSecretsUpdateInstance(i, prevSpec, nonInteractive) { const extensionVersion = await (0, planner_1.getExtensionVersion)(i); const prevExtensionVersion = await (0, planner_1.getExtensionVersion)(prevSpec); const secretParams = secretsInSpec(extensionVersion.spec); for (const s of secretParams) { const prevParam = prevExtensionVersion.spec.params.find((p) => p.param === s.param); 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]) { await handleSecretParamForUpdate(s, i, prevSpec.params[prevParam === null || prevParam === void 0 ? void 0 : prevParam.param], nonInteractive); } else { await handleSecretParamForCreate(s, i, nonInteractive); } } } async function handleSecretParamForCreate(secretParam, i, nonInteractive) { var _a; const providedValue = i.params[secretParam.param]; if (!providedValue) { return; } const [, projectId, , secretName, , version] = providedValue.split("/"); if (!projectId || !secretName || !version) { throw new error_1.FirebaseError(`${clc.bold(i.instanceId)}: Found '${providedValue}' for secret param ${secretParam.param}, but expected a secret version.`); } const secretInfo = await getSecretInfo(projectId, secretName, version); if (!secretInfo.secret) { await promptForCreateSecret({ projectId, secretName, instanceId: i.instanceId, secretParam, nonInteractive, }); return; } else if (!secretInfo.secretVersion) { throw new error_1.FirebaseError(`${clc.bold(i.instanceId)}: Found '${providedValue}' for secret param ${secretParam.param}. ` + `projects/${projectId}/secrets/${secretName} exists, but version ${version} does not. ` + `See more information about this secret at ${secretManager.secretManagerConsoleUri(projectId)}`); } if (!!((_a = secretInfo === null || secretInfo === void 0 ? void 0 : secretInfo.secret) === null || _a === void 0 ? void 0 : _a.labels) && !!(secretInfo === null || secretInfo === void 0 ? void 0 : secretInfo.secret.labels[secretUtils.SECRET_LABEL]) && secretInfo.secret.labels[secretUtils.SECRET_LABEL] !== i.instanceId) { throw new error_1.FirebaseError(`${clc.bold(i.instanceId)}: Found '${providedValue}' for secret param ${secretParam.param}. ` + `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. ` + "Please choose a different name for this secret, and rerun this command."); } await secretUtils.grantFirexServiceAgentSecretAdminRole(secretInfo.secret); } async function handleSecretParamForUpdate(secretParam, i, prevValue, nonInteractive) { const providedValue = i.params[secretParam.param]; if (!providedValue) { return; } const [, projectId, , secretName, , version] = providedValue.split("/"); if (!projectId || !secretName || !version) { throw new error_1.FirebaseError(`${clc.bold(i.instanceId)}: Found '${providedValue}' for secret param ${secretParam.param}, but expected a secret version.`); } const [, prevProjectId, , prevSecretName] = prevValue.split("/"); if (prevSecretName !== secretName) { throw new error_1.FirebaseError(`${clc.bold(i.instanceId)}: Found '${providedValue}' for secret param ${secretParam.param}, ` + `but this instance was previously using a different secret projects/${prevProjectId}/secrets/${prevSecretName}.\n` + `Changing secrets is not supported. If you want to change the value of this secret, ` + `use a new version of projects/${prevProjectId}/secrets/${prevSecretName}.` + `You can create a new version at ${secretManager.secretManagerConsoleUri(projectId)}`); } const secretInfo = await getSecretInfo(projectId, secretName, version); if (!secretInfo.secret) { i.params[secretParam.param] = await promptForCreateSecret({ projectId, secretName, instanceId: i.instanceId, secretParam, nonInteractive, }); return; } else if (!secretInfo.secretVersion) { throw new error_1.FirebaseError(`${clc.bold(i.instanceId)}: Found '${providedValue}' for secret param ${secretParam.param}. ` + `projects/${projectId}/secrets/${secretName} exists, but version ${version} does not. ` + `See more information about this secret at ${secretManager.secretManagerConsoleUri(projectId)}`); } i.params[secretParam.param] = secretManager.toSecretVersionResourceName(secretInfo.secretVersion); await secretUtils.grantFirexServiceAgentSecretAdminRole(secretInfo.secret); } async function getSecretInfo(projectId, secretName, version) { const secretInfo = {}; try { secretInfo.secret = await secretManager.getSecret(projectId, secretName); secretInfo.secretVersion = await secretManager.getSecretVersion(projectId, secretName, version); } catch (err) { if (err.status !== 404) { throw err; } } return secretInfo; } async function promptForCreateSecret(args) { logger_1.logger.info(`${clc.bold(args.instanceId)}: Secret ${args.projectId}/${args.secretName} doesn't exist yet.`); if (args.nonInteractive) { throw new error_1.FirebaseError(`To create this secret, run this command in interactive mode, or go to ${secretManager.secretManagerConsoleUri(args.projectId)}`); } return (0, askUserForParam_1.promptCreateSecret)(args.projectId, args.instanceId, args.secretParam, args.secretName); }