This repository has been archived by the owner on Aug 26, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
adds initial .env support for secret 'syncing' from file #13
- Loading branch information
Brendon Lees
committed
Jan 28, 2021
1 parent
f646f2f
commit 7b48f28
Showing
7 changed files
with
193 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
import {Command, flags} from '@oclif/command' | ||
import {CLIError} from '@oclif/errors' | ||
import dotenv from 'dotenv' | ||
import {request} from '@octokit/request' | ||
import fs from 'fs-extra' | ||
import sodium from 'tweetsodium' | ||
import {configuration} from '../../utils/config' | ||
|
||
export default class SecretsSync extends Command { | ||
static description = 'describe the command here' | ||
|
||
static flags = { | ||
help: flags.help({char: 'h'}), | ||
personalAccessToken: flags.string({ | ||
char: 't', | ||
description: 'Your GitHub Personal Access Token.', | ||
required: false, | ||
}), | ||
org: flags.string({ | ||
char: 'o', | ||
description: 'Organisation the repo belongs to.', | ||
required: false, | ||
}), | ||
repo: flags.string({ | ||
char: 'r', | ||
description: 'Name of the repo.', | ||
required: false, | ||
}), | ||
base64: flags.boolean({ | ||
char: 'b', | ||
description: 'base64 the values before encoding.', | ||
required: false, | ||
default: false, | ||
}), | ||
} | ||
|
||
static args = [{name: 'file'}] | ||
|
||
async run() { | ||
const {args, flags} = this.parse(SecretsSync) | ||
|
||
try { | ||
if (!args.file) { | ||
this.error(new CLIError('Please provide a file')) | ||
} | ||
const messageString = fs.readFileSync(args.file) | ||
const output = dotenv.parse(messageString, {debug: true}) | ||
this.log(typeof output, output) | ||
if (Object.keys(output).length === 0 || output.constructor !== Object) { | ||
this.error('File is either empty or not a valid .env format') | ||
} | ||
|
||
const conf = await configuration(this) | ||
|
||
const requestWithAuth = request.defaults({ | ||
headers: { | ||
authorization: `token ${ | ||
flags.personalAccessToken ?? conf.personalAccessToken | ||
}`, | ||
}, | ||
}) | ||
|
||
const {data: token} = await requestWithAuth( | ||
'GET /repos/{owner}/{repo}/actions/secrets/public-key', | ||
{ | ||
owner: flags.org ?? conf.org, | ||
repo: flags.repo ?? conf.repo, | ||
} | ||
) | ||
|
||
Object.keys(output).forEach(async key => { | ||
let value = output[key] | ||
if (flags.base64) { | ||
value = btoa(value) | ||
} | ||
|
||
const messageBytes = Buffer.from(value) | ||
|
||
const keyBytes = Buffer.from(token.key, 'base64') | ||
|
||
const encryptedBytes = sodium.seal(messageBytes, keyBytes) | ||
|
||
const encrypted = Buffer.from(encryptedBytes).toString('base64') | ||
|
||
try { | ||
await requestWithAuth( | ||
'PUT /repos/{owner}/{repo}/actions/secrets/{secret_name}', | ||
{ | ||
owner: flags.org ?? conf.org, | ||
repo: flags.repo ?? conf.repo, | ||
secret_name: key, | ||
encrypted_value: encrypted, | ||
key_id: token.key_id, | ||
} | ||
) | ||
this.log(`Updated secret: ${key}`) | ||
} catch (error) { | ||
this.error(`Unable to update secret: ${key} \n${error}`) | ||
} | ||
}) | ||
} catch (error) { | ||
this.error(new CLIError(error), {exit: 1}) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import {expect, test} from '@oclif/test' | ||
|
||
describe('secrets:sync', () => { | ||
test | ||
.stdout() | ||
.command(['secrets:sync']) | ||
.it('runs hello', ctx => { | ||
expect(ctx.stdout).to.contain('hello world') | ||
}) | ||
|
||
test | ||
.stdout() | ||
.command(['secrets:sync', '--name', 'jeff']) | ||
.it('runs hello --name jeff', ctx => { | ||
expect(ctx.stdout).to.contain('hello jeff') | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters