Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add github environment support #316

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ Options:
* `-r`, `--repo` - The GitHub full repository name (e.g.
`cdklabs/aws-secrets-github-sync`). If this is not specified, we will try to resolve the
repo from the current git settings.
* `-e`, `--environment` - The GitHub environment to store the secret in (Optional).
* `-R`, `--region` - The AWS region to read the secret from. If this is not
specified, `AWS_REGION` will be used. If the secret is an ARN, we will resolve
the region from the ARN.
Expand Down
2 changes: 2 additions & 0 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ async function main() {
.usage('$0 -C secrets.json')
.option('secret', { alias: 's', describe: 'Secrets Manager secret ID or ARN', type: 'string', required: true })
.option('repo', { alias: 'r', describe: 'GitHub repository owner/name (default is derived from current git repository)', type: 'string' })
.option('environment', { alias: 'e', describe: 'GitHub environment', type: 'string' })
.option('region', { alias: 'R', describe: 'AWS region (if --secret is an ARN, region is not required)', type: 'string' })
.option('keys', { alias: 'k', describe: 'Which keys to update (to update all keys use --all)', type: 'array' })
.option('all', { alias: 'A', describe: 'Update all keys', type: 'boolean' })
Expand All @@ -32,6 +33,7 @@ async function main() {
secret: argv.secret,
region: argv.region,
repository: argv.repo,
environment: argv.environment,
allKeys: argv.all,
keys: argv.keys,
confirm: !argv.yes,
Expand Down
25 changes: 19 additions & 6 deletions src/clients.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,19 @@ export interface SecretOptions {
* Credential profile to use.
*/
readonly profile?: string;
/**
* Environment to use.
*/
readonly env?: string;
}

export interface Clients {
getSecret(secretId: string, options?: SecretOptions): Promise<Secret>;
confirmPrompt(): Promise<boolean>;
getRepositoryName(): string;
storeSecret(repository: string, key: string, value: string): void;
listSecrets(repository: string): string[];
removeSecret(repository: string, key: string): void;
storeSecret(repository: string, key: string, value: string, environment?: string): void;
listSecrets(repository: string, environment?: string): string[];
removeSecret(repository: string, key: string, environment?: string): void;
log(text?: string): void;
}

Expand Down Expand Up @@ -54,19 +58,28 @@ function getRepositoryName(): string {
}
}

function storeSecret(repository: string, name: string, value: string): void {
function storeSecret(repository: string, name: string, value: string, environment?: string): void {
const args = ['secret', 'set', '--repo', repository, name];
if (environment) {
args.push('-e', environment);
}
spawnSync('gh', args, { input: value, stdio: ['pipe', 'inherit', 'inherit'] });
}

function listSecrets(repository: string): string[] {
function listSecrets(repository: string, environment?: string): string[] {
const args = ['secret', 'list', '--repo', repository];
if (environment) {
args.push('-e', environment);
}
const stdout = spawnSync('gh', args, { stdio: ['ignore', 'pipe', 'inherit'] }).stdout.toString('utf-8').trim();
return stdout.split('\n').map(line => line.split('\t')[0]);
}

function removeSecret(repository: string, key: string): void {
function removeSecret(repository: string, key: string, environment?: string): void {
const args = ['secret', 'remove', '--repo', repository, key];
if (environment) {
args.push('-e', environment);
}
spawnSync('gh', args, { stdio: ['ignore', 'inherit', 'inherit'] });
}

Expand Down
13 changes: 10 additions & 3 deletions src/update-secrets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ export interface UpdateSecretsOptions {
*/
readonly repository?: string;

/**
* The environment to use.
* @default - no environment
*/
readonly environment?: string;

/**
* The secret keys to update. To update all keys, set `all` to `true` and leave `keys` empty.
*
Expand Down Expand Up @@ -83,6 +89,7 @@ export async function updateSecrets(options: UpdateSecretsOptions) {
}

const repository: string = options.repository ?? c.getRepositoryName();
const environment = options.environment;
const secret = await c.getSecret(options.secret, { region, profile: options.profile });
const keys = options.keys ?? [];
const prune = options.prune ?? false;
Expand Down Expand Up @@ -117,7 +124,7 @@ export async function updateSecrets(options: UpdateSecretsOptions) {
}

// find all the secrets in the repo that don't correspond to keys in the secret
const existingKeys = c.listSecrets(repository);
const existingKeys = c.listSecrets(repository, environment);
const pruneCandidates = existingKeys.filter(key => !keys.includes(key));
const keysToPrune = pruneCandidates.filter(key => !keep.includes(key));
const keysToKeep = pruneCandidates.filter(key => keep.includes(key));
Expand Down Expand Up @@ -153,13 +160,13 @@ export async function updateSecrets(options: UpdateSecretsOptions) {
continue; // skip if key is not in "keys"
}

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

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