secret_hub 0.0.1 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6835039458d739b136ad9d56baf090fe8261f4969d0ba144b7f361a436ca7116
4
- data.tar.gz: b404dff3cb2248e124b12b3a5a7a9547a6a88554ae2e043a99b8608d09e850a0
3
+ metadata.gz: ba608183188fcc510b16eebb1b02a0a426c69e638f52656c64335ec467ea5042
4
+ data.tar.gz: 78788d64bdbe84fa632fd2d0fd675622b01fd953ccc1c8c3f2787d4106c2a112
5
5
  SHA512:
6
- metadata.gz: e78bf842dcaa9455a7bf612b49ced104346c8ccabf6de097add9073a14e9d6bb2095d8b3529ab1a1da7e39b4b82da1d2e3d7f4031f0e64decb8268e1d9a09ffa
7
- data.tar.gz: 2dc1e103428e7a226a07a893166aac0922757b2f3224a0962c9f7a1bd2a80f4032a919adcbc62c9dabbcef5c5fd31ed80f77c25349b45d77062b4a7d04b57856
6
+ metadata.gz: fae95b5ab77f112281debf4a46194aad8aad1fedfd71bcd78c64913a2d8a98b695099a6aceb8b83c3a7096896d3e9487a687cb910c6b3be1a72016cc6127efd4
7
+ data.tar.gz: 44f948f6467d1d6207204d63bd898603dba654ed298c9af3e2fe91531d844e27b086715158b43fc084efea5f8f11052685a6ef4ba1a6c54dba5b94bbdd9de405
data/README.md CHANGED
@@ -1,24 +1,189 @@
1
- SecretHub
1
+ SecretHub - GitHub Secrets CLI
2
2
  ==================================================
3
3
 
4
4
  [![Gem Version](https://badge.fury.io/rb/secret_hub.svg)](https://badge.fury.io/rb/secret_hub)
5
- [![Build Status](https://travis-ci.com/DannyBen/secret_hub.svg?branch=master)](https://travis-ci.com/DannyBen/secret_hub)
6
- [![Maintainability](https://api.codeclimate.com/v1/badges/.../maintainability)](https://codeclimate.com/github/DannyBen/secret_hub/maintainability)
5
+ [![Build Status](https://github.com/DannyBen/secret_hub/workflows/Test/badge.svg)](https://github.com/DannyBen/secret_hub/actions?query=workflow%3ATest)
6
+ [![Maintainability](https://api.codeclimate.com/v1/badges/9ac95755c33e105ed998/maintainability)](https://codeclimate.com/github/DannyBen/secret_hub/maintainability)
7
7
 
8
8
  ---
9
9
 
10
- Manage GitHub secrets over multiple repositories
10
+ SecretHub lets you easily manage your GitHub secrets from the command line
11
+ with support for bulk operations.
11
12
 
12
13
  ---
13
14
 
14
15
  Installation
15
16
  --------------------------------------------------
16
17
 
17
- $ gem install secret_hub
18
+ ```shell
19
+ $ gem install secret_hub
20
+ ```
18
21
 
19
22
 
23
+ Prerequisites
24
+ --------------------------------------------------
25
+
26
+ SecretHub is a wrapper around the [GitHub Secrets API][secrets-api]. To use
27
+ it, you need to set up your environment with a
28
+ [GitHub Access Token][access-key]:
29
+
30
+
31
+ ```shell
32
+ $ export GITHUB_ACCESS_TOKEN=<your access token>
33
+ ```
34
+
20
35
 
21
36
  Usage
22
37
  --------------------------------------------------
23
38
 
24
- TODO
39
+ SecretHub has two families of commands:
40
+
41
+ 1. Commands that operate on a single repository.
42
+ 2. Commands that operate on multiple repositories, and multiple secrets.
43
+
44
+ Most commands are self explanatory, and described by the CLI.
45
+
46
+ ```shell
47
+ $ secrethub --help
48
+ ```
49
+
50
+ Single repository operations
51
+ --------------------------------------------------
52
+
53
+ ### Show the secret keys in a repository
54
+
55
+ ```shell
56
+ # secrethub list REPO
57
+ $ secrethub list you/your-repo
58
+ ```
59
+
60
+ ### Create or update a secret in a repository
61
+
62
+ ```shell
63
+ # secrethub save REPO KEY VALUE
64
+ $ secrethub list you/your-repo SECRET "there is no spoon"
65
+ ```
66
+
67
+ ### Delete a secret from a repository
68
+
69
+ ```shell
70
+ # secrethub delete REPO KEY
71
+ $ secrethub list you/your-repo SECRET
72
+ ```
73
+
74
+
75
+ Bulk operations
76
+ --------------------------------------------------
77
+
78
+ All the bulk operations function by using a simple YAML configuration file.
79
+ The configuration file includes a list of GitHub repositories, each with a
80
+ list of its secrets.
81
+
82
+ For example:
83
+
84
+ ```yaml
85
+ # secrethub.yml
86
+ user/repo:
87
+ - SECRET
88
+ - PASSWORD
89
+ - SECRET_KEY
90
+
91
+ user/another-repo:
92
+ - SECRET
93
+ - SECRET_KEY
94
+ ```
95
+
96
+ Each list of secrets can either be an array, or a hash.
97
+
98
+ ### Using array syntax
99
+
100
+ All secrets must be defined as environment variables.
101
+
102
+ ```yaml
103
+ user/repo:
104
+ - SECRET
105
+ - PASSWORD
106
+ ```
107
+
108
+ ### Using hash syntax
109
+
110
+ Each secret may define its value, or leave it blank. When a secret value is
111
+ blank, it will be loaded from the environment.
112
+
113
+ ```yaml
114
+ user/another-repo:
115
+ SECRET:
116
+ PASSWORD: p4ssw0rd
117
+ ```
118
+
119
+ ### Using YAML anchors
120
+
121
+ SecretHub ignores any key that does not look like a repository (does not
122
+ include a slash `/`). Using this feature, you can define reusable YAML
123
+ anchors:
124
+
125
+ ```yaml
126
+ docker: &docker
127
+ DOCKER_USER:
128
+ DOCKER_PASSWORD:
129
+
130
+ user/another-repo:
131
+ <<: *docker
132
+ SECRET:
133
+ PASSWORD: p4ssw0rd
134
+ ```
135
+
136
+ Note that YAML anchors only work with the hash syntax.
137
+
138
+
139
+ ### Create a sample configuration file
140
+
141
+ ```shell
142
+ # secrethub bulk init [CONFIG]
143
+ $ secrethub bulk init mysecrets.yml
144
+ ```
145
+
146
+ ### Show the configuration file and its secrets
147
+
148
+ ```shell
149
+ # secrethub bulk show [CONFIG --visible]
150
+ $ secrethub bulk show mysecrets.yml
151
+ ```
152
+
153
+ ### Show all secrets stored on GitHub in all repositories
154
+
155
+ ```shell
156
+ # secrethub bulk list [CONFIG]
157
+ $ secrethub bulk list mysecrets.yml
158
+ ```
159
+
160
+ ### Save multiple secrets to multiple repositories
161
+
162
+ ```shell
163
+ # secrethub bulk save [CONFIG --clean]
164
+ $ secrethub bulk save mysecrets.yml --clean
165
+ ```
166
+
167
+ Using the `--clean` flag, you can ensure that the repositories do not have
168
+ any secrets that you are unaware of. This flag will delete any secret that is
169
+ not specified in your config file.
170
+
171
+ ### Delete secrets from multiple repositories unless they are specified in the config file
172
+
173
+ ```shell
174
+ # secrethub bulk clean [CONFIG]
175
+ $ secrethub bulk clean mysecrets.yml
176
+ ```
177
+
178
+
179
+ Contributing / Support
180
+ --------------------------------------------------
181
+
182
+ If you experience any issue, have a question or a suggestion, or if you wish
183
+ to contribute, feel free to [open an issue][issues].
184
+
185
+ ---
186
+
187
+ [secrets-api]: https://developer.github.com/v3/actions/secrets/
188
+ [access-key]: https://github.com/settings/tokens
189
+ [issues]: https://github.com/DannyBen/secret_hub/issues
@@ -1,5 +1,6 @@
1
1
  require 'secret_hub/version'
2
2
  require 'secret_hub/exceptions'
3
3
  require 'secret_hub/github_client'
4
+ require 'secret_hub/config'
4
5
 
5
6
  require 'byebug' if ENV['BYEBUG']
@@ -1,91 +1,126 @@
1
- require 'yaml'
1
+ require 'fileutils'
2
+ require 'secret_hub/refinements/string_obfuscation'
2
3
 
3
4
  module SecretHub
4
5
  module Commands
5
6
  class Bulk < Base
7
+ using StringObfuscation
8
+
6
9
  summary "Update or delete multiple secrets from multiple repositories"
7
10
 
8
11
  usage "secrethub bulk init [CONFIG]"
9
- usage "secrethub bulk save [CONFIG --clean]"
10
- usage "secrethub bulk clean [CONFIG]"
12
+ usage "secrethub bulk show [CONFIG --visible]"
11
13
  usage "secrethub bulk list [CONFIG]"
14
+ usage "secrethub bulk save [CONFIG --clean --dry]"
15
+ usage "secrethub bulk clean [CONFIG --dry]"
12
16
  usage "secrethub bulk (-h|--help)"
13
17
 
14
18
  command "init", "Create a sample configuration file in the current directory"
19
+ command "show", "Show the configuration file"
15
20
  command "save", "Save multiple secrets to multiple repositories"
16
21
  command "clean", "Delete secrets from multiple repositories unless they are specified in the config file"
17
22
  command "list", "Show all secrets in all repositories"
18
23
 
19
- option "-c, --clean", "Also delete any other secret not defined in the config file"
24
+ option "-c, --clean", "Also delete any other secret not defined in the configuration file"
25
+ option "-v, --visible", "Also show secret values"
26
+ option "-d, --dry", "Dry run"
20
27
 
21
- param "CONFIG", "Path to the configuration file"
28
+ param "CONFIG", "Path to the configuration file [default: secrethub.yml]"
22
29
 
23
30
  example "secrethub bulk init"
31
+ example "secrethub bulk show --visible"
24
32
  example "secrethub bulk clean"
25
- example "secrethub bulk update mysecrets.yml"
26
- example "secrethub bulk update --clean"
33
+ example "secrethub bulk list mysecrets.yml"
34
+ example "secrethub bulk save mysecrets.yml --dry"
35
+ example "secrethub bulk save --clean"
27
36
 
28
37
  def init_command
29
38
  raise SecretHubError, "File #{config_file} already exists" if File.exist? config_file
39
+ FileUtils.cp config_template, config_file
40
+ say "!txtgrn!Saved #{config_file}"
41
+ end
30
42
 
31
- content = {
32
- "user/repo" => %w[SECRET PASSWORD SECRET_KEY],
33
- "user/another-repo" => %w[SECRET SECRET_KEY],
34
- }
43
+ def show_command
44
+ config.each do |repo, secrets|
45
+ say "!txtblu!#{repo}:"
46
+ secrets.each do |key, value|
47
+ show_secret key, value, args['--visible']
48
+ end
49
+ end
50
+ end
35
51
 
36
- File.write config_file, content.to_yaml
37
- say "!txtgrn!Saved #{config_file}"
52
+ def list_command
53
+ config.each_repo do |repo|
54
+ say "!txtblu!#{repo}:"
55
+ github.secrets(repo).each do |secret|
56
+ say "- !txtpur!#{secret}"
57
+ end
58
+ end
38
59
  end
39
60
 
40
61
  def save_command
41
- clean = args['--clean']
62
+ dry = args['--dry']
63
+ skipped = 0
42
64
 
43
- config.each do |repo, keys|
65
+ config.each do |repo, secrets|
44
66
  say "!txtblu!#{repo}"
45
- update_repo repo, keys
46
- clean_repo repo, keys if clean
67
+ skipped += update_repo repo, secrets, dry
68
+ clean_repo repo, secrets.keys, dry if args['--clean']
47
69
  end
70
+
71
+ puts "\n" if skipped > 0 or dry
72
+ say "Skipped #{skipped} missing secrets" if skipped > 0
73
+ say "Dry run, nothing happened" if dry
48
74
  end
49
75
 
50
76
  def clean_command
51
- config.each do |repo, keys|
52
- say "!txtblu!#{repo}"
53
- clean_repo repo, keys
54
- end
55
- end
77
+ dry = args['--dry']
56
78
 
57
- def list_command
58
- config.each do |repo, keys|
79
+ config.each do |repo, secrets|
59
80
  say "!txtblu!#{repo}"
60
- github.secrets(repo).each do |secret|
61
- say "!txtpur!#{secret}"
62
- end
81
+ clean_repo repo, secrets.keys, dry
63
82
  end
83
+
84
+ say "\nDry run, nothing happened" if dry
64
85
  end
65
-
86
+
66
87
  private
67
88
 
68
- def clean_repo(repo, keys)
89
+ def clean_repo(repo, keys, dry)
69
90
  repo_keys = github.secrets repo
70
91
  delete_candidates = repo_keys - keys
71
92
 
72
93
  delete_candidates.each do |key|
73
- say "delete !txtpur!#{key} "
74
- success = github.delete_secret repo, key
94
+ say "delete !txtpur!#{key} "
95
+ github.delete_secret repo, key unless dry
75
96
  say "!txtgrn!OK"
76
97
  end
77
98
  end
78
99
 
79
- def update_repo(repo, keys)
80
- keys.each do |key|
81
- say "save !txtpur!#{key} "
82
- github.put_secret repo, key, secret_value(key)
83
- say "!txtgrn!OK"
100
+ def update_repo(repo, secrets, dry)
101
+ skipped = 0
102
+
103
+ secrets.each do |key, value|
104
+ say "save !txtpur!#{key} "
105
+ if value
106
+ github.put_secret repo, key, value unless dry
107
+ say "!txtgrn!OK"
108
+ else
109
+ say "!txtred!MISSING"
110
+ skipped += 1
111
+ end
84
112
  end
113
+
114
+ skipped
85
115
  end
86
116
 
87
- def secret_value(key)
88
- ENV[key] || raise(EnvironmentError, "Please set the #{key} environment variable")
117
+ def show_secret(key, value, visible)
118
+ if value
119
+ value = value.obfuscate unless visible
120
+ say " !txtpur!#{key}: !txtcyn!#{value}"
121
+ else
122
+ say " !txtpur!#{key}: !txtred!*MISSING*"
123
+ end
89
124
  end
90
125
 
91
126
  def config_file
@@ -93,12 +128,11 @@ module SecretHub
93
128
  end
94
129
 
95
130
  def config
96
- raise ConfigurationError, "Config file not found #{config_flie}" unless File.exist? config_file
97
- result = YAML.load_file config_file
98
- result.each do |key, value|
99
- raise ConfigurationError, "Invalid repo #{key}" unless key.include? '/'
100
- raise ConfigurationError, "Invalid keys for #{key} - must be an array" unless value.is_a? Array
101
- end
131
+ @config ||= Config.load config_file
132
+ end
133
+
134
+ def config_template
135
+ File.expand_path '../config-template.yml', __dir__
102
136
  end
103
137
  end
104
138
  end
@@ -12,9 +12,9 @@ module SecretHub
12
12
 
13
13
  def run
14
14
  repo = args['REPO']
15
- say "!txtblu!#{repo}"
15
+ say "!txtblu!#{repo}:"
16
16
  github.secrets(repo).each do |secret|
17
- say "!txtpur!#{secret}"
17
+ say "- !txtpur!#{secret}"
18
18
  end
19
19
  end
20
20
  end
@@ -0,0 +1,19 @@
1
+ # Ignored keys
2
+ # Keys that do not include '/' will be ignored
3
+ # Can be used to set some reusable YAML anchors
4
+ docker: &docker
5
+ DOCKER_USER:
6
+ DOCKER_PASSWORD:
7
+
8
+ # Array syntax
9
+ # All secrets must be defined as environment variables
10
+ user/repo:
11
+ - SECRET
12
+ - PASSWORD
13
+
14
+ # Hash syntax
15
+ # Empty secrets will be loaded from environment variables
16
+ user/another-repo:
17
+ <<: *docker
18
+ SECRET:
19
+ PASSWORD: p4ssw0rd
@@ -0,0 +1,49 @@
1
+ require 'yaml'
2
+
3
+ module SecretHub
4
+ class Config
5
+ attr_reader :data
6
+
7
+ def self.load(config_file)
8
+ raise ConfigurationError, "Config file not found #{config_flie}" unless File.exist? config_file
9
+ new YAML.load_file config_file
10
+ end
11
+
12
+ def initialize(data)
13
+ @data = data
14
+ end
15
+
16
+ def to_h
17
+ @to_h ||= to_h!
18
+ end
19
+
20
+ def each(&block)
21
+ to_h.each &block
22
+ end
23
+
24
+ def each_repo(&block)
25
+ to_h.keys.each &block
26
+ end
27
+
28
+ private
29
+
30
+ def to_h!
31
+ result = {}
32
+ data.each do |repo, secrets|
33
+ next unless repo.include? '/'
34
+ result[repo] = resolve_secrets secrets
35
+ end
36
+ result
37
+ end
38
+
39
+ def resolve_secrets(secrets)
40
+ secrets = [] unless secrets
41
+
42
+ if secrets.is_a? Hash
43
+ secrets.map { |key, value| [key, value || ENV[key]] }.to_h
44
+ elsif secrets.is_a? Array
45
+ secrets.map { |key| [key, ENV[key]] }.to_h
46
+ end
47
+ end
48
+ end
49
+ end
@@ -1,7 +1,6 @@
1
1
  module SecretHub
2
2
  SecretHubError = Class.new StandardError
3
3
  ConfigurationError = Class.new SecretHubError
4
- EnvironmentError = Class.new SecretHubError
5
4
 
6
5
  class APIError < SecretHubError
7
6
  attr_reader :response
@@ -76,7 +76,7 @@ module SecretHub
76
76
  end
77
77
 
78
78
  def secret_token
79
- ENV['GITHUB_ACCESS_TOKEN'] || raise(EnvironmentError, "Please set GITHUB_ACCESS_TOKEN")
79
+ ENV['GITHUB_ACCESS_TOKEN'] || raise(ConfigurationError, "Please set GITHUB_ACCESS_TOKEN")
80
80
  end
81
81
 
82
82
  end
@@ -0,0 +1,23 @@
1
+ require 'string-obfuscator'
2
+
3
+ module SecretHub
4
+ module StringObfuscation
5
+ refine String do
6
+ def obfuscate
7
+ text = dup
8
+ trim = false
9
+
10
+ if text.size > 40
11
+ trim = true
12
+ text = text[0..40]
13
+ end
14
+
15
+ result = StringObfuscator.obfuscate text,
16
+ percent: 60,
17
+ min_obfuscated_length: 5
18
+
19
+ trim ? "#{result}..." : result
20
+ end
21
+ end
22
+ end
23
+ end
@@ -1,3 +1,3 @@
1
1
  module SecretHub
2
- VERSION = "0.0.1"
2
+ VERSION = "0.1.4"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: secret_hub
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Danny Ben Shitrit
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-02-14 00:00:00.000000000 Z
11
+ date: 2020-02-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mister_bin
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: '7.1'
83
+ - !ruby/object:Gem::Dependency
84
+ name: string-obfuscator
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.1'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.1'
83
97
  description: Command line interface for managing GitHub secrets in bulk
84
98
  email: db@dannyben.com
85
99
  executables:
@@ -96,8 +110,11 @@ files:
96
110
  - lib/secret_hub/commands/delete.rb
97
111
  - lib/secret_hub/commands/list.rb
98
112
  - lib/secret_hub/commands/save.rb
113
+ - lib/secret_hub/config-template.yml
114
+ - lib/secret_hub/config.rb
99
115
  - lib/secret_hub/exceptions.rb
100
116
  - lib/secret_hub/github_client.rb
117
+ - lib/secret_hub/refinements/string_obfuscation.rb
101
118
  - lib/secret_hub/sodium.rb
102
119
  - lib/secret_hub/version.rb
103
120
  homepage: https://github.com/dannyben/secret_hub