export async function updateSecrets()

in src/update-secrets.ts [75:165]


export async function updateSecrets(options: UpdateSecretsOptions) {
  const secretId = options.secret;
  const c = options.clients ?? clients.DEFAULTS;

  // if the secret id is an arn, extract the region from it
  let region = options.region;
  if (!region && secretId.startsWith('arn:')) {
    region = secretId.split(':')[3];
  }

  const repository: string = options.repository ?? c.getRepositoryName();
  const secret = await c.getSecret(options.secret, { region, profile: options.profile });
  const keys = options.keys ?? [];
  const prune = options.prune ?? false;
  const keep = options.keep ?? [];

  if (typeof(secret.json) !== 'object') {
    throw new Error(`Secret "${secret.arn}" is not an object`);
  }

  if (options.allKeys === undefined && options.keys === undefined) {
    throw new Error('Either `all` or `keys` must be set');
  }

  if (options.allKeys) {
    if (keys.length > 0) {
      throw new Error('Cannot set both `all` and `keys`');
    }

    // remove "*" and replace with all the keys from the secret
    keys.push(...Object.keys(secret.json));
  }

  if (keys.length === 0) {
    throw new Error('No keys to update');
  }

  // verify that all the keys exist in the secret
  for (const requiredKey of keys) {
    if (!(requiredKey in secret.json)) {
      throw new Error(`Secret "${secretId}" does not contain key "${requiredKey}"`);
    }
  }

  // find all the secrets in the repo that don't correspond to keys in the secret
  const existingKeys = c.listSecrets(repository);
  const pruneCandidates = existingKeys.filter(key => !keys.includes(key));
  const keysToPrune = pruneCandidates.filter(key => !keep.includes(key));
  const keysToKeep = pruneCandidates.filter(key => keep.includes(key));

  c.log(`FROM  : ${secret.arn}`);
  c.log(`REPO  : ${repository}`);
  c.log(`UDPATE: ${keys.join(',')}`);

  if (pruneCandidates.length > 0) {
    if (prune) {
      if (keysToPrune.length > 0) {
        c.log(`PRUNE : ${keysToPrune.join(',')}`);
      }
      if (keysToKeep.length > 0) {
        c.log(`KEEP  : ${keysToKeep.join(',')}`);
      }
    } else {
      c.log(`SKIP  : ${pruneCandidates.join(',')} (use --prune to remove)`);
    }
  }

  c.log();

  // ask user to confirm
  const confirm = options.confirm ?? true;
  if (confirm && !await c.confirmPrompt()) {
    c.log('Cancelled by user');
    return;
  }

  for (const [key, value] of Object.entries(secret.json)) {
    if (keys.length > 0 && !keys.includes(key)) {
      continue; // skip if key is not in "keys"
    }

    c.storeSecret(repository, key, value);
  }

  // prune keys that are not in the secret
  if (prune) {
    for (const key of keysToPrune) {
      c.removeSecret(repository, key);
    }
  }
}