Skip to content

Commit

Permalink
fix: execute (#2)
Browse files Browse the repository at this point in the history
* fix: remove binary from source and add it to Docker file

* fix: add documentation on readme
  • Loading branch information
danteay committed Nov 1, 2023
1 parent 5ce46ac commit dd535f0
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 21 deletions.
8 changes: 6 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
FROM node:20

RUN curl -sLo ejson.tar.gz https://github.com/Shopify/ejson/releases/download/v1.4.1/ejson_1.4.1_linux_amd64.tar.gz && \
tar xfvz ejson.tar.gz && \
mv ejson /usr/local/bin/ && \
chmod +x /usr/local/bin/ejson && \
rm ejson.tar.gz

RUN mkdir -p /opt/ejson/keys

COPY . /action
WORKDIR /action

RUN chmod +x ejson-1.4.1

RUN npm install --production

ENTRYPOINT ["node", "/action/index.js"]
58 changes: 57 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,59 @@
# ejson-action

Simple github action that helps to execute encryption and decryption of json files using the ejson cli
Simple github action that helps to execute encryption and decryption of json files using the ejson cli. **Current ejson version 1.4.1**.

## Configuration

```yaml
- name: ejson action
uses: Drafteame/ejson-action@main
with:
action: decrypt # [encrypt, decrypt]
file_path: <path-to-ejson-file>
private_key: <private-key-string> # needed if encrypt is used as action

```

### Outputs

| Output | Description |
|------------|---------------------------------------------------|
| **decrypted** | Decrypted content of the file when the action is performed with the `decrypt` action |

## Usage

```yaml
jobs:
test:
runs-on: ubuntu-latest

steps:
- name: Checkout Repository
uses: actions/checkout@v4

- name: Decrypt file
uses: Drafteame/ejson-action@main
id: decrypt
with:
action: decrypt
file_path: <path-to-ejson-file>
private_key: <private-key-string>

- name: Decrypted content
run: |
echo "Decrypted:"
echo "${{ steps.decrypt.outputs.decrypted }}"
- name: Encrypt file
uses: Drafteame/ejson-action@main
id: encrypt
with:
action: encrypt
file_path: <path-to-ejson-file>
private_key: <private-key-string>

- name: Encrypted content
run: |
echo "Encrypted content:"
cat <path-to-ejson-file>
```
2 changes: 1 addition & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ inputs:
required: false

outputs:
decrypt:
decrypted:
description: "List of changes made to the secret"

runs:
Expand Down
Binary file removed ejson-1.4.1
Binary file not shown.
8 changes: 5 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ const main = async () => {
core.getInput("private_key"),
);

const decrypted = await action.run();

core.info(`Decrypted JSON: ${decrypted}`);
try {
await action.run();
} catch (e) {
core.error(e);
}
};

main();
80 changes: 66 additions & 14 deletions src/Action.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,21 @@ import cp from "child_process";
import lodash from "lodash";
import core from "@actions/core";

const ejson = "/action/ejson-1.4.1";
// The ejson command used for encryption and decryption
const ejson = "ejson";

export default class Action {
#action;
#filePath;
#privateKey;

/**
* Create a new Action instance.
*
* @param {string} action The action to perform (encrypt or decrypt).
* @param {string} filePath The path to the JSON file.
* @param {string} privateKey Optional private key for encryption.
*/
constructor(action, filePath, privateKey = "") {
this.exec = util.promisify(cp.exec);

Expand All @@ -21,60 +29,104 @@ export default class Action {
this.#validate();
}

/**
* Validate the existence of the JSON file at the specified path.
*
* @throws {Error} File not exists
*/
#validate() {
if (!fs.existsSync(this.#filePath)) {
throw new Error(`JSON file does not exist at path: ${this.#filePath}`);
}
}

/**
* Run the action based on the provided action type.
*
* @throws {Error} Invalid action to perform
*
* @returns {Promise<string>} - The result of the action.
*/
async run() {
switch (this.#action) {
case "encrypt":
await this.#encrypt();
break;
return await this.#encrypt();

case "decrypt":
await this.#decrypt();
break;
return await this.#decrypt();

default:
throw new Error(`invalid action '${this.#action}'`);
throw new Error(`Invalid action '${this.#action}'`);
}
}

/**
* Encrypt the JSON file using the ejson command.
*
* @throws {Error} An execution error occurs during ejson command
*
* @returns {Promise<string>} - The encrypted content.
*/
async #encrypt() {
const command = `${ejson} encrypt ${this.#filePath}`;
const opts = { env: { ...process.env } };

await this.exec(command, opts);
const res = await this.exec(command, opts);

const out = res.stdout.toString();
const err = res.stderr.toString();

if (!lodash.isEmpty(err)) {
throw new Error(err);
}

core.info("Encrypted successfully...");
}

/**
* Decrypt the JSON file using the ejson command and set the decrypted output.
*
* @throws {Error} An execution error occurs during ejson command
*
* @returns {Promise<void>}
*/
async #decrypt() {
this.#configurePrivateKey();

const command = `${ejson} decrypt ${this.#filePath} > /decrypted.json`;
const command = `${ejson} decrypt ${this.#filePath}`;
const opts = { env: { ...process.env } };

await this.exec(command, opts);
const res = await this.exec(command, opts);

const out = res.stdout.toString();
const err = res.stderr.toString();

const decrypted = fs.readFileSync("/decrypted.json", "utf-8");
if (!lodash.isEmpty(err)) {
throw new Error(err);
}

core.setOutput("decrypted", decrypted);
core.setOutput("decrypted", out);

return decrypted;
core.info("Decrypted successfully...");
}

/**
* Configure the private key for decryption.
*
* @throws {Error} Private key is not configured
* @throws {Error} Public key is not present on ejson file
*/
#configurePrivateKey() {
if (lodash.isEmpty(this.#privateKey)) {
throw new Error("no provided private key for encryption");
throw new Error("No provided private key for encryption");
}

const data = JSON.parse(fs.readFileSync(this.#filePath, "utf8"));

const publicKey = data["_public_key"];

if (!publicKey) {
throw new Error("not found public key on ejson file");
throw new Error("Not found public key in ejson file");
}

const keyPath = `/opt/ejson/keys/${publicKey}`;
Expand Down

0 comments on commit dd535f0

Please sign in to comment.