vtk 0.7.0 → 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ad99a9b7f12175a81330df9b6dd29e528e088a934d9ddb4d13532cdc82745b8a
4
- data.tar.gz: 79949c6723be663c804e04e06f8ff8e6a13781b9eda335821fa28f1b73830200
3
+ metadata.gz: 10024b4fc2040cdd70705ce7c5260b16b6b8c5d27a9d2c8476634ce3799d0142
4
+ data.tar.gz: 0edb9d47c87a76ec6d4e2dc2bbfb37df1dfb3a15cf996dfee92530f3b2f917af
5
5
  SHA512:
6
- metadata.gz: 5950052b41123adfda1fb86db4dcb8ba66387b8f743a0b8f80cbea87b20963c4e75e84077addd2f96be7a172305c63c1140869997ed932bf6d30a092f76c1235
7
- data.tar.gz: f290f9c6a3be7c2dd31e45d70568da46ab22d214311e5dfb5845e6432d05f2a4416f62b1fd6ba837ceed49e7882f381130966f5facda0f7e0e01584dcf17420e
6
+ metadata.gz: 88ca8fd76885f2dd527d6ab23595f3fc6323b6fe8b22cd5ba1412cc3d9d5640d5662aa3c9065f0ff664e8e11a647244c2fe9832cbf58028990ed56b26f923084
7
+ data.tar.gz: 06e3698a16e959732bccea4305915043986cb2a7077eed050c76ecf0bfc99f9cd882e621e91f6715b9f4b16bd61dbfaa2f0312a915b9a7dc53f5caa2c4c652cc
data/.rubocop.yml CHANGED
@@ -1,5 +1,8 @@
1
+ inherit_from: .rubocop_todo.yml
2
+
1
3
  AllCops:
2
4
  NewCops: enable
5
+ TargetRubyVersion: 2.5
3
6
 
4
7
  Layout/LineLength:
5
8
  Max: 120
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,12 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2021-08-06 20:18:41 UTC using RuboCop version 1.8.1.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 1
10
+ # Configuration parameters: CountComments, CountAsOne.
11
+ Metrics/ClassLength:
12
+ Max: 405
data/CHANGELOG.md CHANGED
@@ -1,5 +1,37 @@
1
1
  # Changelog
2
2
 
3
+ ## [v0.9.1](https://github.com/department-of-veterans-affairs/vtk/tree/v0.9.1) (2021-08-06)
4
+
5
+ [Full Changelog](https://github.com/department-of-veterans-affairs/vtk/compare/v0.9.0...v0.9.1)
6
+
7
+ **Merged pull requests:**
8
+
9
+ - VTK Socks Setup for Windows \(via WSL\) [\#19](https://github.com/department-of-veterans-affairs/vtk/pull/19) ([ericboehs](https://github.com/ericboehs))
10
+ - Add ops-access-request label to new issue [\#18](https://github.com/department-of-veterans-affairs/vtk/pull/18) ([jeff2d2](https://github.com/jeff2d2))
11
+
12
+ ## [v0.9.0](https://github.com/department-of-veterans-affairs/vtk/tree/v0.9.0) (2021-08-02)
13
+
14
+ [Full Changelog](https://github.com/department-of-veterans-affairs/vtk/compare/v0.8.0...v0.9.0)
15
+
16
+ **Merged pull requests:**
17
+
18
+ - SOCKS Setup Command [\#11](https://github.com/department-of-veterans-affairs/vtk/pull/11) ([ericboehs](https://github.com/ericboehs))
19
+ - Command Analytics [\#8](https://github.com/department-of-veterans-affairs/vtk/pull/8) ([ericboehs](https://github.com/ericboehs))
20
+ - Open Jenkins [\#1](https://github.com/department-of-veterans-affairs/vtk/pull/1) ([cvalarida](https://github.com/cvalarida))
21
+
22
+ ## [v0.8.0](https://github.com/department-of-veterans-affairs/vtk/tree/v0.8.0) (2021-03-01)
23
+
24
+ [Full Changelog](https://github.com/department-of-veterans-affairs/vtk/compare/v0.7.0...v0.8.0)
25
+
26
+ **Merged pull requests:**
27
+
28
+ - Updating name [\#17](https://github.com/department-of-veterans-affairs/vtk/pull/17) ([alexpappasoddball](https://github.com/alexpappasoddball))
29
+ - Made changes to how the arguments are handled [\#15](https://github.com/department-of-veterans-affairs/vtk/pull/15) ([thilton-oddball](https://github.com/thilton-oddball))
30
+
31
+ ## [v0.7.0](https://github.com/department-of-veterans-affairs/vtk/tree/v0.7.0) (2021-03-01)
32
+
33
+ [Full Changelog](https://github.com/department-of-veterans-affairs/vtk/compare/v0.5.0...v0.7.0)
34
+
3
35
  ## [v0.5.0](https://github.com/department-of-veterans-affairs/vtk/tree/v0.5.0) (2021-02-19)
4
36
 
5
37
  [Full Changelog](https://github.com/department-of-veterans-affairs/vtk/compare/v0.4.0...v0.5.0)
@@ -72,10 +104,6 @@
72
104
 
73
105
  [Full Changelog](https://github.com/department-of-veterans-affairs/vtk/compare/79143038509757799edb2bb9be2f925b7d985221...oclif)
74
106
 
75
- **Merged pull requests:**
76
-
77
- - Open Jenkins [\#1](https://github.com/department-of-veterans-affairs/vtk/pull/1) ([cvalarida](https://github.com/cvalarida))
78
-
79
107
 
80
108
 
81
109
  \* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)*
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
- # Platform Developer Toolkit
1
+ # VFS Toolkit
2
2
 
3
- The purpose of this gem is to allow VFS engineers to quickly begin developing on VA.gov. It does this by providing a command line interface that allows the use of simple commands and parameters to do everything from setting up a development environment to building out a directory structure and creating necessary files for separating code into its own module.
3
+ The purpose of this gem is to allow engineers to quickly begin developing on VA.gov. It does this by providing a command line interface that allows the use of simple commands and parameters to do everything from setting up a development environment to building out a directory structure and creating necessary files for separating code into its own module.
4
4
 
5
5
  *The following assumes you have Ruby 2.6.6 or higher installed*
6
6
 
@@ -35,6 +35,25 @@ This above command runs a custom rails generator. For more information see the [
35
35
 
36
36
  Handles connecting to VA network via SOCKS.
37
37
 
38
+ ---
39
+
40
+ ```
41
+ $ vtk socks setup
42
+ ```
43
+
44
+ The **setup subcommand** will do the following:
45
+ - Download the recommended `.ssh/config` if missing.
46
+ - Generate a VA SSH key if missing (and opens the access request form).
47
+ - Add your VA SSH key to your ssh agent and keychain.
48
+ - Test the SOCKS tunnel via SSH and HTTP
49
+ - Configure your system to start the SOCKS tunnel on boot
50
+ - Configure your system proxy for use on VA.gov domains (all other traffic bypasses the proxy).
51
+ - Allow you to troubleshoot your SOCKS connection by running it again.
52
+
53
+ **NOTE**: Running `vtk socks on` and/or `vtk socks off` is not necessary when using `vtk socks setup`.
54
+
55
+ ---
56
+
38
57
  ```
39
58
  $ vtk socks on
40
59
  ----> Connecting...
data/exe/vtk CHANGED
@@ -6,7 +6,7 @@ $LOAD_PATH.unshift(lib_path) unless $LOAD_PATH.include?(lib_path)
6
6
  require 'vtk/cli'
7
7
 
8
8
  Signal.trap('INT') do
9
- warn("\n#{caller.join("\n")}: interrupted")
9
+ warn("\n#{caller.join("\n")}: interrupted") if ENV['DEBUG']
10
10
  exit(1)
11
11
  end
12
12
 
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require 'net/http'
5
+ require 'open-uri'
6
+ require 'uri'
7
+
8
+ module Vtk
9
+ # Provides command analytics to VTK team
10
+ class Analytics
11
+ attr_reader :name, :args, :hostname
12
+
13
+ def initialize(name:, args: nil, hostname: nil)
14
+ @name = name
15
+ @args = args || ARGV.join('_')
16
+ @hostname = hostname || `hostname -f`.chomp
17
+ end
18
+
19
+ def log
20
+ return if ENV['CI'] || ENV['TEST'] || ENV['VTK_DISABLE_ANALYTICS']
21
+
22
+ Process.fork do
23
+ exit unless internet?
24
+
25
+ emit_point
26
+ rescue StandardError
27
+ false # Silently error
28
+ end
29
+ end
30
+
31
+ def emit_point
32
+ uri = URI.parse 'https://dev.va.gov/_vfs/vtk-analytics/record'
33
+ Net::HTTP.start uri.host, uri.port, use_ssl: uri.scheme == 'https' do |http|
34
+ request = Net::HTTP::Post.new uri, 'Content-Type' => 'application/json'
35
+ request.body = { series: [point] }.to_json
36
+ http.request request
37
+ end
38
+ end
39
+
40
+ def point
41
+ {
42
+ metric: 'vtk.command_executed',
43
+ type: 'count',
44
+ interval: 1,
45
+ tags: ["name:#{name}", "args:#{args}"],
46
+ host: hostname,
47
+ points: [[Time.now.utc.to_i, '1']]
48
+ }
49
+ end
50
+
51
+ def internet?
52
+ true if URI.open 'http://www.google.com/'
53
+ rescue SocketError
54
+ false
55
+ end
56
+ end
57
+ end
data/lib/vtk/command.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'forwardable'
4
+ require 'vtk/analytics'
4
5
 
5
6
  module Vtk
6
7
  # Command class that all command inherit from
@@ -9,6 +10,11 @@ module Vtk
9
10
 
10
11
  def_delegators :command, :run
11
12
 
13
+ def initialize
14
+ command_name = self.class.to_s.split('::').last(2).join('_').downcase
15
+ Vtk::Analytics.new(name: command_name).log
16
+ end
17
+
12
18
  # Execute this command
13
19
  #
14
20
  # @api public
@@ -8,6 +8,24 @@ module Vtk
8
8
  class Socks < Thor
9
9
  namespace :socks
10
10
 
11
+ desc 'setup', 'Configures local machine for VA SOCKS access'
12
+ method_option :help, aliases: '-h', type: :boolean,
13
+ desc: 'Display usage information'
14
+ method_option :boot_script_path, type: :string, desc: 'Path to install boot script (e.g. ~/Library)'
15
+ method_option :ssh_key_path, type: :string, desc: 'Path to SSH key (e.g. ~/.ssh/id_rsa_vagov)'
16
+ method_option :ssh_config_path, type: :string, desc: 'Path to SSH config (e.g. ~/.ssh/config)'
17
+ method_option :port, aliases: '-p', type: :string,
18
+ desc: 'Port that SOCKS server is running on'
19
+ method_option :skip_test, type: :boolean, desc: 'Skip testing SOCKS connection'
20
+ def setup(*)
21
+ if options[:help]
22
+ invoke :help, ['setup']
23
+ else
24
+ require_relative 'socks/setup'
25
+ Vtk::Commands::Socks::Setup.new(options).execute
26
+ end
27
+ end
28
+
11
29
  desc 'off', 'Disconnects from VA SOCKS'
12
30
  method_option :help, aliases: '-h', type: :boolean,
13
31
  desc: 'Display usage information'
@@ -50,7 +50,7 @@ module Vtk
50
50
  return output.puts "\r----> Connected to SOCKS."
51
51
  end
52
52
 
53
- output.puts "\r----> ERROR: Could not connect to SOCKS."
53
+ output.puts "\r----> ERROR: Could not connect to SOCKS. Try running `vtk socks setup` first."
54
54
  output.puts "----> Verbose Output from SSH log:\n\n"
55
55
 
56
56
  output.puts File.read '/tmp/socks.log'
@@ -0,0 +1,531 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../command'
4
+ require 'tty-prompt'
5
+ require 'fileutils'
6
+ require 'erb'
7
+
8
+ module Vtk
9
+ module Commands
10
+ class Socks
11
+ # Sets up socks access to the VA network
12
+ class Setup < Vtk::Command
13
+ PROXY_URL = 'https://raw.githubusercontent.com/department-of-veterans-affairs/va.gov-team/master/' \
14
+ 'scripts/socks/proxy.pac'
15
+
16
+ attr_reader :ssh_config_path, :input, :output, :boot_script_path, :ssh_key_path, :prompt, :port, :skip_test
17
+
18
+ def initialize(options)
19
+ @options = options
20
+ @prompt = TTY::Prompt.new interrupt: :exit
21
+ @port = options['port'] || '2001'
22
+ @boot_script_path = options['boot_script_path'] || "#{ENV['HOME']}/Library"
23
+ @ssh_key_path = options['ssh_key_path'] || "#{ENV['HOME']}/.ssh/id_rsa_vagov"
24
+ @ssh_config_path = options['ssh_config_path'] || "#{ENV['HOME']}/.ssh/config"
25
+ @skip_test = options['skip_test'] || false
26
+
27
+ super()
28
+ end
29
+
30
+ def execute(input: $stdin, output: $stdout)
31
+ define_stdin_out_vars input: input, output: output
32
+
33
+ setup_ssh_config
34
+ check_ssh_key
35
+ ssh_agent_add
36
+
37
+ unless @ssh_key_created
38
+ test_ssh_connection unless skip_test
39
+ configure_system_boot
40
+ configure_system_proxy
41
+ end
42
+
43
+ log "SOCKS setup complete. #{'Re-run `vtk socks setup` after your key is approved.' if @ssh_key_created}"
44
+ end
45
+
46
+ private
47
+
48
+ def define_stdin_out_vars(input:, output:)
49
+ @input = input
50
+ @output = output
51
+ end
52
+
53
+ def check_ssh_key
54
+ return true if key_exists? && private_and_public_keys_match?
55
+
56
+ @ssh_key_created = generate_key_and_open_key_access_request
57
+ end
58
+
59
+ def key_exists?
60
+ File.exist? ssh_key_path
61
+ end
62
+
63
+ def private_and_public_keys_match?
64
+ return true unless public_key_exists?
65
+
66
+ pub_key_from_private = `ssh-keygen -y -e -f #{ssh_key_path}`
67
+ pub_key_from_public = `ssh-keygen -y -e -f #{ssh_key_path}.pub`
68
+ return true if pub_key_from_private == pub_key_from_public
69
+
70
+ log "❌ ERROR: #{ssh_key_path}.pub is not the public key for #{ssh_key_path}."
71
+ exit 1
72
+ end
73
+
74
+ def public_key_exists?
75
+ File.exist? "#{ssh_key_path}.pub"
76
+ end
77
+
78
+ def generate_key_and_open_key_access_request
79
+ log 'VA key missing. Generating now...'
80
+ system "ssh-keygen -f #{ssh_key_path} #{'-N ""' if ENV['TEST']}"
81
+
82
+ if prompt.yes?(copy_and_open_gh)
83
+ copy_key_to_clipboard
84
+ open_command access_request_template_url
85
+ else
86
+ key_contents = File.read "#{ssh_key_path}.pub"
87
+ log "Copy this key & submit into the access request form (#{access_request_template_url}):\n#{key_contents}"
88
+ end
89
+ end
90
+
91
+ def copy_key_to_clipboard
92
+ ssh_key_contents = File.read "#{ssh_key_path}.pub"
93
+
94
+ if copy_command
95
+ IO.popen(copy_command, 'w') { |f| f << ssh_key_contents }
96
+ elsif wsl?
97
+ system %(powershell.exe Set-Clipboard -Value "'#{ssh_key_contents}'")
98
+ end
99
+ end
100
+
101
+ def copy_command
102
+ if macos?
103
+ 'pbcopy'
104
+ elsif ubuntu_like? && !wsl?
105
+ system 'sudo apt-get install -y xsel' if `which xsel`.empty?
106
+ 'xsel --clipboard'
107
+ end
108
+ end
109
+
110
+ def open_command(url)
111
+ if macos?
112
+ `open "#{url}"`
113
+ elsif wsl?
114
+ `powershell.exe Start '"#{url}"'`
115
+ elsif ubuntu_like?
116
+ `xdg-open "#{url}"`
117
+ end
118
+ end
119
+
120
+ def access_request_template_url
121
+ 'https://github.com/department-of-veterans-affairs/va.gov-team/issues/new?' \
122
+ 'assignees=&labels=external-request%2C+operations%2C+ops-access-request&' \
123
+ 'template=Environment-Access-Request-Template.md&title=Access+for+%5Bindividual%5D'
124
+ end
125
+
126
+ def copy_and_open_gh
127
+ '----> An SSH key has been created. Would you like to copy the key to your clipboard and open the access ' \
128
+ 'request issue in GitHub now?'
129
+ end
130
+
131
+ def setup_ssh_config
132
+ create_ssh_directory
133
+ install_ssh_config
134
+ configure_ssh_config_with_keychain
135
+ ssh_config_clean_up
136
+ end
137
+
138
+ def install_ssh_config
139
+ return true if ssh_config_configured?
140
+
141
+ if ssh_config_exists? && !prompt.yes?("----> #{pretty_ssh_config_path} incomplete. Backup and replace now?")
142
+ return false
143
+ end
144
+
145
+ log 'Installing SSH config...'
146
+
147
+ download_ssh_config unless File.exist? '/tmp/dova-devops'
148
+ backup_existing_ssh_config
149
+ FileUtils.cp '/tmp/dova-devops/ssh/config', ssh_config_path
150
+ FileUtils.chmod 0o600, "#{File.dirname ssh_config_path}/config"
151
+ end
152
+
153
+ def ssh_config_configured?
154
+ return false unless ssh_config_exists?
155
+
156
+ download_ssh_config
157
+ ssh_config_local = File.read ssh_config_path
158
+ ssh_config = File.read '/tmp/dova-devops/ssh/config'
159
+ ssh_config_local.include? ssh_config
160
+ end
161
+
162
+ def ssh_config_exists?
163
+ File.exist? ssh_config_path
164
+ end
165
+
166
+ def download_ssh_config
167
+ install_git
168
+
169
+ ssh_config_clean_up
170
+
171
+ ssh_agent_add
172
+ system 'git config --global credential.helper > /dev/null || ' \
173
+ "git config --global credential.helper 'cache --timeout=600'"
174
+ cloned = system(
175
+ "git clone --quiet#{' --depth 1' if macos?} --no-checkout --filter=blob:none #{repo_url} '/tmp/dova-devops'"
176
+ )
177
+ exit 1 unless cloned
178
+
179
+ `cd /tmp/dova-devops; git checkout master -- ssh/config`
180
+ end
181
+
182
+ def install_git
183
+ if macos?
184
+ install_brew
185
+ elsif ubuntu_like?
186
+ return true unless `which git`.empty?
187
+
188
+ system 'sudo apt-get install -y git'
189
+ end
190
+ end
191
+
192
+ def install_brew
193
+ return false unless macos?
194
+
195
+ installed = !`which brew`.empty?
196
+ return true if installed
197
+
198
+ log 'Homebrew not installed. Installing now...'
199
+ system '/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"'
200
+ end
201
+
202
+ def ssh_config_clean_up
203
+ FileUtils.rm_rf '/tmp/dova-devops'
204
+ end
205
+
206
+ def repo_url
207
+ @repo_url ||= begin
208
+ keyscan_github_com
209
+
210
+ if github_ssh_configured
211
+ 'git@github.com:department-of-veterans-affairs/devops.git'
212
+ else
213
+ 'https://github.com/department-of-veterans-affairs/devops.git'
214
+ end
215
+ end
216
+ end
217
+
218
+ def keyscan_github_com
219
+ return true if File.exist?('~/.ssh/known_hosts') && !`ssh-keygen -F github.com`.empty?
220
+
221
+ `ssh-keyscan -H github.com >> ~/.ssh/known_hosts 2> /dev/null`
222
+ end
223
+
224
+ def github_ssh_configured
225
+ !`ssh -T git@github.com 2>&1`.include?('Permission denied')
226
+ end
227
+
228
+ def backup_existing_ssh_config
229
+ return true unless ssh_config_exists?
230
+
231
+ if File.exist? "#{ssh_config_path}.bak"
232
+ log "!!! ERROR: Could not make backup of #{pretty_ssh_config_path} as #{pretty_ssh_config_path}.bak " \
233
+ 'exists. Aborting.'
234
+ exit 1
235
+ end
236
+
237
+ FileUtils.mv ssh_config_path, "#{ssh_config_path}.bak"
238
+ end
239
+
240
+ def create_ssh_directory
241
+ ssh_dir = File.dirname ssh_config_path
242
+ FileUtils.mkdir_p ssh_dir
243
+ FileUtils.chmod 0o700, ssh_dir
244
+ end
245
+
246
+ def configure_ssh_config_with_keychain
247
+ return unless macos?
248
+ return if ssh_config_configured_with_keychain?
249
+
250
+ keychain_config = <<~CFG
251
+
252
+ # Maintain SSH keys in macOS Keychain
253
+ Host *
254
+ UseKeychain yes
255
+ AddKeysToAgent yes
256
+ IdentityFile #{pretty_ssh_key_path}
257
+ CFG
258
+
259
+ IO.write ssh_config_path, keychain_config, mode: 'a'
260
+ end
261
+
262
+ def ssh_config_configured_with_keychain?
263
+ return false unless ssh_config_exists?
264
+
265
+ ssh_config_local = File.readlines ssh_config_path
266
+ ssh_config_local.grep(/UseKeychain yes/).any?
267
+ end
268
+
269
+ def ssh_agent_add
270
+ FileUtils.chmod 0o600, ssh_key_path if key_exists?
271
+ FileUtils.chmod 0o600, "#{ssh_key_path}.pub" if public_key_exists?
272
+
273
+ if macos?
274
+ `ssh-add -AK 2> /dev/null; ssh-add -AK #{ssh_key_path} 2> /dev/null`
275
+ elsif ubuntu_like?
276
+ `[ -z "$SSH_AUTH_SOCK" ] && eval "$(ssh-agent -s)";
277
+ ssh-add 2> /dev/null; ssh-add #{ssh_key_path} 2> /dev/null`
278
+ end
279
+ end
280
+
281
+ def test_ssh_connection
282
+ output.print '----> Testing SOCKS SSH connection...'
283
+
284
+ add_ip_to_known_hosts
285
+
286
+ if proxy_running? || ssh_output.include?('This account is currently not available.')
287
+ output.puts ' ✅ DONE'
288
+ else
289
+ check_ssh_error ssh_output
290
+ exit 1
291
+ end
292
+ end
293
+
294
+ def ssh_output
295
+ `ssh -i #{ssh_key_path} -F #{ssh_config_path} -o ConnectTimeout=5 -q socks -D #{port} exit 2>&1`
296
+ end
297
+
298
+ def add_ip_to_known_hosts
299
+ jump_box_ip = `grep -A 2 'Host socks' ~/.ssh/config | grep ProxyCommand | awk '{print $6}'`.chomp
300
+ socks_ip = `grep -A 2 'Host socks' ~/.ssh/config | grep HostName | awk '{print $2}'`.chomp
301
+
302
+ return unless `ssh-keygen -F #{socks_ip}`.empty?
303
+
304
+ `ssh-keyscan -H #{jump_box_ip} >> ~/.ssh/known_hosts 2> /dev/null`
305
+ `ssh -i #{ssh_key_path} dsva@#{jump_box_ip} 'ssh-keyscan -H #{socks_ip}' >> ~/.ssh/known_hosts 2> /dev/null`
306
+ end
307
+
308
+ def check_ssh_error(ssh_output)
309
+ if ssh_output.include? 'Permission denied (publickey)'
310
+ output.puts '⚠️ WARN: SSH key is not approved yet. Once it is, re-run `vtk socks setup`.'
311
+ copy_key_to_clipboard if prompt.yes? 'Would you like to copy your VA public key to your clipboard again?'
312
+ else
313
+ ssh_command = "ssh -i #{ssh_key_path} -F #{ssh_config_path} -o ConnectTimeout=5 -vvv socks -D #{port} -N"
314
+ output.puts ' ❌ ERROR: SSH Connection to SOCKS server unsuccessful. Error message:'
315
+ output.puts ssh_command
316
+ output.puts `#{ssh_command}`
317
+ end
318
+ end
319
+
320
+ def configure_system_boot
321
+ log 'Configuring SOCKS tunnel to run on system boot...' do
322
+ if wsl?
323
+ wsl_configure_system_boot && wsl_start_socks_proxy
324
+ else
325
+ install_autossh && (install_launch_agent || install_systemd_service)
326
+ end
327
+ end
328
+ end
329
+
330
+ def wsl_configure_system_boot
331
+ return true if File.exist? socks_bat
332
+
333
+ IO.write socks_bat, 'wsl nohup bash -c "/usr/bin/ssh socks -N &" < nul > nul 2>&1', mode: 'a'
334
+ end
335
+
336
+ def socks_bat
337
+ "#{socks_bat_dir}/gov.va.socks.bat"
338
+ end
339
+
340
+ def socks_bat_dir
341
+ profile_path = `wslpath "$(wslvar USERPROFILE)"`.chomp
342
+ "#{profile_path}/AppData/Roaming/Microsoft/Windows/Start Menu/Programs/Startup"
343
+ end
344
+
345
+ def wsl_start_socks_proxy
346
+ return true if proxy_running?
347
+
348
+ system "cd '#{socks_bat_dir}'; cmd.exe /c gov.va.socks.bat > /dev/null"
349
+ end
350
+
351
+ def proxy_running?
352
+ system("lsof -i:#{port}", out: '/dev/null') || system('lsof -nP | grep ssh | grep -q sock')
353
+ end
354
+
355
+ def launch_agent_label
356
+ @launch_agent_label ||= begin
357
+ launch_agent_label = 'gov.va.socks'
358
+ launch_agent_label += "-test-#{rand 1000}" if ENV['TEST'] == 'test'
359
+ launch_agent_label
360
+ end
361
+ end
362
+
363
+ def install_autossh
364
+ installed = !`which autossh`.empty?
365
+ return true if installed
366
+
367
+ if macos?
368
+ system 'brew install autossh'
369
+ elsif ubuntu_like?
370
+ system 'sudo apt-get install -y autossh'
371
+ end
372
+ end
373
+
374
+ def install_launch_agent
375
+ return false unless macos?
376
+
377
+ unless File.exist? "#{boot_script_path}/LaunchAgents/gov.va.socks.plist"
378
+ FileUtils.mkdir_p "#{boot_script_path}/Logs/gov.va.socks"
379
+ FileUtils.mkdir_p "#{boot_script_path}/LaunchAgents"
380
+
381
+ write_launch_agent
382
+ end
383
+
384
+ system "launchctl unload #{boot_script_path}/LaunchAgents/gov.va.socks.plist 2> /dev/null"
385
+ system "launchctl load -w #{boot_script_path}/LaunchAgents/gov.va.socks.plist"
386
+ end
387
+
388
+ def write_launch_agent
389
+ erb_template = File.read File.realpath "#{__dir__}/../../templates/socks/setup/gov.va.socks.plist.erb"
390
+ erb = ERB.new erb_template
391
+ launch_agent_contents = erb.result(
392
+ launch_agent_variables.instance_eval { binding }
393
+ )
394
+ File.write "#{boot_script_path}/LaunchAgents/gov.va.socks.plist", launch_agent_contents
395
+ end
396
+
397
+ def launch_agent_variables
398
+ OpenStruct.new(
399
+ label: launch_agent_label,
400
+ autossh_path: `which autossh`.chomp,
401
+ port: @port,
402
+ boot_script_path: File.realpath(boot_script_path),
403
+ user: ENV['USER']
404
+ )
405
+ end
406
+
407
+ def install_systemd_service
408
+ return false unless ubuntu_like?
409
+
410
+ write_systemd_service unless File.exist? '/etc/systemd/system/va_gov_socks.service'
411
+
412
+ system 'sudo systemctl daemon-reload'
413
+ system 'sudo systemctl enable va_gov_socks'
414
+ system 'sudo systemctl start va_gov_socks'
415
+ end
416
+
417
+ def write_systemd_service
418
+ erb_template = File.read File.realpath "#{__dir__}/../../templates/socks/setup/va_gov_socks.service.erb"
419
+ erb = ERB.new erb_template
420
+ systemd_service_contents = erb.result(
421
+ systemd_service_variables.instance_eval { binding }
422
+ )
423
+ File.write '/tmp/va_gov_socks.service', systemd_service_contents
424
+ system 'sudo mv /tmp/va_gov_socks.service /etc/systemd/system/va_gov_socks.service'
425
+ end
426
+
427
+ def systemd_service_variables
428
+ OpenStruct.new(
429
+ autossh_path: `which autossh`.chomp,
430
+ port: @port,
431
+ ssh_key_path: ssh_key_path,
432
+ user: ENV['USER']
433
+ )
434
+ end
435
+
436
+ def configure_system_proxy
437
+ return log 'Skipping system proxy configuration as custom --port was used.' unless port == '2001'
438
+
439
+ if macos?
440
+ mac_configure_system_proxy
441
+ elsif wsl?
442
+ wsl_configure_system_proxy
443
+ elsif ubuntu_like?
444
+ ubuntu_configure_system_proxy
445
+ end
446
+ end
447
+
448
+ def mac_configure_system_proxy
449
+ return true if mac_system_proxy_already_configured?
450
+
451
+ log 'Configuring system proxy to use SOCKS tunnel...' do
452
+ network_interfaces.map do |network_interface|
453
+ system %(networksetup -setautoproxyurl "#{network_interface}" "#{PROXY_URL}")
454
+ end.all?
455
+ end
456
+ end
457
+
458
+ def ubuntu_configure_system_proxy
459
+ return true if `gsettings get org.gnome.system.proxy mode` == "'auto'\n"
460
+
461
+ log 'Configuring system proxy to use SOCKS tunnel...' do
462
+ `gsettings set org.gnome.system.proxy mode 'auto'` &&
463
+ `gsettings set org.gnome.system.proxy autoconfig-url "#{PROXY_URL}"`
464
+ end
465
+ end
466
+
467
+ def wsl_configure_system_proxy
468
+ log 'Configuring system proxy to use SOCKS tunnel...' do
469
+ reg_key = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings'
470
+ `powershell.exe Set-ItemProperty -path "'#{reg_key}'" AutoConfigURL -Value "'#{PROXY_URL}'"`
471
+ end
472
+ end
473
+
474
+ def mac_system_proxy_already_configured?
475
+ network_interfaces.map do |network_interface|
476
+ output = `networksetup -getautoproxyurl "#{network_interface}"`
477
+ output == "URL: #{PROXY_URL}\nEnabled: Yes\n"
478
+ end.all?
479
+ end
480
+
481
+ def network_interfaces
482
+ @network_interfaces ||= begin
483
+ `networksetup -listallnetworkservices`.split("\n").drop(1).select do |network_interface|
484
+ `networksetup -getautoproxyurl "#{network_interface}"`.start_with?('URL: (null)')
485
+ end
486
+ end
487
+ end
488
+
489
+ def macos?
490
+ RUBY_PLATFORM.include? 'darwin'
491
+ end
492
+
493
+ def wsl?
494
+ @wsl ||= File.exist?('/proc/version') && File.open('/proc/version').grep(/Microsoft/i).any?
495
+ end
496
+
497
+ def ubuntu_like?
498
+ return false if `which apt-get`.empty? && `which gsettings`.empty?
499
+
500
+ true
501
+ end
502
+
503
+ def pretty_ssh_config_path
504
+ pretty_path ssh_config_path
505
+ end
506
+
507
+ def pretty_ssh_key_path
508
+ pretty_path ssh_key_path
509
+ end
510
+
511
+ def pretty_path(path)
512
+ path.gsub ENV['HOME'], '~'
513
+ end
514
+
515
+ def log(message)
516
+ if block_given?
517
+ output.print "----> #{message}"
518
+
519
+ return_value = yield
520
+
521
+ output.puts return_value ? ' ✅ DONE' : ' ❌ FAIL'
522
+
523
+ return_value
524
+ else
525
+ output.puts "----> #{message}"
526
+ end
527
+ end
528
+ end
529
+ end
530
+ end
531
+ end
@@ -0,0 +1 @@
1
+ #
@@ -0,0 +1,35 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>Label</key>
6
+ <string><%= label %></string>
7
+
8
+ <key>RunAtLoad</key>
9
+ <true/>
10
+
11
+ <key>ProgramArguments</key>
12
+ <array>
13
+ <string><%= autossh_path %></string>
14
+ <string>-v</string>
15
+ <string>-M</string>
16
+ <string>0</string>
17
+ <string>-D</string>
18
+ <string><%= port %></string>
19
+ <string>socks</string>
20
+ <string>-N</string>
21
+ </array>
22
+
23
+ <key>StandardOutPath</key>
24
+ <string><%= boot_script_path %>/Logs/gov.va.socks/autossh.stdout</string>
25
+
26
+ <key>StandardErrorPath</key>
27
+ <string><%= boot_script_path %>/Logs/gov.va.socks/autossh.stderr</string>
28
+
29
+ <key>User</key>
30
+ <string><%= user %></string>
31
+
32
+ <key>ThrottleInterval</key>
33
+ <integer>30</integer>
34
+ </dict>
35
+ </plist>
@@ -0,0 +1,12 @@
1
+ [Unit]
2
+ Description=VA SOCKS Tunnel
3
+ After=network.target
4
+
5
+ [Service]
6
+ Environment="AUTOSSH_GATETIME=0"
7
+ ExecStart=<%= autossh_path %> -v -M 0 -D <%= port %> -i <%= ssh_key_path %> socks -N
8
+ Restart=always
9
+ User=<%= user %>
10
+
11
+ [Install]
12
+ WantedBy=multi-user.target
data/lib/vtk/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Vtk
4
- VERSION = '0.7.0'
4
+ VERSION = '0.9.2'
5
5
  end
data/vtk.gemspec CHANGED
@@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
12
12
  spec.summary = 'A CLI for the platform'
13
13
  spec.description = 'This is a platform CLI tool for VFS developer usage.'
14
14
  spec.homepage = 'https://github.com/department-of-veterans-affairs/vtk'
15
- spec.required_ruby_version = Gem::Requirement.new('>= 2.4.0')
15
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.5.0')
16
16
 
17
17
  spec.metadata['homepage_uri'] = spec.homepage
18
18
  spec.metadata['documentation_uri'] = spec.homepage
@@ -29,12 +29,14 @@ Gem::Specification.new do |spec|
29
29
  spec.require_paths = ['lib']
30
30
 
31
31
  spec.add_dependency 'thor', '> 0.20.3'
32
+ spec.add_dependency 'tty-command', '~> 0.10.0'
33
+ spec.add_dependency 'tty-prompt', '~> 0.23.0'
32
34
 
33
35
  spec.add_development_dependency 'github_changelog_generator', '~> 1.15.0'
34
36
  spec.add_development_dependency 'pry', '~> 0.13.0'
35
37
  spec.add_development_dependency 'rake', '~> 13.0.0'
36
38
  spec.add_development_dependency 'rspec', '~> 3.10.0'
37
- spec.add_development_dependency 'rubocop', '~> 1.6.0'
39
+ spec.add_development_dependency 'rubocop', '~> 1.8.0'
38
40
  spec.add_development_dependency 'rubocop-rake', '~> 0.5.0'
39
41
  spec.add_development_dependency 'rubocop-rspec', '~> 2.0.0'
40
42
 
metadata CHANGED
@@ -1,16 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vtk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.9.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eric Boehs
8
8
  - Lindsey Hattamer
9
9
  - Travis Hilton
10
- autorequire:
10
+ autorequire:
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2021-03-01 00:00:00.000000000 Z
13
+ date: 2021-08-11 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: thor
@@ -26,6 +26,34 @@ dependencies:
26
26
  - - ">"
27
27
  - !ruby/object:Gem::Version
28
28
  version: 0.20.3
29
+ - !ruby/object:Gem::Dependency
30
+ name: tty-command
31
+ requirement: !ruby/object:Gem::Requirement
32
+ requirements:
33
+ - - "~>"
34
+ - !ruby/object:Gem::Version
35
+ version: 0.10.0
36
+ type: :runtime
37
+ prerelease: false
38
+ version_requirements: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - "~>"
41
+ - !ruby/object:Gem::Version
42
+ version: 0.10.0
43
+ - !ruby/object:Gem::Dependency
44
+ name: tty-prompt
45
+ requirement: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: 0.23.0
50
+ type: :runtime
51
+ prerelease: false
52
+ version_requirements: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - "~>"
55
+ - !ruby/object:Gem::Version
56
+ version: 0.23.0
29
57
  - !ruby/object:Gem::Dependency
30
58
  name: github_changelog_generator
31
59
  requirement: !ruby/object:Gem::Requirement
@@ -88,14 +116,14 @@ dependencies:
88
116
  requirements:
89
117
  - - "~>"
90
118
  - !ruby/object:Gem::Version
91
- version: 1.6.0
119
+ version: 1.8.0
92
120
  type: :development
93
121
  prerelease: false
94
122
  version_requirements: !ruby/object:Gem::Requirement
95
123
  requirements:
96
124
  - - "~>"
97
125
  - !ruby/object:Gem::Version
98
- version: 1.6.0
126
+ version: 1.8.0
99
127
  - !ruby/object:Gem::Dependency
100
128
  name: rubocop-rake
101
129
  requirement: !ruby/object:Gem::Requirement
@@ -139,6 +167,7 @@ files:
139
167
  - ".gitignore"
140
168
  - ".rspec"
141
169
  - ".rubocop.yml"
170
+ - ".rubocop_todo.yml"
142
171
  - ".tool-versions"
143
172
  - CHANGELOG.md
144
173
  - Gemfile
@@ -150,6 +179,7 @@ files:
150
179
  - docs/design-doc.md
151
180
  - exe/vtk
152
181
  - lib/vtk.rb
182
+ - lib/vtk/analytics.rb
153
183
  - lib/vtk/cli.rb
154
184
  - lib/vtk/command.rb
155
185
  - lib/vtk/commands/.gitkeep
@@ -162,8 +192,12 @@ files:
162
192
  - lib/vtk/commands/socks.rb
163
193
  - lib/vtk/commands/socks/off.rb
164
194
  - lib/vtk/commands/socks/on.rb
195
+ - lib/vtk/commands/socks/setup.rb
165
196
  - lib/vtk/templates/.gitkeep
166
197
  - lib/vtk/templates/module/add/.gitkeep
198
+ - lib/vtk/templates/socks/setup/.gitkeep
199
+ - lib/vtk/templates/socks/setup/gov.va.socks.plist.erb
200
+ - lib/vtk/templates/socks/setup/va_gov_socks.service.erb
167
201
  - lib/vtk/version.rb
168
202
  - vtk.gemspec
169
203
  homepage: https://github.com/department-of-veterans-affairs/vtk
@@ -174,7 +208,7 @@ metadata:
174
208
  documentation_uri: https://github.com/department-of-veterans-affairs/vtk
175
209
  source_code_uri: https://github.com/department-of-veterans-affairs/vtk
176
210
  changelog_uri: https://github.com/department-of-veterans-affairs/vtk/blob/master/CHANGELOG.md
177
- post_install_message:
211
+ post_install_message:
178
212
  rdoc_options: []
179
213
  require_paths:
180
214
  - lib
@@ -182,15 +216,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
182
216
  requirements:
183
217
  - - ">="
184
218
  - !ruby/object:Gem::Version
185
- version: 2.4.0
219
+ version: 2.5.0
186
220
  required_rubygems_version: !ruby/object:Gem::Requirement
187
221
  requirements:
188
222
  - - ">="
189
223
  - !ruby/object:Gem::Version
190
224
  version: '0'
191
225
  requirements: []
192
- rubygems_version: 3.0.3
193
- signing_key:
226
+ rubygems_version: 3.2.1
227
+ signing_key:
194
228
  specification_version: 4
195
229
  summary: A CLI for the platform
196
230
  test_files: []