kubricate
Version:
A TypeScript framework for building reusable, type-safe Kubernetes infrastructure — without the YAML mess.
112 lines (111 loc) • 4.01 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.SecretManagerEngine = void 0;
var _SecretManager = /*#__PURE__*/require("../SecretManager.js");
var _SecretRegistry = /*#__PURE__*/require("../SecretRegistry.js");
/**
* SecretManagerEngine orchestrates loading, validating, and preparing secrets
* across all stacks defined in the Kubricate config.
*/
class SecretManagerEngine {
options;
constructor(options) {
this.options = options;
}
normalizeSecretSpec(input) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const isManager = val =>
// Check if the value is an instance of SecretManager
val instanceof _SecretManager.SecretManager ||
// Check the SecretManager interface
typeof val?.getSecrets === 'function' && typeof val?.resolveProvider === 'function' && typeof val?.resolveConnector === 'function';
return isManager(input) ? new _SecretRegistry.SecretRegistry().add('default', input) : input;
}
/**
* Collect all SecretManager instances from the project config.
*
* @throws {Error} If both `manager` and `registry` are defined simultaneously.
* @returns {MergedSecretManager}
*/
collect() {
const {
config,
logger
} = this.options;
logger.info('Collecting secret managers...');
const secretSpec = config.secret?.secretSpec;
if (!secretSpec) {
throw new Error('[config] No secret manager or secret registry found. Please define "secret.secretSpec" in kubricate.config.ts.');
}
const result = {};
const normalized = this.normalizeSecretSpec(secretSpec);
for (const [name, manager] of Object.entries(normalized.list())) {
result[name] = {
name,
secretManager: manager
};
}
logger.debug(`Collected ${Object.keys(result).length} secret manager(s)`);
return result;
}
/**
* Validate all connectors by attempting to load secrets and resolve their values.
* Will throw if any secret can't be loaded.
*/
async validate(managers) {
const {
logger
} = this.options;
logger.info('Validating secret managers...');
for (const entry of Object.values(managers)) {
const secrets = entry.secretManager.getSecrets();
await this.loadSecrets(entry.secretManager, secrets);
}
logger.debug('Secret managers validated successfully');
}
/**
* Prepare all effects (from providers) based on loaded secret values
*/
async prepareEffects(managers) {
const effects = [];
for (const entry of Object.values(managers)) {
const secrets = entry.secretManager.getSecrets();
const resolved = await this.loadSecrets(entry.secretManager, secrets);
for (const name of Object.keys(secrets)) {
const provider = entry.secretManager.resolveProvider(secrets[name].provider);
effects.push(...provider.prepare(name, resolved[name]));
}
}
return effects;
}
/**
* Load secrets from connectors, optionally returning the loaded values.
* If `returnValues` is false, this acts as a validation-only step.
*/
async loadSecrets(secretManager, secrets) {
const {
effectOptions
} = this.options;
const resolved = {};
const loaded = new Set();
for (const name of Object.keys(secrets)) {
if (loaded.has(name)) continue;
const connector = secretManager.resolveConnector(secrets[name].connector);
// Set working directory into connector if not already set
if (connector.getWorkingDir?.() === undefined && connector.setWorkingDir) {
connector.setWorkingDir(effectOptions.workingDir);
}
// Load the secret
await connector.load([name]);
// Get the secret value
// Throws if the secret was not previously loaded via `load()`
resolved[name] = connector.get(name);
loaded.add(name);
}
return resolved;
}
}
exports.SecretManagerEngine = SecretManagerEngine;
//# sourceMappingURL=SecretManagerEngine.js.map