ndr_dev_support 6.1.4 → 6.1.7

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: 665f148ac622b9f75c0150d8b1d6770aaeaaf5c9d1bb561c5a1d34a3f9b8bf2d
4
- data.tar.gz: af2bd48cfef10426450978b40071f134d40af2524edec37cf380b5ffa820a409
3
+ metadata.gz: 5fe8e3400612fc7c12992a9ed37a1896cc2345ef9d060638776ad5f3f5f2c2e1
4
+ data.tar.gz: 229b4288c7f789407821bea03feaf6bf0512b5628d51d1a69fd8f8febdcacb6d
5
5
  SHA512:
6
- metadata.gz: 706873fa19d231e950bec7f26a74946a5c19d9d594930b5fe6b64e0b4be12545254b2371c82067a7ed0b420153ac050f449980c84c3eb15b8a2a58940e6a64ab
7
- data.tar.gz: a20045257bbd629bca137e8b8724549836c2c484e05d1074b245dbdf56c607608cfd572141619c4bfe18786ae8645581ebe6777ed0068bd849e1bb8d97d95306
6
+ metadata.gz: 1edfdb2328f91d2fb3707b1f6e1b8b70f48cf4bae5037a1bea01398192a079912d063842bd45a88b748fb6522e6c6b5593336584e7bad3a0e2c91e0ff539fcb5
7
+ data.tar.gz: 687c9637cc0c9d1dae203b242393f91c44fc7817719fb9e0fbe43bb8ea9b545918ee45850f0f2f2d8186858a72ef807416ef2006fd8cf7f8b2533b5987596c74
data/CHANGELOG.md CHANGED
@@ -1,6 +1,18 @@
1
1
  ## [Unreleased]
2
2
  * No unreleased changes
3
3
 
4
+ ## 6.1.7 / 2022-07-15
5
+ ### Added
6
+ * Add `cd:credentials` rake task for continuous deployment of credentials
7
+
8
+ ## 6.1.6 / 2022-07-01
9
+ ### Added
10
+ * capistrano: use DEPLOYER environment variable for non-interactive deployments
11
+
12
+ ## 6.1.5 / 2022-06-24
13
+ ### Fixed
14
+ * audit:code should allow special characters in filenames
15
+
4
16
  ## 6.1.4 / 2022-06-16
5
17
  ### Added
6
18
  * Add warning when upgrading webpacker
@@ -30,6 +30,8 @@ require_relative 'sysadmin_scripts'
30
30
  # and SVN branches. To use the latter, be sure to set the `:repository_branches` variable
31
31
  # to point at the root of the branches. Otherwise, just set `:repository` directly as normal.
32
32
  #
33
+ # Set environment variable DEPLOYER to deploy as a particular user instead of prompting.
34
+ #
33
35
  Capistrano::Configuration.instance(:must_exist).load do
34
36
  # Paths that are symlinked for each release to the "shared" directory:
35
37
  set :shared_paths, %w[config/database.yml config/secrets.yml log tmp]
@@ -94,9 +96,14 @@ Capistrano::Configuration.instance(:must_exist).load do
94
96
 
95
97
  # Gather SSH credentials: (password is asked for by Net::SSH, if needed)
96
98
  set :use_sudo, false
97
- set :user, Capistrano::CLI.ui.ask('Deploy as: ')
99
+ if ENV['DEPLOYER']
100
+ set :user, ENV['DEPLOYER']
101
+ Capistrano::CLI.ui.say "Deploy as: #{fetch(:user)}"
102
+ else
103
+ set :user, Capistrano::CLI.ui.ask('Deploy as: ')
104
+ end
98
105
 
99
- # If no alternate user is specified, deploy to the crediental-holding user.
106
+ # If no alternate user is specified, deploy to the credential-holding user.
100
107
  set :application_user, fetch(:user) unless fetch(:application_user)
101
108
 
102
109
  # The home folder of the application user:
@@ -0,0 +1,157 @@
1
+ require 'English'
2
+ require_relative 'stoppable'
3
+ require 'ndr_dev_support/slack_message_publisher'
4
+ require 'shellwords'
5
+ require 'with_clean_rbenv'
6
+
7
+ module NdrDevSupport
8
+ module Daemon
9
+ # Wrapper around Capistrano based Continuous Deployment of application credentials
10
+ #
11
+ # Assumes there is a capistrano task "app:update_secrets" which can be used together
12
+ # with a target name, e.g. cap target app:update_secrets
13
+ # to update a capistrano target with secrets / credentials from one or more repositories.
14
+ # To use this daemon, a number of environment variables need to be set
15
+ # including CD_TARGETS and CD_URLS.
16
+ class CDCredentials
17
+ include Stoppable
18
+
19
+ def self.from_args(env)
20
+ name = env['WORKER_NAME'].to_s
21
+ cd_targets = env['CD_TARGETS'].to_s.split
22
+ cd_urls = env['CD_URLS'].to_s.split
23
+
24
+ new(name: name, cd_targets: cd_targets, cd_urls: cd_urls)
25
+ end
26
+
27
+ def initialize(name:, cd_targets:, cd_urls:)
28
+ super
29
+
30
+ # Worker name can be used for clear logging:
31
+ @name = name
32
+ raise ArgumentError, 'No WORKER_NAME specified!' if name.blank?
33
+
34
+ # Capistrano targets to use for deployments
35
+ @cd_targets = cd_targets
36
+ raise ArgumentError, 'No CD_TARGETS specified!' unless cd_targets&.present?
37
+
38
+ # URLs to watch for continuous deployment
39
+ @cd_urls = cd_urls
40
+ raise ArgumentError, 'No CD_URLS specified!' unless cd_urls&.present?
41
+ end
42
+
43
+ private
44
+
45
+ def run_once
46
+ log('running once...')
47
+
48
+ # Keep state, watch repositories for changes, maybe save state to disk?
49
+ if (revisions = check_for_new_revisions)
50
+ log("deploying with revisions #{revisions}...")
51
+ deploy_credentials # should also notify slack if any changes deployed, but not
52
+ else
53
+ log('nothing new to deploy')
54
+ end
55
+ log('completed single run.')
56
+ rescue => e
57
+ log(<<~MSG)
58
+ Unhandled exception! #{e.class}: #{e.message}
59
+ #{(e.backtrace || []).join("\n")}
60
+ MSG
61
+
62
+ raise e
63
+ end
64
+
65
+ # Check for new revisions, and cache the latest one.
66
+ # If there are new revisions in the repositories available since the last check,
67
+ # return a hash of repo -> latest revision
68
+ # If no revisions have changed, returns nil
69
+ def check_for_new_revisions
70
+ # TODO: implement this, by checking for updates to @cd_urls
71
+ # Stub implementation, pretends things always changed
72
+ { 'dummy_repo' => '0' }
73
+ end
74
+
75
+ # Deploy credentials to all targets. Should also notify slack if any changes deployed
76
+ def deploy_credentials
77
+ log("Deploying to #{@cd_targets.join(', ')}...")
78
+ @changed_targets = []
79
+ @unchanged_targets = []
80
+ @failed_targets = []
81
+ @cd_targets.each do |target|
82
+ deploy_to_target(target)
83
+ end
84
+ publish_results
85
+ end
86
+
87
+ # Deploy credentials to a single target.
88
+ def deploy_to_target(target)
89
+ WithCleanRbenv.with_clean_rbenv do
90
+ results = `rbenv exec bundle exec cap #{Shellwords.escape(target)} \
91
+ app:update_secrets < /dev/null`.split("\n")
92
+ puts results
93
+ if $CHILD_STATUS.exitstatus.zero?
94
+ if results.include?('No changed secret files to upload')
95
+ @unchanged_targets << target
96
+ log("Unchanged target #{target}")
97
+ elsif results.grep(/^Uploaded [0-9]+ changed secret files: /).any?
98
+ @changed_targets << target
99
+ log("Changed target #{target}")
100
+ else
101
+ @failed_targets << target
102
+ log("Unparseable result deploying to target #{target}")
103
+ end
104
+ else
105
+ @failed_targets << target
106
+ log("Failed to deploy to target #{target}")
107
+ end
108
+ end
109
+ end
110
+
111
+ def publish_results
112
+ slack_publisher = NdrDevSupport::SlackMessagePublisher.new(ENV['SLACK_WEBHOOK_URL'],
113
+ username: 'Rake CI',
114
+ icon_emoji: ':robot_face:',
115
+ channel: ENV['SLACK_CHANNEL'])
116
+ slack_publisher.post(attachments: attachments)
117
+ end
118
+
119
+ # Status / warning messages for slack notifications
120
+ def attachments
121
+ attachments = []
122
+
123
+ if @failed_targets.any?
124
+ attachment = {
125
+ color: 'danger',
126
+ title: "#{@failed_targets.count} failed credential updates :rotating_light:",
127
+ text: "Failed targets: `#{@failed_targets.join(', ')}`",
128
+ footer: 'bundle exec cap target app:update_secrets',
129
+ mrkdwn_in: ['text']
130
+ }
131
+ attachments << attachment
132
+ puts attachment.inspect
133
+ end
134
+
135
+ if @changed_targets.any?
136
+ text = "Changed targets: `#{@changed_targets.join(', ')}`\n"
137
+ text << (if @unchanged_targets.any?
138
+ "Unchanged targets: `#{@unchanged_targets.join(', ')}`"
139
+ else
140
+ 'No unchanged targets'
141
+ end)
142
+ attachment = {
143
+ color: 'good',
144
+ title: "#{@changed_targets.size} successful credential updates",
145
+ text: text,
146
+ footer: 'bundle exec cap target app:update_secrets',
147
+ mrkdwn_in: ['text']
148
+ }
149
+ attachments << attachment
150
+ puts attachment.inspect
151
+ end
152
+
153
+ attachments
154
+ end
155
+ end
156
+ end
157
+ end
@@ -1,5 +1,6 @@
1
1
  load 'tasks/audit_code.rake'
2
2
  load 'tasks/audit_bundle.rake'
3
+ load 'tasks/cd/credentials.rake'
3
4
  load 'tasks/ci/brakeman.rake'
4
5
  load 'tasks/ci/bundle_audit.rake'
5
6
  load 'tasks/ci/commit_cop.rake'
@@ -2,5 +2,5 @@
2
2
  # This defines the NdrDevSupport version. If you change it, rebuild and commit the gem.
3
3
  # Use "rake build" to build the gem, see rake -T for all bundler rake tasks (and our own).
4
4
  module NdrDevSupport
5
- VERSION = '6.1.4'
5
+ VERSION = '6.1.7'
6
6
  end
@@ -1,6 +1,7 @@
1
1
  require 'csv'
2
2
  require 'pathname'
3
3
  require 'yaml'
4
+ require 'shellwords'
4
5
 
5
6
  SAFETY_FILE =
6
7
  if File.exist?('code_safety.yml')
@@ -338,7 +339,8 @@ def get_last_changed_revision(repo, fname)
338
339
  %x[git log -n 1 -- "#{fname}"].split("\n").first[7..-1]
339
340
  when 'git-svn', 'svn'
340
341
  begin
341
- svn_info = %x[svn info -r head "#{repo}/#{fname}"]
342
+ dest = "#{repo}/#{fname}@"
343
+ svn_info = %x[svn info -r head #{Shellwords.escape(dest)}]
342
344
  rescue
343
345
  puts 'we have an error in the svn info line'
344
346
  end
@@ -376,9 +378,10 @@ def capture_file_diffs(repo, fname, safe_revision, repolatest)
376
378
  cmd =
377
379
  case repository_type
378
380
  when 'git'
379
- cmd = ['git', '--no-pager', 'diff', '--color', '-b', "#{safe_revision}..#{repolatest}", fname]
381
+ ['git', '--no-pager', 'diff', '--color', '-b', "#{safe_revision}..#{repolatest}", fname]
380
382
  when 'git-svn', 'svn'
381
- cmd = ['svn', 'diff', '-r', "#{safe_revision.to_i}:#{repolatest.to_i}", '-x', '-b', "#{repo}/#{fname}"]
383
+ ['svn', 'diff', '-r', "#{safe_revision.to_i}:#{repolatest.to_i}", '-x', '-b',
384
+ "#{repo}/#{fname}@"]
382
385
  end
383
386
 
384
387
  stdout_and_err_str, _status = Open3.capture2e(*cmd)
@@ -0,0 +1,9 @@
1
+ namespace :cd do
2
+ desc 'Run Capistrano Continuous Deployment credentials server'
3
+ task :credentials do
4
+ require 'ndr_dev_support/daemon/cd_credentials'
5
+
6
+ worker = NdrDevSupport::Daemon::CDCredentials.from_args(ENV)
7
+ worker.run
8
+ end
9
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ndr_dev_support
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.1.4
4
+ version: 6.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - NCRS Development Team
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-06-16 00:00:00.000000000 Z
11
+ date: 2022-07-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pry
@@ -422,6 +422,7 @@ files:
422
422
  - lib/ndr_dev_support/capistrano/standalone_gems.rb
423
423
  - lib/ndr_dev_support/capistrano/svn_cache.rb
424
424
  - lib/ndr_dev_support/capistrano/sysadmin_scripts.rb
425
+ - lib/ndr_dev_support/daemon/cd_credentials.rb
425
426
  - lib/ndr_dev_support/daemon/ci_server.rb
426
427
  - lib/ndr_dev_support/daemon/stoppable.rb
427
428
  - lib/ndr_dev_support/integration_testing.rb
@@ -452,6 +453,7 @@ files:
452
453
  - lib/ndr_dev_support/version.rb
453
454
  - lib/tasks/audit_bundle.rake
454
455
  - lib/tasks/audit_code.rake
456
+ - lib/tasks/cd/credentials.rake
455
457
  - lib/tasks/ci/brakeman.rake
456
458
  - lib/tasks/ci/bundle_audit.rake
457
459
  - lib/tasks/ci/commit_cop.rake