bard 1.3.9 → 1.4.1

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: 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