Skip to content

Commit

Permalink
Chore/add exclude flag (#4)
Browse files Browse the repository at this point in the history
* chore: add exclude option to skip sync keys

* chore: save

* chore: save

* chore: add colors to log messages

* chore: add configuration to show or hide secret values
  • Loading branch information
danteay authored Nov 1, 2023
1 parent 1349adc commit 7c01ba1
Show file tree
Hide file tree
Showing 8 changed files with 297 additions and 64 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,6 @@ jobs:
secret_name: <secret-name>
json_file_path: path/to/json/secrets.json
dry_run: true # Default false
show_values: false # If true secret values will be displayed on action logs (default false)
exclude: '^_' # Regular expression that excludes the matching keys to be synced (default '^_')
```
9 changes: 8 additions & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,14 @@ inputs:
dry_run:
description: "Dry run mode (preview changes without modifying the secret)"
required: false
default: "false" # Set the default value to 'false'
default: "false"
show_values:
description: "Dry run mode (preview changes without modifying the secret)"
required: false
default: "false"
exclude:
description: "List of regular expressions that determines if a secret key should be excluded from sync"
required: false

outputs:
changes:
Expand Down
29 changes: 17 additions & 12 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,35 @@
import core from "@actions/core";
import Action from "./src/action/Action.js";

async function run() {
try {
const dryRun = core.getInput("dry_run") === "true";
const getAction = () => {
return new Action(
core.getInput("aws_access_key_id"),
core.getInput("aws_secret_access_key"),
core.getInput("aws_region"),
core.getInput("secret_name"),
core.getInput("json_file_path"),
core.getInput("exclude"),
core.getBooleanInput("show_values"),
);
};

const action = new Action(
core.getInput("aws_access_key_id"),
core.getInput("aws_secret_access_key"),
core.getInput("aws_region"),
core.getInput("secret_name"),
core.getInput("json_file_path"),
);
const run = async () => {
try {
const dryRun = core.getBooleanInput("dry_run");

const changeSet = await action.run();
const changeSet = await getAction().run();

for (const desc of changeSet.changeDesc()) {
core.info(desc);
}

if (!dryRun) {
await changeSet.apply();
core.info("Secrets has been synced!!");
}
} catch (error) {
core.setFailed(error.message);
}
}
};

run();
50 changes: 39 additions & 11 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"scripts": {
"lint": "npx eslint --fix .",
"format": "npx prettier --write .",
"test": "mocha ./tests/**/*.test.js",
"test": "FORCE_COLOR=0 mocha ./tests/**/*.test.js",
"pre-commit": "pre-commit install --hook-type commit-msg"
},
"repository": {
Expand Down Expand Up @@ -41,6 +41,7 @@
"dependencies": {
"@actions/core": "^1.10.1",
"@aws-sdk/client-secrets-manager": "^3.425.0",
"chalk": "^5.3.0",
"fs": "^0.0.1-security",
"lodash": "^4.17.21"
}
Expand Down
62 changes: 42 additions & 20 deletions src/action/Action.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import fs from "fs";
import SecretsManager from "../secrets-manager/SecretsManager.js";
import ChangeSet from "./ChangeSet.js";

const defaultSkipPattern = "^_";

/**
* Action is a class representing an action to synchronize secrets with AWS Secrets Manager.
* It validates input data, fetches existing secrets, and creates a change set for updates.
Expand All @@ -11,22 +13,54 @@ export default class Action {
/**
* Creates a new Action instance.
*
* @param {string} keyId - The AWS access key ID.
* @param {string} secretKey - The AWS secret access key.
* @param {string} region - The AWS region.
* @param {string} secretName - The name of the secret in AWS Secrets Manager.
* @param {string} jsonFile - The path to the JSON file containing the new secret values.
* @param {string} keyId The AWS access key ID.
* @param {string} secretKey The AWS secret access key.
* @param {string} region The AWS region.
* @param {string} secretName The name of the secret in AWS Secrets Manager.
* @param {string} jsonFile The path to the JSON file containing the new secret values.
* @param {string} skipPattern A regular expression that eval keys of the json file and if match,
* that key should be omitted
* @param {string} showValues If this flag is set to true all secret values will be displayed on logs,
* if false, a place holder will be displayed.
*
* @throws {Error} Throws an error if any required parameter is missing or if the JSON file doesn't exist.
*/
constructor(keyId, secretKey, region, secretName, jsonFile) {
this.validateData(keyId, secretKey, region, secretName, jsonFile);
constructor(
keyId,
secretKey,
region,
secretName,
jsonFile,
skipPattern,
showValues = false,
) {
this.#validateData(keyId, secretKey, region, secretName, jsonFile);

this.jsonFile = jsonFile;
this.skipPattern = skipPattern || defaultSkipPattern;
this.showValues = showValues;

this.smClient = new SecretsManager(keyId, secretKey, region, secretName);
}

/**
* Runs the action to synchronize secrets by fetching existing secrets and creating a change set.
*
* @returns {Promise<ChangeSet>} A promise that resolves to a ChangeSet instance representing the changes to be applied.
*/
async run() {
const existingSecretData = await this.smClient.getValues();
const newSecretData = JSON.parse(fs.readFileSync(this.jsonFile, "utf8"));

return new ChangeSet(
this.smClient,
newSecretData,
existingSecretData,
this.skipPattern,
this.showValues,
);
}

/**
* Validates input data, ensuring that required parameters are provided and the JSON file exists.
*
Expand All @@ -38,7 +72,7 @@ export default class Action {
*
* @throws {Error} Throws an error if any required parameter is missing or if the JSON file doesn't exist.
*/
validateData(keyId, secretKey, region, secretName, jsonFile) {
#validateData(keyId, secretKey, region, secretName, jsonFile) {
if (!keyId) {
throw new Error("Missing aws_access_key_id");
}
Expand All @@ -64,16 +98,4 @@ export default class Action {
throw new Error(`JSON file does not exist at path: ${jsonFile}`);
}
}

/**
* Runs the action to synchronize secrets by fetching existing secrets and creating a change set.
*
* @returns {Promise<ChangeSet>} A promise that resolves to a ChangeSet instance representing the changes to be applied.
*/
async run() {
const existingSecretData = await this.smClient.getValues();
const newSecretData = JSON.parse(fs.readFileSync(this.jsonFile, "utf8"));

return new ChangeSet(this.smClient, newSecretData, existingSecretData);
}
}
Loading

0 comments on commit 7c01ba1

Please sign in to comment.