Skip to content

Instantly share code, notes, and snippets.

@hilleer
Last active May 22, 2021 11:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hilleer/fc122b3f6647f232dc95441a13d04c5e to your computer and use it in GitHub Desktop.
Save hilleer/fc122b3f6647f232dc95441a13d04c5e to your computer and use it in GitHub Desktop.
Fuck up story; rotating Heroku app serets using their CLI tool
const childProcess = require('child_process');
const { promisify } = require('util');
const exec = promisify(childProcess.exec);
const DRY_RUN = true; // set to false when you want to execute it
const { NEW_SECRET } = process.env; // do not end up committing the new secret :-)
(async () => {
const { stdout: apps } = await exec('heroku apps -A --json');
const appsWithSecret = [];
for (const app of JSON.parse(apps)) {
const { name } = app;
const { stdout: config } = await exec(`heroku config -a ${name} --json`);
const prodAppRegex = /^PROD-FOO/;
const isProdApp = (app) => app.name.test(prodAppRegex); // could also use a simple string comparison if fit your needs
const match = Object.entries(config).find((isProdApp));
if (!match) {
continue;
}
appsWithSecret.push({ name, envVariable: match, otherPropsYouMightNeed });
}
for (const app of appsWithSecret) {
const { name, envVariable } = app;
const [key, oldSecret] = envVariable;
if (DRY_RUN) {
const appSecret = await getAppSecret(name, key);
// could verify "oldSecret" === "appSecret"
} else {
const resultOldKey = await setAppSecret(appName, `${key}_old`, oldSecret);
const resultNewKey = await setAppSecret(appName, key, NEW_SECRET);
}
}
})();
async function getAppSecret(appName, configVar) {
const { stdout: appSecret } = await exec(`heroku config:get ${configVar} -a ${appName}`);
// returns a string of the value
return appSecret;
}
async function setAppSecret(appName, configVar, newValue) {
const { stdout: result } = await exec(`heroku config:set ${configVar}=${newValue} -a ${appName}`);
// return a string like:
// Setting <configVar> and restarting ⬢ <appName>... done, <new app version>
// <configVar>: newValue
return result;
}
module.exports = {
setAppSecret
}
const childProcess = require('child_process');
const { promisify } = require('util');
const { setAppSecret } = require('./addNewSecret');
const exec = promisify(childProcess.exec);
// same approach as in addNewSecret with the difference that we look for the old key now:
// <configVar>_old and unset it using below function
async function unsetAppSecret(appName, configVar) {
const { stdout: result } = await exec(`heroku config:unset ${configVar} -a ${appName}`);
// returns a string like:
// Unsetting <configVar and restarting ⬢ <appName>... done, <new app version>
return result;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment