UNPKG

envilder

Version:

A CLI and GitHub Action that securely centralizes your environment variables from AWS SSM or Azure Key Vault as a single source of truth

157 lines 8.48 kB
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var PullSecretsToEnvCommandHandler_1; import { inject, injectable } from 'inversify'; import pc from 'picocolors'; import { EnvironmentVariable } from '../../domain/EnvironmentVariable.js'; import { ExpiredCredentialsError, SecretsFetchError, SsoSessionExpiredError, } from '../../domain/errors/DomainErrors.js'; import { describeError } from '../../infrastructure/describeError.js'; import { TYPES } from '../../types.js'; let PullSecretsToEnvCommandHandler = PullSecretsToEnvCommandHandler_1 = class PullSecretsToEnvCommandHandler { constructor(secretProvider, variableStore, logger) { this.secretProvider = secretProvider; this.variableStore = variableStore; this.logger = logger; } /** * Handles the PullSecretsToEnvCommand which orchestrates the process of fetching * environment variable values from a secret store and writing them to a local environment file. * * @param command - The PullSecretsToEnvCommand containing mapPath and envFilePath */ handle(command) { return __awaiter(this, void 0, void 0, function* () { const { requestVariables, currentVariables } = yield this.loadVariables(command); const { variables, resolvedCount, totalCount } = yield this.envild(requestVariables, currentVariables); yield this.saveEnvFile(command.envFilePath, variables); this.logger.info(PullSecretsToEnvCommandHandler_1.buildSummary(resolvedCount, totalCount, command.envFilePath)); }); } loadVariables(command) { return __awaiter(this, void 0, void 0, function* () { const requestVariables = yield this.variableStore.getMapping(command.mapPath); const currentVariables = yield this.variableStore.getEnvironment(command.envFilePath); return { requestVariables, currentVariables }; }); } saveEnvFile(envFilePath, variables) { return __awaiter(this, void 0, void 0, function* () { yield this.variableStore.saveEnvironment(envFilePath, variables); }); } envild(paramMap, existingEnvVariables) { return __awaiter(this, void 0, void 0, function* () { const outcomes = yield Promise.all(Object.entries(paramMap).map(([envVar, secretName]) => this.processSecret(envVar, secretName, existingEnvVariables))); const resolved = outcomes.filter((outcome) => outcome.status === 'resolved'); const warnings = outcomes.filter((outcome) => outcome.status === 'warning'); const errors = outcomes.filter((outcome) => outcome.status === 'error'); this.logSecretsSection(resolved, warnings); if (errors.length > 0) { throw new SecretsFetchError(errors.map((error) => ({ envVar: error.envVar, path: error.path, reason: error.reason, }))); } return { variables: existingEnvVariables, resolvedCount: resolved.length, totalCount: Object.keys(paramMap).length, }; }); } processSecret(envVar, secretName, existingEnvVariables) { return __awaiter(this, void 0, void 0, function* () { try { const value = yield this.secretProvider.getSecret(secretName); if (value === undefined) { return { status: 'warning', envVar, path: secretName, reason: 'not-found', }; } if (value === '') { return { status: 'warning', envVar, path: secretName, reason: 'empty' }; } existingEnvVariables[envVar] = value; const masked = new EnvironmentVariable(envVar, value, true).maskedValue; return { status: 'resolved', envVar, masked }; } catch (error) { if (error instanceof ExpiredCredentialsError || error instanceof SsoSessionExpiredError) { throw error; } const maskedPath = EnvironmentVariable.maskSecretPath(secretName); const reason = PullSecretsToEnvCommandHandler_1.describeErrorReason(error, maskedPath); return { status: 'error', envVar, path: maskedPath, reason }; } }); } static describeErrorReason(error, maskedPath) { const message = describeError(error); const duplicatedPrefix = `${maskedPath}: `; return message.startsWith(duplicatedPrefix) ? message.slice(duplicatedPrefix.length) : message; } logSecretsSection(resolved, warnings) { if (resolved.length === 0 && warnings.length === 0) { return; } this.logger.info(`\n${pc.bold(pc.yellow('\u{1FA99} RESOLVING SECRETS'))}`); this.logger.info(PullSecretsToEnvCommandHandler_1.RULE); for (const outcome of resolved) { this.logger.info(` ${pc.green('\u2713 ')}${pc.bold(PullSecretsToEnvCommandHandler_1.pad(outcome.envVar))}${pc.dim('\u2192 ')}${pc.dim(outcome.masked)}`); } this.logWarnings(warnings); } logWarnings(warnings) { for (const outcome of warnings) { const maskedPath = EnvironmentVariable.maskSecretPath(outcome.path); if (outcome.reason === 'not-found') { this.logger.warn(` ${pc.red('\u2717 ')}${pc.bold(pc.red(PullSecretsToEnvCommandHandler_1.pad(outcome.envVar)))} ${pc.red(`secret not found (path: ${maskedPath}) \u2014 skipped`)}`); continue; } this.logger.warn(` ${pc.yellow('\u26A0 ')}${pc.bold(PullSecretsToEnvCommandHandler_1.pad(outcome.envVar))} ${pc.dim(`no value found (path: ${maskedPath}) \u2014 skipped`)}`); } } static pad(name) { return name.padEnd(PullSecretsToEnvCommandHandler_1.LABEL_WIDTH); } static buildSummary(resolvedCount, totalCount, envFilePath) { return `\n${pc.bold(pc.green('\u2B50 LEVEL CLEARED'))}${pc.dim(` \u2014 ${resolvedCount}/${totalCount} secrets loaded \u00B7 `)}${pc.bold(envFilePath)}${pc.dim(' written')}\n`; } }; PullSecretsToEnvCommandHandler.LABEL_WIDTH = 20; PullSecretsToEnvCommandHandler.RULE = pc.yellow('\u2501'.repeat(60)); PullSecretsToEnvCommandHandler = PullSecretsToEnvCommandHandler_1 = __decorate([ injectable(), __param(0, inject(TYPES.ISecretProvider)), __param(1, inject(TYPES.IVariableStore)), __param(2, inject(TYPES.ILogger)), __metadata("design:paramtypes", [Object, Object, Object]) ], PullSecretsToEnvCommandHandler); export { PullSecretsToEnvCommandHandler }; //# sourceMappingURL=PullSecretsToEnvCommandHandler.js.map