bard 1.3.9 → 1.4.1

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: 4786eaeab7a9790f644eebe54fe86e3c03e829a9e1d2bc149e612c6b125d9687
4
- data.tar.gz: ce9ba38f2f0e4e1897997d31f6f687cf2256978f928bcd3399555e1b7bdbc200
3
+ metadata.gz: b61ad7f978453da17070fecbb92f64e0fc3311f3c8b530d7cb89227f6a72d286
4
+ data.tar.gz: f0961592b8234b9c71929cfb5f34b9cc9edbf4f75485331bdf25a6a27e620e44
5
5
  SHA512:
6
- metadata.gz: 54b835052687d6356ffc0f06d62413f1cbdb4f9fd606fe4047849d3556069d871e3432b5c79ff5d84bab829293fb0ad2333ef0b7671232ca8ea39d8f27d46c9e
7
- data.tar.gz: cd14da902d7b39bc7dc665164a0019225ca23436122498d1dae2cd78966cece12acea9346f6345e8cf3a141a35130813c63c8af726559b25fe43bcc518589464
6
+ metadata.gz: bb9fa351d2b084dc624909e0691aa0ad698c182bf5d0417c3e5731f63bc9ac2aaa90b23be87ba3c894abb74a4b16baf5a638124789eb3eefd8e2087ba6b71257
7
+ data.tar.gz: 902e8f5be5ae6c1c47cbf34c771fe77c1e3dc298f345983732c6b7cd74eb7293c9d6c325cf2e90814532a85bbaa22b9825c416e507ee40aec88c9068e1bfd328
data/bard.gemspec CHANGED
@@ -20,6 +20,7 @@ Gem::Specification.new do |spec|
20
20
  spec.add_dependency "thor", ">= 0.19.0"
21
21
  spec.add_dependency "rvm"
22
22
  spec.add_dependency "term-ansicolor", ">= 1.0.3"
23
+ spec.add_dependency "rbnacl"
23
24
 
24
25
  spec.add_development_dependency "byebug"
25
26
  spec.add_development_dependency "rspec"
@@ -30,6 +30,14 @@ jobs:
30
30
  uses: ruby/setup-ruby@v1
31
31
  with:
32
32
  bundler-cache: true
33
+ - name: Set up apt packages
34
+ run: |
35
+ sudo rm -f /var/lib/man-db/auto-update
36
+ echo "APT_PACKAGES=$(paste -sd " " Aptfile)" >> $GITHUB_ENV
37
+ - name: Apt packages
38
+ uses: awalsh128/cache-apt-pkgs-action@latest
39
+ with:
40
+ packages: ${{ env.APT_PACKAGES }}
33
41
  - name: Setup
34
42
  run: bin/setup
35
43
  - name: Run tests
@@ -3,6 +3,7 @@ module AptDependencies
3
3
 
4
4
  def self.ensure!
5
5
  return "true" if deps_to_install.none?
6
+ return "true" if ENV["APT_PACKAGES"] # already installed via github actions
6
7
  if sudo_password_required? && ENV["RAILS_ENV"] != "development"
7
8
  $stderr.puts "sudo requires password! cannot install #{deps_to_install.join(' ')}"
8
9
  exit 1
data/lib/bard/cli/new.rb CHANGED
@@ -40,7 +40,8 @@ class Bard::CLI::New < Bard::CLI::Command
40
40
  end
41
41
 
42
42
  def push_to_github
43
- Bard::Github.new(project_name).create_repo
43
+ api = Bard::Github.new(project_name)
44
+ api.create_repo
44
45
  run! <<~BASH
45
46
  cd ../#{project_name}
46
47
  git init -b master
@@ -49,6 +50,9 @@ class Bard::CLI::New < Bard::CLI::Command
49
50
  git remote add origin git@github.com:botandrosedesign/#{project_name}
50
51
  git push -u origin master
51
52
  BASH
53
+ api.add_master_key File.read("../#{project_name}/config/master.key")
54
+ api.add_master_branch_protection
55
+ api.patch(nil, allow_auto_merge: true)
52
56
  end
53
57
 
54
58
  def stage
@@ -21,6 +21,9 @@ file ".gitignore", <<~GITIGNORE
21
21
  # Ignore master key for decrypting credentials and more.
22
22
  /config/master.key
23
23
 
24
+ # ignore coverage reports
25
+ /coverage
26
+
24
27
  # Ignore database dumps
25
28
  /db/data.*
26
29
 
@@ -39,30 +42,32 @@ file "Gemfile", <<~RUBY
39
42
 
40
43
  gem "bootsnap", require: false
41
44
  gem "rails", "~>8.0.0"
45
+ gem "solid_cache"
46
+ gem "solid_queue"
47
+ gem "solid_cable"
42
48
  gem "bard-rails"
43
49
  gem "sqlite3"
50
+ gem "image_processing"
51
+ gem "puma"
52
+ gem "exception_notification"
44
53
 
54
+ # css
45
55
  gem "sprockets-rails"
46
56
  gem "dartsass-sprockets"
47
57
  gem "bard-sass"
48
58
 
59
+ # js
49
60
  gem "importmap-rails"
50
61
  gem "turbo-rails"
51
62
  gem "stimulus-rails"
52
63
 
53
- gem "solid_cache"
54
- gem "solid_queue"
55
- gem "solid_cable"
56
-
57
- gem "image_processing"
58
- gem "puma"
59
-
60
64
  group :development do
61
65
  gem "web-console"
62
66
  end
63
67
 
64
68
  group :development, :test do
65
69
  gem "debug", require: "debug/prelude"
70
+ gem "parallel_tests", "~>3.9.0" # 3.10 pegs CPU
66
71
  gem "brakeman", require: false
67
72
  gem "rubocop-rails-omakase", require: false
68
73
  end
@@ -83,6 +88,64 @@ file "Gemfile", <<~RUBY
83
88
  end
84
89
  RUBY
85
90
 
91
+ file "config/initializers/exception_notification.rb", <<~RUBY
92
+ require "exception_notification/rails"
93
+
94
+ ExceptionNotification.configure do |config|
95
+ config.ignored_exceptions = []
96
+
97
+ # Adds a condition to decide when an exception must be ignored or not.
98
+ # The ignore_if method can be invoked multiple times to add extra conditions.
99
+ config.ignore_if do |exception, options|
100
+ not Rails.env.production?
101
+ end
102
+
103
+ config.ignore_if do |exception, options|
104
+ %w[
105
+ ActiveRecord::RecordNotFound
106
+ AbstractController::ActionNotFound
107
+ ActionController::RoutingError
108
+ ActionController::InvalidAuthenticityToken
109
+ ActionView::MissingTemplate
110
+ ActionController::BadRequest
111
+ ActionDispatch::Http::Parameters::ParseError
112
+ ActionDispatch::Http::MimeNegotiation::InvalidType
113
+ ].include?(exception.class.to_s)
114
+ end
115
+
116
+ config.add_notifier :email, {
117
+ email_prefix: "[\#{File.basename(Dir.pwd)}] ",
118
+ exception_recipients: "micah@botandrose.com",
119
+ smtp_settings: Rails.application.credentials.exception_notification_smtp_settings,
120
+ }
121
+ end
122
+
123
+ if defined?(Rake::Application)
124
+ Rake::Application.prepend Module.new {
125
+ def display_error_message error
126
+ ExceptionNotifier.notify_exception(error)
127
+ super
128
+ end
129
+
130
+ def invoke_task task_name
131
+ super
132
+ rescue RuntimeError => exception
133
+ if exception.message.starts_with?("Don't know how to build task")
134
+ ExceptionNotifier.notify_exception(exception)
135
+ end
136
+ raise exception
137
+ end
138
+ }
139
+ end
140
+
141
+ ActionController::Live.prepend Module.new {
142
+ def log_error exception
143
+ ExceptionNotifier.notify_exception exception, env: request.env
144
+ super
145
+ end
146
+ }
147
+ RUBY
148
+
86
149
  file "app/assets/config/manifest.js", <<~RUBY
87
150
  //= link_tree ../images
88
151
  //= link_directory ../stylesheets .css
@@ -110,6 +173,18 @@ insert_into_file "config/database.yml", <<~YAML, after: "database: storage/test.
110
173
  database: storage/staging.sqlite3
111
174
  YAML
112
175
 
176
+ insert_into_file "config/database.yml", <<-YAML, after: "# database: path/to/persistent/storage/production.sqlite3"
177
+
178
+ cable:
179
+ <<: *default
180
+ # database: path/to/persistent/storage/production_cable.sqlite3
181
+ migrations_paths: db/cable_migrate
182
+ queue:
183
+ <<: *default
184
+ # database: path/to/persistent/storage/production_queue.sqlite3
185
+ migrations_paths: db/queue_migrate
186
+ YAML
187
+
113
188
  gsub_file "config/environments/production.rb", / (config\.logger.+STDOUT.*)$/, ' # \1'
114
189
 
115
190
  after_bundle do
@@ -23,10 +23,11 @@ class Bard::CLI::Provision < Bard::CLI::Command
23
23
  desc "provision [ssh_url] --steps=all", "takes an optional ssh url to a raw ubuntu 22.04 install, and readies it in the shape of :production"
24
24
  option :steps, type: :array, default: STEPS
25
25
  def provision ssh_url=config[:production].ssh
26
+ # unfreeze the string for later mutation
27
+ ssh_url = ssh_url.dup
26
28
  options[:steps].each do |step|
27
29
  require "bard/provision/#{step.downcase}"
28
- # dup unfreezes the string for later mutation
29
- Bard::Provision.const_get(step).call(config, ssh_url.dup)
30
+ Bard::Provision.const_get(step).call(config, ssh_url)
30
31
  end
31
32
  end
32
33
  end
data/lib/bard/git.rb CHANGED
@@ -20,7 +20,9 @@ module Bard
20
20
  end
21
21
 
22
22
  def sha_of ref
23
- `git rev-parse #{ref}`.chomp
23
+ sha = `git rev-parse #{ref} 2>/dev/null`.chomp
24
+ return sha if $?.success?
25
+ nil # Branch doesn't exist
24
26
  end
25
27
  end
26
28
  end
data/lib/bard/github.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require "net/http"
2
2
  require "json"
3
3
  require "base64"
4
+ require "rbnacl"
4
5
 
5
6
  module Bard
6
7
  class Github < Struct.new(:project_name)
@@ -19,6 +20,22 @@ module Bard
19
20
  end
20
21
  end
21
22
 
23
+ def put path, params={}
24
+ request(path) do |uri|
25
+ Net::HTTP::Put.new(uri).tap do |r|
26
+ r.body = JSON.dump(params)
27
+ end
28
+ end
29
+ end
30
+
31
+ def patch path, params={}
32
+ request(path) do |uri|
33
+ Net::HTTP::Patch.new(uri).tap do |r|
34
+ r.body = JSON.dump(params)
35
+ end
36
+ end
37
+ end
38
+
22
39
  def delete path, params={}
23
40
  request(path) do |uri|
24
41
  Net::HTTP::Delete.new(uri).tap do |r|
@@ -36,6 +53,38 @@ module Bard
36
53
  post("keys", title:, key:)
37
54
  end
38
55
 
56
+ def add_master_key master_key
57
+ response = get("actions/secrets/public-key")
58
+ public_key, public_key_id = response.values_at("key", "key_id")
59
+
60
+ def encrypt_secret(encoded_public_key, secret)
61
+ decoded_key = Base64.decode64(encoded_public_key)
62
+ public_key = RbNaCl::PublicKey.new(decoded_key)
63
+ box = RbNaCl::Boxes::Sealed.from_public_key(public_key)
64
+ encrypted_secret = box.encrypt(secret)
65
+ Base64.strict_encode64(encrypted_secret)
66
+ end
67
+
68
+ encrypted_master_key = encrypt_secret(public_key, master_key)
69
+
70
+ put("actions/secrets/RAILS_MASTER_KEY", {
71
+ encrypted_value: encrypted_master_key,
72
+ key_id: public_key_id,
73
+ })
74
+ end
75
+
76
+ def add_master_branch_protection
77
+ put("branches/master/protection", {
78
+ required_status_checks: {
79
+ strict: false,
80
+ contexts: [],
81
+ },
82
+ enforce_admins: nil,
83
+ required_pull_request_reviews: nil,
84
+ restrictions: nil,
85
+ })
86
+ end
87
+
39
88
  def create_repo
40
89
  post("https://api.github.com/orgs/botandrosedesign/repos", {
41
90
  name: project_name,
@@ -44,7 +93,7 @@ module Bard
44
93
  end
45
94
 
46
95
  def delete_repo
47
- delete("https://api.github.com/repos/botandrosedesign/#{project_name}")
96
+ delete(nil)
48
97
  end
49
98
 
50
99
  private
@@ -60,7 +109,12 @@ module Bard
60
109
  uri = if path =~ /^http/
61
110
  URI(path)
62
111
  else
63
- URI("https://api.github.com/repos/botandrosedesign/#{project_name}/#{path}")
112
+ base = "https://api.github.com/repos/botandrosedesign/#{project_name}"
113
+ if path
114
+ URI.join(base, path)
115
+ else
116
+ URI(base)
117
+ end
64
118
  end
65
119
 
66
120
  req = nil
@@ -92,9 +92,7 @@ module Bard
92
92
  end
93
93
 
94
94
  def get_parent_commit
95
- sha = Git.sha_of("#{@branch}^{commit}")
96
- return sha if $?.success?
97
- nil # Branch doesn't exist yet
95
+ Git.sha_of("#{@branch}^{commit}")
98
96
  end
99
97
 
100
98
  def commit_and_push commit_sha
@@ -8,6 +8,7 @@ class Bard::Provision::MySQL < Bard::Provision
8
8
  provision_server.run! [
9
9
  "sudo apt-get install -y mysql-server",
10
10
  %(sudo mysql -uroot -e "ALTER USER \\"'\\"root\\"'\\"@\\"'\\"localhost\\"'\\" IDENTIFIED WITH mysql_native_password BY \\"'\\"\\"'\\", \\"'\\"root\\"'\\"@\\"'\\"localhost\\"'\\" PASSWORD EXPIRE NEVER; FLUSH PRIVILEGES;"),
11
+ %(mysql -uroot -e "UPDATE mysql.user SET password_lifetime = NULL WHERE user = 'root' AND host = 'localhost';"),
11
12
  ].join("; "), home: true
12
13
  end
13
14
 
@@ -36,7 +36,7 @@ class Bard::Provision::User < Bard::Provision
36
36
  end
37
37
 
38
38
  def ssh_with_user? ssh_uri, user: ssh_uri.user
39
- system "ssh -o ConnectTimeout=2 -p#{ssh_uri.port || 22} #{user}@#{ssh_uri.host} exit >/dev/null 2>&1"
39
+ system "ssh -o ConnectTimeout=2 -p#{ssh_uri.port || 22} #{user}@#{ssh_uri.host} : >/dev/null 2>&1"
40
40
  end
41
41
  end
42
42
 
data/lib/bard/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module Bard
2
- VERSION = "1.3.9"
2
+ VERSION = "1.4.1"
3
3
  end
4
4
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bard
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.9
4
+ version: 1.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Micah Geisel
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-01-17 00:00:00.000000000 Z
11
+ date: 2025-02-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: 1.0.3
55
+ - !ruby/object:Gem::Dependency
56
+ name: rbnacl
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: byebug
57
71
  requirement: !ruby/object:Gem::Requirement