secret_hub 0.1.1 → 0.1.6

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: ce4f4c239e9593aa02e1236120dfbcaf2546f6fe36364aab50200cf40b2166f8
4
- data.tar.gz: f5ebb5db5db52d32fba5c07136444beadd348f1be4e9dd43af44682881bc1007
3
+ metadata.gz: e7f29f7f724bd83bc5b9899c90248279f9997bfe5e9e5c5a09f37af679faad12
4
+ data.tar.gz: 9d8ffac16034c077d0c9f497e919aae03c8673b32e09afdbae0fbf9e08c76ad4
5
5
  SHA512:
6
- metadata.gz: 5492dca43f4c9eab988e47e0a06889ca5541113bd3ad3551a5c0adb68231c0647bf600d858e135c515e8ade1925115e65578497463cbea60c00fc47e01cc1bf9
7
- data.tar.gz: bef918bb30a0eaf1e6ddd0774652c4b9a8355b88a91bf084bb18702fc4c88bf11812e33000a4a83577641718e324587792a54dfe4bcdf92e69418f48add0bb0a
6
+ metadata.gz: 85bf36c96fe639fdf512a4332cc179ad385009ba06800db5b0aa27a0e92a8dcef8a1dc37af1431d58a94fa921b6bf7b26e58ac826b6f48ab0b2a4dd4e1a70ae1
7
+ data.tar.gz: 7bd79637ed41dc098098ff42e00226e1c424f1fd711d7ef6ba905a442e57d2052116fc6127f19861b46cbf49b917721e5ded32619e5d89822539495e0d65edbd
data/README.md CHANGED
@@ -41,38 +41,45 @@ SecretHub has two families of commands:
41
41
  1. Commands that operate on a single repository.
42
42
  2. Commands that operate on multiple repositories, and multiple secrets.
43
43
 
44
- ### Single repository operations
44
+ Most commands are self explanatory, and described by the CLI.
45
45
 
46
- #### Show the secret keys in a repository
46
+ ```shell
47
+ $ secrethub --help
48
+ ```
49
+
50
+ Single repository operations
51
+ --------------------------------------------------
52
+
53
+ ### Show the secret keys in a repository
47
54
 
48
55
  ```shell
49
56
  # secrethub list REPO
50
57
  $ secrethub list you/your-repo
51
58
  ```
52
59
 
53
- #### Create or update a secret in a repository
60
+ ### Create or update a secret in a repository
54
61
 
55
62
  ```shell
56
63
  # secrethub save REPO KEY VALUE
57
64
  $ secrethub list you/your-repo SECRET "there is no spoon"
58
65
  ```
59
66
 
60
- #### Delete a secret from a repository
67
+ ### Delete a secret from a repository
61
68
 
62
69
  ```shell
63
70
  # secrethub delete REPO KEY
64
- $ secrethub list you/your-repo SECRET
71
+ $ secrethub delete you/your-repo SECRET
65
72
  ```
66
73
 
67
- ### Bulk operations
68
74
 
69
- All the bulk operations function by:
75
+ Bulk operations
76
+ --------------------------------------------------
70
77
 
71
- 1. Having a config file specifying the list of repositories, and their
72
- expected secret keys.
73
- 2. Having all the secrets set up as environment variables.
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.
74
81
 
75
- A typical config file looks like this:
82
+ For example:
76
83
 
77
84
  ```yaml
78
85
  # secrethub.yml
@@ -86,24 +93,74 @@ user/another-repo:
86
93
  - SECRET_KEY
87
94
  ```
88
95
 
89
- #### Create a sample configuration file
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/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
90
140
 
91
141
  ```shell
92
142
  # secrethub bulk init [CONFIG]
93
143
  $ secrethub bulk init mysecrets.yml
94
144
  ```
95
145
 
96
- #### Show all secrets in all repositories
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
97
154
 
98
155
  ```shell
99
156
  # secrethub bulk list [CONFIG]
100
157
  $ secrethub bulk list mysecrets.yml
101
158
  ```
102
159
 
103
- #### Save multiple secrets to multiple repositories
160
+ ### Save multiple secrets to multiple repositories
104
161
 
105
162
  ```shell
106
- # secrethub bulk save [CONFIG --clean]
163
+ # secrethub bulk save [CONFIG --clean --dry --only REPO]
107
164
  $ secrethub bulk save mysecrets.yml --clean
108
165
  ```
109
166
 
@@ -111,7 +168,7 @@ Using the `--clean` flag, you can ensure that the repositories do not have
111
168
  any secrets that you are unaware of. This flag will delete any secret that is
112
169
  not specified in your config file.
113
170
 
114
- #### Delete secrets from multiple repositories unless they are specified in the config file
171
+ ### Delete secrets from multiple repositories unless they are specified in the config file
115
172
 
116
173
  ```shell
117
174
  # secrethub bulk clean [CONFIG]
@@ -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']
@@ -9,7 +9,8 @@ module SecretHub
9
9
  class CLI
10
10
  def self.router
11
11
  router = MisterBin::Runner.new version: VERSION,
12
- header: "GitHub Secret Manager"
12
+ header: "GitHub Secret Manager",
13
+ footer: "Run !txtpur!secrethub COMMAND --help!txtrst! for command specific help"
13
14
 
14
15
  router.route 'list', to: Commands::List
15
16
  router.route 'save', to: Commands::Save
@@ -1,45 +1,58 @@
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]"
12
+ usage "secrethub bulk show [CONFIG --visible]"
9
13
  usage "secrethub bulk list [CONFIG]"
10
- usage "secrethub bulk save [CONFIG --clean]"
11
- usage "secrethub bulk clean [CONFIG]"
14
+ usage "secrethub bulk save [CONFIG --clean --dry --only REPO]"
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"
27
+ option "-o, --only REPO", "Save all secrets to a single repository from the configuration file"
20
28
 
21
29
  param "CONFIG", "Path to the configuration file [default: secrethub.yml]"
22
30
 
23
31
  example "secrethub bulk init"
32
+ example "secrethub bulk show --visible"
24
33
  example "secrethub bulk clean"
25
34
  example "secrethub bulk list mysecrets.yml"
26
- example "secrethub bulk save mysecrets.yml"
35
+ example "secrethub bulk save mysecrets.yml --dry"
27
36
  example "secrethub bulk save --clean"
37
+ example "secrethub bulk save --only me/my-important-repo"
28
38
 
29
39
  def init_command
30
40
  raise SecretHubError, "File #{config_file} already exists" if File.exist? config_file
31
-
32
- content = {
33
- "user/repo" => %w[SECRET PASSWORD SECRET_KEY],
34
- "user/another-repo" => %w[SECRET SECRET_KEY],
35
- }
36
-
37
- File.write config_file, content.to_yaml
41
+ FileUtils.cp config_template, config_file
38
42
  say "!txtgrn!Saved #{config_file}"
39
43
  end
40
44
 
45
+ def show_command
46
+ config.each do |repo, secrets|
47
+ say "!txtblu!#{repo}:"
48
+ secrets.each do |key, value|
49
+ show_secret key, value, args['--visible']
50
+ end
51
+ end
52
+ end
53
+
41
54
  def list_command
42
- config.each do |repo, keys|
55
+ config.each_repo do |repo|
43
56
  say "!txtblu!#{repo}:"
44
57
  github.secrets(repo).each do |secret|
45
58
  say "- !txtpur!#{secret}"
@@ -48,45 +61,70 @@ module SecretHub
48
61
  end
49
62
 
50
63
  def save_command
51
- clean = args['--clean']
64
+ dry = args['--dry']
65
+ only = args['--only']
66
+ skipped = 0
52
67
 
53
- config.each do |repo, keys|
68
+ config.each do |repo, secrets|
69
+ next if only and repo != only
54
70
  say "!txtblu!#{repo}"
55
- update_repo repo, keys
56
- clean_repo repo, keys if clean
71
+ skipped += update_repo repo, secrets, dry
72
+ clean_repo repo, secrets.keys, dry if args['--clean']
57
73
  end
74
+
75
+ puts "\n" if skipped > 0 or dry
76
+ say "Skipped #{skipped} missing secrets" if skipped > 0
77
+ say "Dry run, nothing happened" if dry
58
78
  end
59
79
 
60
80
  def clean_command
61
- config.each do |repo, keys|
81
+ dry = args['--dry']
82
+
83
+ config.each do |repo, secrets|
62
84
  say "!txtblu!#{repo}"
63
- clean_repo repo, keys
85
+ clean_repo repo, secrets.keys, dry
64
86
  end
87
+
88
+ say "\nDry run, nothing happened" if dry
65
89
  end
66
90
 
67
91
  private
68
92
 
69
- def clean_repo(repo, keys)
93
+ def clean_repo(repo, keys, dry)
70
94
  repo_keys = github.secrets repo
71
95
  delete_candidates = repo_keys - keys
72
96
 
73
97
  delete_candidates.each do |key|
74
- say "delete !txtpur!#{key} "
75
- success = github.delete_secret repo, key
98
+ say "delete !txtpur!#{key} "
99
+ github.delete_secret repo, key unless dry
76
100
  say "!txtgrn!OK"
77
101
  end
78
102
  end
79
103
 
80
- def update_repo(repo, keys)
81
- keys.each do |key|
82
- say "save !txtpur!#{key} "
83
- github.put_secret repo, key, secret_value(key)
84
- say "!txtgrn!OK"
104
+ def update_repo(repo, secrets, dry)
105
+ skipped = 0
106
+
107
+ secrets.each do |key, value|
108
+ say "save !txtpur!#{key} "
109
+ if value
110
+ github.put_secret repo, key, value unless dry
111
+ say "!txtgrn!OK"
112
+ else
113
+ say "!txtred!MISSING"
114
+ skipped += 1
115
+ end
85
116
  end
117
+
118
+ skipped
86
119
  end
87
120
 
88
- def secret_value(key)
89
- ENV[key] || raise(EnvironmentError, "Please set the #{key} environment variable")
121
+ def show_secret(key, value, visible)
122
+ if value
123
+ value = value.obfuscate unless visible
124
+ say " !txtpur!#{key}: !txtcyn!#{value}"
125
+ else
126
+ say " !txtpur!#{key}: !txtred!*MISSING*"
127
+ end
90
128
  end
91
129
 
92
130
  def config_file
@@ -94,9 +132,11 @@ module SecretHub
94
132
  end
95
133
 
96
134
  def config
97
- raise ConfigurationError, "Config file not found #{config_flie}" unless File.exist? config_file
98
- result = YAML.load_file config_file
99
- result.transform_values { |v| v || [] }
135
+ @config ||= Config.load config_file
136
+ end
137
+
138
+ def config_template
139
+ File.expand_path '../config-template.yml', __dir__
100
140
  end
101
141
  end
102
142
  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_file}" 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.1.1"
2
+ VERSION = "0.1.6"
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.1.1
4
+ version: 0.1.6
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-15 00:00:00.000000000 Z
11
+ date: 2020-04-17 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