bullion 0.8.0 → 0.10.0

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: 963485e78c3801d797247abf4898afb5b592797d173a03a5e388060bbd455e01
4
- data.tar.gz: c1ae7f9f915693551e8223096260f74deff612211d22340b3b90cfb328a27553
3
+ metadata.gz: 74fbfc1ee8b98c2ff1c707302c8e62c9b2f8d106308b8b3b02d6a1ffe622cb77
4
+ data.tar.gz: adbd79fc4e82a9630dee2dd71c1e33c7e0a8f02732c986af07b1ba3d1733fd5c
5
5
  SHA512:
6
- metadata.gz: 3439de16cbab209608c35eda483ce814d6bba3bfb0a6a28c03c7ea7a372fa9008e34a479270ff5463c44d222f0b11438be05f419210775faccd01aa39f22f5e5
7
- data.tar.gz: 43c3238954f9766495a86ae6ea04463ccb3646d5ee5a1bbbfcccaf6c4a2bba1056ff252dd9f409eec836e3ac04b611c570ee34bd0c1f8cb38dc02b47dee7d194
6
+ metadata.gz: f1cfc723554109cdb6e837e2dabd66eed6dd52d3cd7ca649923f88940c31e83e957e749ec1449c6eef4ffbcc89aafbbf822a3725b55688a3dc5d4290bd63552b
7
+ data.tar.gz: ccbe2a235fa91b4568b6977f55b22122de5f0fc1e0c2620c4ef9e16dfc4ce618ccff0322ea1e5c9dc3711f2dc10b22a9dc0bcd5c45d406adb08640229ec78048
@@ -38,7 +38,7 @@ jobs:
38
38
  runs-on: ubuntu-latest
39
39
  strategy:
40
40
  matrix:
41
- ruby-version: ['3.3', '3.4']
41
+ ruby-version: ['3.4']
42
42
 
43
43
  steps:
44
44
  - name: Checkout code
@@ -1,3 +1,3 @@
1
1
  {
2
- ".": "0.8.0"
2
+ ".": "0.10.0"
3
3
  }
data/.rubocop.yml CHANGED
@@ -6,11 +6,12 @@ Layout/LineLength:
6
6
  Max: 100
7
7
 
8
8
  AllCops:
9
- TargetRubyVersion: 3.3
9
+ TargetRubyVersion: 3.4
10
10
  Exclude:
11
11
  - 'db/schema.rb'
12
12
  - 'vendor/**/*'
13
13
  - 'tmp/**/*'
14
+ - Itsi.rb
14
15
  NewCops: enable
15
16
 
16
17
  Metrics/AbcSize:
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 3.3.4
1
+ 3.4.4
data/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.10.0](https://github.com/jgnagy/bullion/compare/bullion/v0.9.0...bullion/v0.10.0) (2025-07-05)
4
+
5
+
6
+ ### ⚠ BREAKING CHANGES
7
+
8
+ * update Docker image with Itsi configuration
9
+
10
+ ### Bug Fixes
11
+
12
+ * update Docker image with Itsi configuration ([4be39dd](https://github.com/jgnagy/bullion/commit/4be39dd6200f058907029e23a07f19241705b701))
13
+
14
+ ## [0.9.0](https://github.com/jgnagy/bullion/compare/bullion/v0.8.0...bullion/v0.9.0) (2025-07-05)
15
+
16
+
17
+ ### ⚠ BREAKING CHANGES
18
+
19
+ * full ruby and dependency upgrade
20
+
21
+ ### Miscellaneous Chores
22
+
23
+ * full ruby and dependency upgrade ([7625208](https://github.com/jgnagy/bullion/commit/7625208b1c4fa6b1acb5a0c9e7362001d66e4e08))
24
+
3
25
  ## [0.8.0](https://github.com/jgnagy/bullion/compare/bullion-v0.7.3...bullion/v0.8.0) (2025-03-13)
4
26
 
5
27
 
data/Dockerfile CHANGED
@@ -1,10 +1,10 @@
1
- FROM ruby:3.2 AS build
1
+ FROM ruby:3.4.4 AS build
2
2
 
3
3
  ENV RACK_ENV=development
4
4
 
5
5
  COPY . /build
6
6
 
7
- RUN apt-get update && apt-get upgrade -y && apt-get install -y libsqlite3-dev sqlite3 curl libsodium-dev
7
+ RUN apt-get update && apt-get upgrade -y && apt-get install -y libsqlite3-dev sqlite3 curl libsodium-dev build-essential libclang-dev
8
8
 
9
9
  RUN cd /build \
10
10
  && gem build bullion.gemspec \
@@ -12,14 +12,14 @@ RUN cd /build \
12
12
 
13
13
  WORKDIR /build
14
14
 
15
- FROM ruby:3.2
15
+ FROM ruby:3.4.4
16
16
  LABEL maintainer="Jonathan Gnagy <jonathan.gnagy@gmail.com>"
17
17
 
18
18
  ENV BULLION_PORT=9292
19
- ENV BULLION_ENVIRONMENT=development
19
+ ENV RACK_ENV=production
20
20
  ENV DATABASE_URL=sqlite3:///tmp/bullion.db
21
21
 
22
- RUN apt-get update && apt-get upgrade -y && apt-get -y install libsqlite3-dev sqlite3 curl libsodium-dev
22
+ RUN apt-get update && apt-get upgrade -y && apt-get -y install libsqlite3-dev sqlite3 curl libsodium-dev build-essential libclang-dev
23
23
 
24
24
  RUN mkdir /app
25
25
 
@@ -27,6 +27,7 @@ COPY ./scripts/docker-entrypoint.sh /entrypoint.sh
27
27
  COPY --from=build /bullion.gem /app/bullion.gem
28
28
  COPY ./db /app/db
29
29
  COPY ./config.ru /app/config.ru
30
+ COPY ./Itsi.rb /app/Itsi.rb
30
31
  COPY ./Rakefile /app/Rakefile
31
32
 
32
33
  RUN mkdir /ssl
@@ -34,7 +35,8 @@ RUN mkdir /ssl
34
35
  RUN chmod +x /entrypoint.sh \
35
36
  && chown nobody /app/db \
36
37
  && chown nobody /app/db/schema.rb \
37
- && chown -R nobody:nogroup /ssl
38
+ && chown -R nobody:nogroup /ssl \
39
+ && chown nobody /app
38
40
 
39
41
  WORKDIR /app
40
42
 
@@ -42,4 +44,6 @@ RUN gem install bullion.gem
42
44
 
43
45
  USER nobody
44
46
 
47
+ EXPOSE 9292
48
+
45
49
  ENTRYPOINT ["/entrypoint.sh"]
data/Gemfile.lock CHANGED
@@ -1,26 +1,26 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- bullion (0.8.0)
4
+ bullion (0.10.0)
5
5
  benchmark (~> 0.4)
6
6
  dry-configurable (~> 1.1)
7
7
  httparty (~> 0.21)
8
+ itsi (~> 0.2)
8
9
  json (~> 2.6)
9
10
  jwt (~> 2.7)
10
11
  mysql2 (~> 0.5)
11
12
  openssl (~> 3.0)
12
13
  prometheus-client (~> 4.2)
13
- puma (~> 6.4)
14
14
  sinatra (~> 3.1)
15
15
  sinatra-activerecord (~> 2.0)
16
16
  sinatra-contrib (~> 3.1)
17
- sqlite3 (~> 2.6)
17
+ sqlite3 (~> 2.7)
18
18
 
19
19
  GEM
20
20
  remote: https://rubygems.org/
21
21
  specs:
22
- acme-client (2.0.20)
23
- base64 (~> 0.2.0)
22
+ acme-client (2.0.22)
23
+ base64 (~> 0.2)
24
24
  faraday (>= 1.0, < 3.0.0)
25
25
  faraday-retry (>= 1.0, < 3.0.0)
26
26
  activemodel (8.0.2)
@@ -42,18 +42,18 @@ GEM
42
42
  securerandom (>= 0.3)
43
43
  tzinfo (~> 2.0, >= 2.0.5)
44
44
  uri (>= 0.13.1)
45
- ast (2.4.2)
45
+ ast (2.4.3)
46
46
  backport (1.2.0)
47
- base64 (0.2.0)
48
- benchmark (0.4.0)
49
- bigdecimal (3.1.9)
47
+ base64 (0.3.0)
48
+ benchmark (0.4.1)
49
+ bigdecimal (3.2.2)
50
50
  byebug (11.1.3)
51
51
  concurrent-ruby (1.3.5)
52
- connection_pool (2.5.0)
53
- csv (3.3.2)
54
- diff-lcs (1.6.0)
52
+ connection_pool (2.5.3)
53
+ csv (3.3.5)
54
+ diff-lcs (1.6.2)
55
55
  docile (1.4.1)
56
- drb (2.2.1)
56
+ drb (2.2.3)
57
57
  dry-configurable (1.3.0)
58
58
  dry-core (~> 1.1)
59
59
  zeitwerk (~> 2.6)
@@ -61,98 +61,109 @@ GEM
61
61
  concurrent-ruby (~> 1.0)
62
62
  logger
63
63
  zeitwerk (~> 2.6)
64
- faraday (2.12.2)
64
+ faraday (2.13.2)
65
65
  faraday-net_http (>= 2.0, < 3.5)
66
66
  json
67
67
  logger
68
- faraday-net_http (3.4.0)
68
+ faraday-net_http (3.4.1)
69
69
  net-http (>= 0.5.0)
70
- faraday-retry (2.2.1)
70
+ faraday-retry (2.3.2)
71
71
  faraday (~> 2.0)
72
- httparty (0.22.0)
72
+ httparty (0.23.1)
73
73
  csv
74
74
  mini_mime (>= 1.0.0)
75
75
  multi_xml (>= 0.5.2)
76
76
  i18n (1.14.7)
77
77
  concurrent-ruby (~> 1.0)
78
- jaro_winkler (1.6.0)
79
- json (2.10.2)
80
- jwt (2.10.1)
78
+ itsi (0.2.18)
79
+ itsi-scheduler (~> 0.2.18)
80
+ itsi-server (~> 0.2.18)
81
+ itsi-scheduler (0.2.18)
82
+ rb_sys (~> 0.9.91)
83
+ itsi-server (0.2.18)
84
+ json (~> 2)
85
+ prism (~> 1.4)
86
+ rack (>= 1.6)
87
+ rb_sys (~> 0.9.91)
88
+ jaro_winkler (1.6.1)
89
+ json (2.12.2)
90
+ jwt (2.10.2)
81
91
  base64
82
92
  kramdown (2.5.1)
83
93
  rexml (>= 3.3.9)
84
94
  kramdown-parser-gfm (1.1.0)
85
95
  kramdown (~> 2.0)
86
- language_server-protocol (3.17.0.4)
96
+ language_server-protocol (3.17.0.5)
87
97
  lint_roller (1.1.0)
88
- logger (1.6.6)
98
+ logger (1.7.0)
89
99
  mini_mime (1.1.5)
90
100
  minitest (5.25.5)
91
101
  multi_json (1.15.0)
92
- multi_xml (0.7.1)
102
+ multi_xml (0.7.2)
93
103
  bigdecimal (~> 3.1)
94
104
  mustermann (3.0.3)
95
105
  ruby2_keywords (~> 0.0.1)
96
106
  mysql2 (0.5.6)
97
107
  net-http (0.6.0)
98
108
  uri
99
- nio4r (2.7.4)
100
- nokogiri (1.18.3-aarch64-linux-gnu)
109
+ nokogiri (1.18.8-aarch64-linux-gnu)
101
110
  racc (~> 1.4)
102
- nokogiri (1.18.3-aarch64-linux-musl)
111
+ nokogiri (1.18.8-aarch64-linux-musl)
103
112
  racc (~> 1.4)
104
- nokogiri (1.18.3-arm-linux-gnu)
113
+ nokogiri (1.18.8-arm-linux-gnu)
105
114
  racc (~> 1.4)
106
- nokogiri (1.18.3-arm-linux-musl)
115
+ nokogiri (1.18.8-arm-linux-musl)
107
116
  racc (~> 1.4)
108
- nokogiri (1.18.3-arm64-darwin)
117
+ nokogiri (1.18.8-arm64-darwin)
109
118
  racc (~> 1.4)
110
- nokogiri (1.18.3-x86_64-darwin)
119
+ nokogiri (1.18.8-x86_64-darwin)
111
120
  racc (~> 1.4)
112
- nokogiri (1.18.3-x86_64-linux-gnu)
121
+ nokogiri (1.18.8-x86_64-linux-gnu)
113
122
  racc (~> 1.4)
114
- nokogiri (1.18.3-x86_64-linux-musl)
123
+ nokogiri (1.18.8-x86_64-linux-musl)
115
124
  racc (~> 1.4)
116
125
  observer (0.1.2)
117
126
  openssl (3.3.0)
118
- ostruct (0.6.1)
119
- parallel (1.26.3)
120
- parser (3.3.7.1)
127
+ ostruct (0.6.2)
128
+ parallel (1.27.0)
129
+ parser (3.3.8.0)
121
130
  ast (~> 2.4.1)
122
131
  racc
132
+ prism (1.4.0)
123
133
  prometheus-client (4.2.4)
124
134
  base64
125
- puma (6.6.0)
126
- nio4r (~> 2.0)
127
135
  racc (1.8.1)
128
- rack (2.2.13)
136
+ rack (2.2.17)
129
137
  rack-protection (3.2.0)
130
138
  base64 (>= 0.1.0)
131
139
  rack (~> 2.2, >= 2.2.4)
132
140
  rack-test (2.2.0)
133
141
  rack (>= 1.3)
134
142
  rainbow (3.1.1)
135
- rake (13.2.1)
136
- rbs (3.8.1)
143
+ rake (13.3.0)
144
+ rake-compiler-dock (1.9.1)
145
+ rb_sys (0.9.116)
146
+ rake-compiler-dock (= 1.9.1)
147
+ rbs (3.9.4)
137
148
  logger
138
149
  regexp_parser (2.10.0)
139
150
  reverse_markdown (3.0.0)
140
151
  nokogiri
141
152
  rexml (3.4.1)
142
- rspec (3.13.0)
153
+ rspec (3.13.1)
143
154
  rspec-core (~> 3.13.0)
144
155
  rspec-expectations (~> 3.13.0)
145
156
  rspec-mocks (~> 3.13.0)
146
- rspec-core (3.13.3)
157
+ rspec-core (3.13.5)
147
158
  rspec-support (~> 3.13.0)
148
- rspec-expectations (3.13.3)
159
+ rspec-expectations (3.13.5)
149
160
  diff-lcs (>= 1.2.0, < 2.0)
150
161
  rspec-support (~> 3.13.0)
151
- rspec-mocks (3.13.2)
162
+ rspec-mocks (3.13.5)
152
163
  diff-lcs (>= 1.2.0, < 2.0)
153
164
  rspec-support (~> 3.13.0)
154
- rspec-support (3.13.2)
155
- rubocop (1.73.2)
165
+ rspec-support (3.13.4)
166
+ rubocop (1.77.0)
156
167
  json (~> 2.3)
157
168
  language_server-protocol (~> 3.17.0.2)
158
169
  lint_roller (~> 1.1.0)
@@ -160,15 +171,16 @@ GEM
160
171
  parser (>= 3.3.0.2)
161
172
  rainbow (>= 2.2.2, < 4.0)
162
173
  regexp_parser (>= 2.9.3, < 3.0)
163
- rubocop-ast (>= 1.38.0, < 2.0)
174
+ rubocop-ast (>= 1.45.1, < 2.0)
164
175
  ruby-progressbar (~> 1.7)
165
176
  unicode-display_width (>= 2.4.0, < 4.0)
166
- rubocop-ast (1.38.1)
167
- parser (>= 3.3.1.0)
177
+ rubocop-ast (1.45.1)
178
+ parser (>= 3.3.7.2)
179
+ prism (~> 1.4)
168
180
  rubocop-rake (0.7.1)
169
181
  lint_roller (~> 1.1)
170
182
  rubocop (>= 1.72.1)
171
- rubocop-rspec (3.5.0)
183
+ rubocop-rspec (3.6.0)
172
184
  lint_roller (~> 1.1)
173
185
  rubocop (~> 1.72, >= 1.72.1)
174
186
  ruby-progressbar (1.13.0)
@@ -197,33 +209,34 @@ GEM
197
209
  rack-protection (= 3.2.0)
198
210
  sinatra (= 3.2.0)
199
211
  tilt (~> 2.0)
200
- solargraph (0.52.0)
212
+ solargraph (0.56.0)
201
213
  backport (~> 1.2)
202
- benchmark
214
+ benchmark (~> 0.4)
203
215
  bundler (~> 2.0)
204
216
  diff-lcs (~> 1.4)
205
- jaro_winkler (~> 1.6)
217
+ jaro_winkler (~> 1.6, >= 1.6.1)
206
218
  kramdown (~> 2.3)
207
219
  kramdown-parser-gfm (~> 1.1)
208
220
  logger (~> 1.6)
209
221
  observer (~> 0.1)
210
222
  ostruct (~> 0.6)
211
223
  parser (~> 3.0)
212
- rbs (~> 3.0)
213
- reverse_markdown (>= 2.0, < 4)
224
+ prism (~> 1.4)
225
+ rbs (~> 3.3)
226
+ reverse_markdown (~> 3.0)
214
227
  rubocop (~> 1.38)
215
228
  thor (~> 1.0)
216
229
  tilt (~> 2.0)
217
230
  yard (~> 0.9, >= 0.9.24)
218
231
  yard-solargraph (~> 0.1)
219
- sqlite3 (2.6.0-aarch64-linux-gnu)
220
- sqlite3 (2.6.0-aarch64-linux-musl)
221
- sqlite3 (2.6.0-arm-linux-gnu)
222
- sqlite3 (2.6.0-arm-linux-musl)
223
- sqlite3 (2.6.0-arm64-darwin)
224
- sqlite3 (2.6.0-x86_64-darwin)
225
- sqlite3 (2.6.0-x86_64-linux-gnu)
226
- sqlite3 (2.6.0-x86_64-linux-musl)
232
+ sqlite3 (2.7.1-aarch64-linux-gnu)
233
+ sqlite3 (2.7.1-aarch64-linux-musl)
234
+ sqlite3 (2.7.1-arm-linux-gnu)
235
+ sqlite3 (2.7.1-arm-linux-musl)
236
+ sqlite3 (2.7.1-arm64-darwin)
237
+ sqlite3 (2.7.1-x86_64-darwin)
238
+ sqlite3 (2.7.1-x86_64-linux-gnu)
239
+ sqlite3 (2.7.1-x86_64-linux-musl)
227
240
  thor (1.3.2)
228
241
  tilt (2.6.0)
229
242
  timeout (0.4.3)
@@ -236,7 +249,7 @@ GEM
236
249
  yard (0.9.37)
237
250
  yard-solargraph (0.1.0)
238
251
  yard (~> 0.9)
239
- zeitwerk (2.7.2)
252
+ zeitwerk (2.7.3)
240
253
 
241
254
  PLATFORMS
242
255
  aarch64-linux
data/Itsi.rb ADDED
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This is the default Itsi configuration file, installed when you run `itsi init`
4
+ # It contains a sane starting point for configuring your Itsi server.
5
+ # You can use this file in both development and production environments.
6
+ # Most of the options in this file can be overridden by command line options.
7
+ # Check out itsi -h to learn more about the command line options available to you.
8
+
9
+ env = ENV.fetch("APP_ENV") { ENV.fetch("RACK_ENV", "development") }
10
+
11
+ # Number of worker processes to spawn
12
+ # If more than 1, Itsi will be booted in Cluster mode
13
+ workers ENV["WORKERS"]&.to_i || (env == "development" ? 1 : nil)
14
+
15
+ # Number of threads to spawn per worker process
16
+ # For pure CPU bound applicationss, you'll get the best results keeping this number low
17
+ # Setting a value of 1 is great for superficial benchmarks, but in reality
18
+ # it's better to set this a bit higher to allow expensive requests to get overtaken and minimize head-of-line blocking
19
+ threads ENV.fetch("THREADS", 3).to_i
20
+
21
+ # If your application is IO bound (e.g. performing a lot of proxied HTTP requests, or heavy queries etc)
22
+ # you can see *substantial* benefits from enabling this option.
23
+ # To set this option, pass a string, not a class (as we will not have loaded the class yet)
24
+ # E.g.
25
+ # `fiber_scheduler "Itsi::Scheduler"` - The default fast and light-weight scheduler that comes with Itsi
26
+ # `fiber_scheduler "Async::Scheduler"` - Bring your own scheduler!
27
+ fiber_scheduler "Itsi::Scheduler"
28
+
29
+ # If you bind to https, without specifying a certificate, Itsi will use a self-signed certificate.
30
+ # The self-signed certificate will use a CA generated for your
31
+ # host and stored inside `ITSI_LOCAL_CA_DIR` (Defaults to ~/.itsi)
32
+ # bind "https://0.0.0.0:3000"
33
+ # bind "https://0.0.0.0:3000?domains=dev.itsi.fyi"
34
+ #
35
+ # If you want to use let's encrypt to generate you a real certificate you
36
+ # and pass cert=acme and an acme_email address to generate one.
37
+ # bind "https://itsi.fyi?cert=acme&acme_email=admin@itsi.fyi"
38
+ # You can generate certificates for multiple domains at once, by passing a comma-separated list of domains
39
+ # bind "https://0.0.0.0?domains=foo.itsi.fyi,bar.itsi.fyi&cert=acme&acme_email=admin@itsi.fyi"
40
+ #
41
+ # If you already have a certificate you can specify it using the cert and key parameters
42
+ # bind "https://itsi.fyi?cert=/path/to/cert.pem&key=/path/to/key.pem"
43
+ #
44
+ # You can also bind to a unix socket or a tls unix socket. E.g.
45
+ # bind "unix:///tmp/itsi.sock"
46
+ # bind "tls:///tmp/itsi.secure.sock"
47
+
48
+ bind "http://0.0.0.0:#{ENV.fetch("BULLION_PORT", 9292)}"
49
+
50
+ # If you want to preload the application, set preload to true
51
+ # to load the entire rack-app defined in rack_file_name before forking.
52
+ # Alternatively, you can preload just a specific set of gems in a group in your gemfile,
53
+ # by providing the group name here.
54
+ # E.g.
55
+ #
56
+ # preload :preload # Load gems inside the preload group
57
+ # preload false # Don't preload.
58
+ #
59
+ # If you want to be able to perform zero-downtime deploys using a single itsi process,
60
+ # you should disable preloads, so that the application is loaded fresh each time a new worker boots
61
+ preload true
62
+
63
+ # Set the maximum memory limit for each worker process in bytes
64
+ # When this limit is reached, the worker will be gracefully restarted.
65
+ # Only one worker is restarted at a time to ensure we don't take down
66
+ # all of them at once, if they reach the threshold simultaneously.
67
+ worker_memory_limit ENV.fetch("WORKER_MEMORY_LIMIT") { 1024 * 1024 * 1024 } # Default to 1GB
68
+
69
+ # You can provide an optional block of code to run, when a worker hits its memory threshold
70
+ # (Use this to send yourself an alert,
71
+ # write metrics to disk etc. etc.)
72
+ after_memory_limit_reached do |pid|
73
+ puts "Worker #{pid} has reached its memory threshold and will restart"
74
+ end
75
+
76
+ # Do clean up of any non-threadsafe resources before forking a new worker here.
77
+ before_fork {}
78
+
79
+ # Reinitialize any non-threadsafe resources after forking a new worker here.
80
+ after_fork {}
81
+
82
+ # Shutdown timeout
83
+ # Number of seconds to wait for workers to gracefully shutdown before killing them.
84
+ shutdown_timeout 5
85
+
86
+ # Set this to false for application environments that require rack.input to be a rewindable body
87
+ # (like Rails). For rack applications that can stream inputs, you can set this to true for a more
88
+ # memory-efficient approach.
89
+ stream_body false
90
+
91
+ # OOB GC responses threshold
92
+ # Specifies how frequently OOB gc should be triggered during periods where there is a gap in queued requests.
93
+ # Setting this too low can substantially worsen performance
94
+ oob_gc_responses_threshold 512
95
+
96
+ # Log level
97
+ # Set this to one of the following values: debug, info, warn, error, fatal
98
+ # Can also be set using the ITSI_LOG environment variable
99
+ log_level ENV.fetch("LOG_LEVEL", "warn").to_sym
100
+
101
+ # Log Format
102
+ # Set this to be either :plain or :json. If you leave it blank Itsi will try
103
+ # and auto-detect the format based on the TTY environment.
104
+ log_format :plain
105
+ # You can mount several Ruby apps as either
106
+ # 1. rackup files
107
+ # 2. inline rack apps
108
+ # 3. inline Ruby endpoints
109
+ #
110
+ # 1. rackup_file
111
+ rackup_file "./config.ru"
112
+ #
113
+ # 2. inline rack app
114
+ # require 'rack'
115
+ # run(Rack::Builder.app do
116
+ # use Rack::CommonLogger
117
+ # run ->(env) { [200, { 'content-type' => 'text/plain' }, ['OK']] }
118
+ # end)
119
+ #
120
+ # 3. Endpoints
121
+ # endpoint "/" do |req|
122
+ # req.ok "Hello from Itsi"
123
+ # end
data/README.md CHANGED
@@ -40,8 +40,9 @@ Whether run locally or via Docker, the following environment variables configure
40
40
  | `DNS01_NAMESERVERS` | _None_ | A comma-delimited list of nameservers to use for resolving [DNS-01](https://letsencrypt.org/docs/challenge-types/#dns-01-challenge) challenges. Usually you'll want this to be set to your _internal_ nameservers so internal names resolve correctly. When not set, it'll use the host's DNS. |
41
41
  | `LOG_LEVEL` | `warn` | Log level for Bullion. Supported levels (starting with the noisiest) are debug, info, warn, error, and fatal. |
42
42
  | `BULLION_PORT` | `9292` | TCP port Bullion will listen on. |
43
- | `MIN_THREADS` | `2` | Minimum number of [Puma](https://puma.io/) threads for processing requests. |
44
- | `MAX_THREADS` | `32` | Maximum number of [Puma](https://puma.io/) threads for processing requests. |
43
+ | `THREADS` | `3` | Number of [Itsi threads](https://itsi.fyi/options/threads/) for processing requests. |
44
+ | `WORKERS` | `1` | Number of [Itsi workers](https://itsi.fyi/options/workers/) to spawn. |
45
+ | `WORKER_MEMORY_LIMIT` | `1024**3` | [Itsi worker memory limit](https://itsi.fyi/options/worker_memory_limit/) for each worker process (in bytes). Default is 1GiB. |
45
46
  | `RACK_ENV` | `production`* | When run via Docker, the default is `production`, when run via `rake local_demo` it is `development`. Used to tell Bullion if it is run in development mode or for testing. |
46
47
 
47
48
  ### Integrating
data/Rakefile CHANGED
@@ -4,12 +4,62 @@ ENV["RACK_ENV"] ||= "development"
4
4
 
5
5
  if %w[development test].include? ENV["RACK_ENV"]
6
6
  ENV["DATABASE_URL"] = "sqlite3:#{File.expand_path(".")}/tmp/db/#{ENV["RACK_ENV"]}.sqlite3"
7
+ require "bundler/gem_tasks"
8
+ require "rspec/core/rake_task"
9
+ require "rubocop/rake_task"
10
+ require "yard"
11
+
12
+ RSpec::Core::RakeTask.new(:spec) do |t|
13
+ t.exclude_pattern = "spec/integration/**{,/*/**}/*_spec.rb"
14
+ t.rspec_opts = "--require spec_helper"
15
+ end
16
+ RSpec::Core::RakeTask.new(:integration_testing) do |t|
17
+ t.pattern = "spec/integration/**{,/*/**}/*_spec.rb"
18
+ t.rspec_opts = "--require integration_helper"
19
+ end
20
+ RuboCop::RakeTask.new(:rubocop)
21
+ YARD::Rake::YardocTask.new
22
+
23
+ desc "Runs a backgrounded demo environment"
24
+ task :demo do
25
+ rack_env = "test"
26
+ database_url = "sqlite3:#{File.expand_path(".")}/tmp/db/#{rack_env}.sqlite3"
27
+ system("RACK_ENV=\"#{rack_env}\" DATABASE_URL=\"#{database_url}\" bundle exec rake db:migrate")
28
+ system(
29
+ "RACK_ENV=\"#{rack_env}\" DATABASE_URL=\"#{database_url}\" " \
30
+ "LOG_LEVEL='#{ENV.fetch("LOG_LEVEL", "info")}' " \
31
+ "itsi --daemonize"
32
+ )
33
+ FileUtils.touch(File.join(File.expand_path("."), "tmp", "daemon.pid"))
34
+ end
35
+
36
+ desc "Runs a foregrounded demo environment"
37
+ task :foreground_demo do
38
+ system("itsi")
39
+ end
40
+
41
+ desc "Cleans up test or demo environment"
42
+ task :cleanup do
43
+ at_exit do
44
+ pid_file = File.join(File.expand_path("."), "tmp", "daemon.pid")
45
+ if File.exist?(pid_file)
46
+ system("itsi stop")
47
+ FileUtils.rm_f(pid_file)
48
+ end
49
+ FileUtils.rm_f(File.join(File.expand_path("."), "tmp", "tls.crt"))
50
+ FileUtils.rm_f(File.join(File.expand_path("."), "tmp", "tls.key"))
51
+ FileUtils.rm_f(File.join(File.expand_path("."), "tmp", "root_tls.crt"))
52
+ FileUtils.rm_f(File.join(File.expand_path("."), "tmp", "root_tls.key"))
53
+ FileUtils.rm_rf(File.join(File.expand_path("."), "tmp", "db"))
54
+ ENV["CA_DIR"] = nil
55
+ ENV["CA_SECRET"] = nil
56
+ ENV["CA_DOMAINS"] = nil
57
+ end
58
+ end
59
+
60
+ Rake::Task["integration_testing"].enhance(["cleanup"])
7
61
  end
8
62
 
9
- require "bundler/gem_tasks"
10
- require "rspec/core/rake_task"
11
- require "rubocop/rake_task"
12
- require "yard"
13
63
  require "openssl"
14
64
  require "sqlite3"
15
65
  require "sinatra/activerecord/rake"
@@ -22,17 +72,6 @@ namespace :db do
22
72
  end
23
73
  end
24
74
 
25
- RSpec::Core::RakeTask.new(:spec) do |t|
26
- t.exclude_pattern = "spec/integration/**{,/*/**}/*_spec.rb"
27
- t.rspec_opts = "--require spec_helper"
28
- end
29
- RSpec::Core::RakeTask.new(:integration_testing) do |t|
30
- t.pattern = "spec/integration/**{,/*/**}/*_spec.rb"
31
- t.rspec_opts = "--require integration_helper"
32
- end
33
- RuboCop::RakeTask.new(:rubocop)
34
- YARD::Rake::YardocTask.new
35
-
36
75
  desc "Prepares a demo or test environment"
37
76
  task :prep do
38
77
  FileUtils.mkdir_p(File.join(File.expand_path("."), "tmp"))
@@ -48,7 +87,7 @@ task :prep do
48
87
  root_ca.version = 2
49
88
  root_ca.serial = (2**rand(10..20)) - 1
50
89
  root_ca.subject = OpenSSL::X509::Name.parse(
51
- %w[test domain].reverse.map { |piece| "DC=#{piece}" }.join("/") + "/CN=bullion"
90
+ %w[test domain].reverse.map { "DC=#{it}" }.join("/") + "/CN=bullion"
52
91
  )
53
92
  root_ca.issuer = root_ca.subject # root CA's are "self-signed"
54
93
  root_ca.public_key = root_key.public_key
@@ -108,45 +147,6 @@ task :prep do
108
147
  )
109
148
  end
110
149
 
111
- desc "Runs a backgrounded demo environment"
112
- task :demo do
113
- rack_env = "test"
114
- database_url = "sqlite3:#{File.expand_path(".")}/tmp/db/#{rack_env}.sqlite3"
115
- system("RACK_ENV=\"#{rack_env}\" DATABASE_URL=\"#{database_url}\" bundle exec rake db:migrate")
116
- system(
117
- "RACK_ENV=\"#{rack_env}\" DATABASE_URL=\"#{database_url}\" " \
118
- "LOG_LEVEL='#{ENV.fetch("LOG_LEVEL", "info")}' " \
119
- "rackup -D -P #{File.expand_path(".")}/tmp/daemon.pid"
120
- )
121
- end
122
-
123
- desc "Runs a foregrounded demo environment"
124
- task :foreground_demo do
125
- system("rackup -o 0.0.0.0 -P #{File.expand_path(".")}/tmp/daemon.pid")
126
- end
127
-
128
- desc "Cleans up test or demo environment"
129
- task :cleanup do
130
- at_exit do
131
- pid_file = File.join(File.expand_path("."), "tmp", "daemon.pid")
132
- if File.exist?(pid_file)
133
- pid = File.read(pid_file).to_i
134
- Process.kill("TERM", pid)
135
- FileUtils.rm_f(pid_file)
136
- end
137
- FileUtils.rm_f(File.join(File.expand_path("."), "tmp", "tls.crt"))
138
- FileUtils.rm_f(File.join(File.expand_path("."), "tmp", "tls.key"))
139
- FileUtils.rm_f(File.join(File.expand_path("."), "tmp", "root_tls.crt"))
140
- FileUtils.rm_f(File.join(File.expand_path("."), "tmp", "root_tls.key"))
141
- FileUtils.rm_rf(File.join(File.expand_path("."), "tmp", "db"))
142
- ENV["CA_DIR"] = nil
143
- ENV["CA_SECRET"] = nil
144
- ENV["CA_DOMAINS"] = nil
145
- end
146
- end
147
-
148
- Rake::Task["integration_testing"].enhance(["cleanup"])
149
-
150
150
  task test: %i[prep db:migrate spec demo integration_testing]
151
151
  task unit: %i[prep db:migrate spec]
152
152
 
data/bullion.gemspec CHANGED
@@ -24,21 +24,21 @@ Gem::Specification.new do |spec|
24
24
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
25
25
  spec.require_paths = ["lib"]
26
26
 
27
- spec.required_ruby_version = "~> 3.3"
27
+ spec.required_ruby_version = "~> 3.4"
28
28
 
29
29
  spec.add_dependency "benchmark", "~> 0.4"
30
30
  spec.add_dependency "dry-configurable", "~> 1.1"
31
31
  spec.add_dependency "httparty", "~> 0.21"
32
+ spec.add_dependency "itsi", "~> 0.2"
32
33
  spec.add_dependency "json", "~> 2.6"
33
34
  spec.add_dependency "jwt", "~> 2.7"
34
35
  spec.add_dependency "mysql2", "~> 0.5"
35
36
  spec.add_dependency "openssl", "~> 3.0"
36
37
  spec.add_dependency "prometheus-client", "~> 4.2"
37
- spec.add_dependency "puma", "~> 6.4"
38
38
  spec.add_dependency "sinatra", "~> 3.1"
39
39
  spec.add_dependency "sinatra-activerecord", "~> 2.0"
40
40
  spec.add_dependency "sinatra-contrib", "~> 3.1"
41
- spec.add_dependency "sqlite3", "~> 2.6"
41
+ spec.add_dependency "sqlite3", "~> 2.7"
42
42
 
43
43
  spec.add_development_dependency "acme-client", "~> 2.0"
44
44
  spec.add_development_dependency "bundler", "~> 2.4"
data/config.ru CHANGED
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # \ -s puma
4
-
5
3
  require "bullion"
6
4
  Bullion.validate_config!
7
5
 
@@ -27,7 +27,7 @@ module Bullion
27
27
  benchtime = Benchmark.realtime do
28
28
  until success || tries >= retries
29
29
  tries += 1
30
- success = perform
30
+ success = performs_challenge?
31
31
  if success
32
32
  LOGGER.info "Validated #{type} #{identifier}"
33
33
  challenge.status = "valid"
@@ -59,5 +59,9 @@ module Bullion
59
59
  def identifier
60
60
  challenge.identifier
61
61
  end
62
+
63
+ def performs_challenge?
64
+ raise NotImplementedError
65
+ end
62
66
  end
63
67
  end
@@ -8,7 +8,7 @@ module Bullion
8
8
  def self.acme_type = "dns-01"
9
9
  def type = "DNS01"
10
10
 
11
- def perform
11
+ def performs_challenge?
12
12
  value = dns_value
13
13
  expected_value = digest_value("#{challenge.token}.#{challenge.thumbprint}")
14
14
 
@@ -8,7 +8,7 @@ module Bullion
8
8
  def self.acme_type = "http-01"
9
9
  def type = "HTTP01"
10
10
 
11
- def perform
11
+ def performs_challenge?
12
12
  response = begin
13
13
  retrieve_body(challenge_url)
14
14
  rescue SocketError
@@ -88,7 +88,7 @@ module Bullion
88
88
 
89
89
  # Validation helpers
90
90
 
91
- def validate_account_data(hash)
91
+ def account_data_valid?(hash)
92
92
  unless [true, false, nil].include?(hash["onlyReturnExisting"])
93
93
  raise Bullion::Acme::Errors::Malformed,
94
94
  "Invalid onlyReturnExisting: #{hash["onlyReturnExisting"]}"
@@ -113,31 +113,31 @@ module Bullion
113
113
  true
114
114
  end
115
115
 
116
- def validate_acme_csr(order, csr)
116
+ def acme_csr_valid?(order_csr)
117
+ csr = order_csr.csr
118
+ order = order_csr.order
117
119
  csr_attrs = extract_csr_attrs(csr)
118
120
  csr_sans = extract_csr_sans(csr_attrs)
119
121
  csr_domains = extract_csr_domains(csr_sans)
120
122
  csr_cn = cn_from_csr(csr)
121
123
 
122
- order_domains = order.identifiers.map { |i| i["value"] }
123
-
124
124
  # Make sure the CSR has a valid public key
125
125
  raise Bullion::Acme::Errors::BadCsr unless csr.verify(csr.public_key)
126
126
 
127
- return false unless order.status == "ready"
127
+ return false unless order.ready_status?
128
128
  raise Bullion::Acme::Errors::BadCsr unless csr_domains.include?(csr_cn)
129
- raise Bullion::Acme::Errors::BadCsr unless csr_domains.sort == order_domains.sort
129
+ raise Bullion::Acme::Errors::BadCsr unless csr_domains.sort == order.domains.sort
130
130
 
131
131
  true
132
132
  end
133
133
 
134
- def validate_order(hash)
134
+ def order_valid?(hash)
135
135
  validate_order_nb_and_na(hash["notBefore"], hash["notAfter"])
136
136
 
137
137
  # Don't approve empty orders
138
138
  raise Bullion::Acme::Errors::InvalidOrder, "Empty order!" if hash["identifiers"].empty?
139
139
 
140
- order_domains = hash["identifiers"].select { |ident| ident["type"] == "dns" }
140
+ order_domains = hash["identifiers"].select { it["type"] == "dns" }
141
141
 
142
142
  # Don't approve an order with identifiers that _aren't_ of type 'dns'
143
143
  unless hash["identifiers"] == order_domains
@@ -188,7 +188,7 @@ module Bullion
188
188
 
189
189
  def extract_valid_order_domains(order_domains)
190
190
  order_domains.reject do |domain|
191
- Bullion.config.ca.domains.none? { domain["value"].end_with?(_1) }
191
+ Bullion.config.ca.domains.none? { domain["value"].end_with?(it) }
192
192
  end
193
193
  end
194
194
  end
@@ -14,11 +14,6 @@ module Bullion
14
14
  end
15
15
  end
16
16
 
17
- def openssl_compat_csr(csrdata)
18
- "-----BEGIN CERTIFICATE REQUEST-----\n" \
19
- "#{csrdata}-----END CERTIFICATE REQUEST-----"
20
- end
21
-
22
17
  # @see https://tools.ietf.org/html/rfc7518#page-30
23
18
  def key_data_to_rsa(key_data)
24
19
  exponent = base64_to_long(key_data["e"])
@@ -13,6 +13,15 @@ module Bullion
13
13
 
14
14
  validates :status, inclusion: { in: %w[invalid pending ready processing valid deactivated] }
15
15
 
16
+ enum :status, {
17
+ invalid: "invalid",
18
+ pending: "pending",
19
+ ready: "ready",
20
+ processing: "processing",
21
+ valid: "valid",
22
+ deactivated: "deactivated"
23
+ }, suffix: "status"
24
+
16
25
  def init_values
17
26
  self.expires ||= Time.now + (60 * 60)
18
27
  end
@@ -10,6 +10,8 @@ module Bullion
10
10
 
11
11
  validates_presence_of :subject
12
12
 
13
+ has_one :order
14
+
13
15
  def init_values
14
16
  self.serial ||= SecureRandom.hex(4).to_i(16)
15
17
  end
@@ -13,6 +13,13 @@ module Bullion
13
13
  }
14
14
  validates :status, inclusion: { in: %w[invalid pending processing valid] }
15
15
 
16
+ enum :status, {
17
+ invalid: "invalid",
18
+ pending: "pending",
19
+ processing: "processing",
20
+ valid: "valid"
21
+ }, suffix: "status"
22
+
16
23
  def identifier
17
24
  authorization.identifier["value"]
18
25
  end
@@ -29,7 +36,7 @@ module Bullion
29
36
  end
30
37
 
31
38
  def client
32
- challenge_class = Bullion.acme.challenge_clients.find { _1.acme_type == acme_type }
39
+ challenge_class = Bullion.acme.challenge_clients.find { it.acme_type == acme_type }
33
40
 
34
41
  unless challenge_class
35
42
  raise Bullion::Acme::Errors::UnsupportedChallengeType,
@@ -9,10 +9,19 @@ module Bullion
9
9
  after_initialize :init_values, unless: :persisted?
10
10
 
11
11
  belongs_to :account
12
+ belongs_to :certificate
12
13
  has_many :authorizations
13
14
 
14
15
  validates :status, inclusion: { in: %w[invalid pending ready processing valid] }
15
16
 
17
+ enum :status, {
18
+ invalid: "invalid",
19
+ pending: "pending",
20
+ ready: "ready",
21
+ processing: "processing",
22
+ valid: "valid"
23
+ }, suffix: "status"
24
+
16
25
  def init_values
17
26
  self.expires ||= Time.now + (60 * 60)
18
27
  self.not_before ||= Time.now
@@ -31,9 +40,8 @@ module Bullion
31
40
  end
32
41
  end
33
42
 
34
- def certificate
35
- Certificate.find(certificate_id)
36
- end
43
+ # Used to extract domains from order (mostly for comparison with CSR)
44
+ def domains = identifiers.map { it["value"] }
37
45
  end
38
46
  end
39
47
  end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bullion
4
+ module Models
5
+ # Pseudo-model for ACMEv2 Order CSR
6
+ class OrderCsr
7
+ class << self
8
+ def from_acme_request(order, raw_data)
9
+ decoded_data = Base64.urlsafe_decode64(raw_data)
10
+ reencoded_data = Base64.encode64(decoded_data)
11
+ csr_string = openssl_compat_csr(reencoded_data)
12
+
13
+ new(order, csr_string)
14
+ end
15
+
16
+ private
17
+
18
+ def openssl_compat_csr(csrdata)
19
+ "-----BEGIN CERTIFICATE REQUEST-----\n" \
20
+ "#{csrdata}-----END CERTIFICATE REQUEST-----"
21
+ end
22
+ end
23
+
24
+ attr_reader :csr, :order
25
+
26
+ def initialize(order, csr)
27
+ @order = order.is_a?(Order) ? order : Order.find(order)
28
+ @csr = if csr.is_a?(String)
29
+ OpenSSL::X509::Request.new(csr)
30
+ else
31
+ csr
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -6,3 +6,6 @@ require "bullion/models/certificate"
6
6
  require "bullion/models/challenge"
7
7
  require "bullion/models/nonce"
8
8
  require "bullion/models/order"
9
+
10
+ # Pseudo-models (not in DB)
11
+ require "bullion/models/order_csr"
@@ -121,7 +121,7 @@ module Bullion
121
121
  begin
122
122
  parse_acme_jwt(header_data["jwk"], validate_nonce: false)
123
123
 
124
- validate_account_data(@payload_data)
124
+ account_data_valid?(@payload_data)
125
125
  rescue Bullion::Acme::Error => e
126
126
  content_type "application/problem+json"
127
127
  halt 400, { type: e.acme_error, detail: e.message }.to_json
@@ -186,7 +186,7 @@ module Bullion
186
186
  add_acme_headers @new_nonce
187
187
 
188
188
  {
189
- orders: @user.orders.map { |order| uri("/orders/#{order.id}") }
189
+ orders: @user.orders.map { uri("/orders/#{it.id}") }
190
190
  }
191
191
  end
192
192
 
@@ -196,9 +196,9 @@ module Bullion
196
196
  parse_acme_jwt
197
197
 
198
198
  # Only identifiers of type "dns" are supported
199
- identifiers = @payload_data["identifiers"].select { |i| i["type"] == "dns" }
199
+ identifiers = @payload_data["identifiers"].select { it["type"] == "dns" }
200
200
 
201
- validate_order(@payload_data)
201
+ order_valid?(@payload_data)
202
202
 
203
203
  order = @user.start_order(
204
204
  identifiers:,
@@ -215,7 +215,7 @@ module Bullion
215
215
  notBefore: order.not_before,
216
216
  notAfter: order.not_after,
217
217
  identifiers: order.identifiers,
218
- authorizations: order.authorizations.map { |a| uri("/authorizations/#{a.id}") },
218
+ authorizations: order.authorizations.map { uri("/authorizations/#{it.id}") },
219
219
  finalize: uri("/orders/#{order.id}/finalize")
220
220
  }.to_json
221
221
  rescue Bullion::Acme::Error => e
@@ -238,11 +238,11 @@ module Bullion
238
238
  notBefore: order.not_before,
239
239
  notAfter: order.not_after,
240
240
  identifiers: order.identifiers,
241
- authorizations: order.authorizations.map { |a| uri("/authorizations/#{a.id}") },
241
+ authorizations: order.authorizations.map { uri("/authorizations/#{it.id}") },
242
242
  finalize: uri("/orders/#{order.id}/finalize")
243
243
  }
244
244
 
245
- data[:certificate] = uri("/certificates/#{order.certificate.id}") if order.status == "valid"
245
+ data[:certificate] = uri("/certificates/#{order.certificate.id}") if order.valid_status?
246
246
 
247
247
  data.to_json
248
248
  rescue Bullion::Acme::Error => e
@@ -260,14 +260,9 @@ module Bullion
260
260
  content_type "application/json"
261
261
  add_acme_headers @new_nonce, additional: { "Location" => uri("/orders/#{order.id}") }
262
262
 
263
- raw_csr_data = Base64.urlsafe_decode64(@payload_data["csr"])
264
- encoded_csr = Base64.encode64(raw_csr_data)
263
+ order_csr = Models::OrderCsr.from_acme_request(order, @payload_data["csr"])
265
264
 
266
- csr_data = openssl_compat_csr(encoded_csr)
267
-
268
- csr = OpenSSL::X509::Request.new(csr_data)
269
-
270
- unless validate_acme_csr(order, csr)
265
+ unless acme_csr_valid?(order_csr)
271
266
  content_type "application/problem+json"
272
267
  halt 400, {
273
268
  type: Bullion::Acme::Errors::BadCsr.new.acme_error,
@@ -275,7 +270,7 @@ module Bullion
275
270
  }.to_json
276
271
  end
277
272
 
278
- cert_id = sign_csr(csr, @user.contacts.first).last
273
+ cert_id = sign_csr(order_csr.csr, @user.contacts.first).last
279
274
 
280
275
  order.certificate_id = cert_id
281
276
  order.status = "valid"
@@ -287,11 +282,11 @@ module Bullion
287
282
  notBefore: order.not_before,
288
283
  notAfter: order.not_after,
289
284
  identifiers: order.identifiers,
290
- authorizations: order.authorizations.map { |a| uri("/authorizations/#{a.id}") },
285
+ authorizations: order.authorizations.map { uri("/authorizations/#{it.id}") },
291
286
  finalize: uri("/orders/#{order.id}/finalize")
292
287
  }
293
288
 
294
- data[:certificate] = uri("/certificates/#{order.certificate.id}") if order.status == "valid"
289
+ data[:certificate] = uri("/certificates/#{order.certificate.id}") if order.valid_status?
295
290
 
296
291
  data.to_json
297
292
  rescue Bullion::Acme::Error => e
@@ -320,7 +315,7 @@ module Bullion
320
315
  chash[:url] = uri("/challenges/#{c.id}")
321
316
  chash[:token] = c.token
322
317
  chash[:status] = c.status
323
- chash[:validated] = c.validated if c.status == "valid"
318
+ chash[:validated] = c.validated if c.valid_status?
324
319
 
325
320
  chash
326
321
  end
@@ -355,12 +350,12 @@ module Bullion
355
350
  url: uri("/challenges/#{challenge.id}")
356
351
  }
357
352
 
358
- if challenge.status == "valid"
353
+ if challenge.valid_status?
359
354
  data[:validated] = challenge.validated
360
355
  authorization = challenge.authorization
361
- authorization.update!(status: "valid") unless authorization.status == "valid"
356
+ authorization.update!(status: "valid") unless authorization.valid_status?
362
357
  order = authorization.order
363
- order.update!(status: "ready") unless order.status == "ready"
358
+ order.update!(status: "ready") unless order.ready_status?
364
359
  end
365
360
 
366
361
  add_link_relation("up", uri("/authorizations/#{challenge.authorization.id}"))
@@ -378,7 +373,7 @@ module Bullion
378
373
  add_acme_headers @new_nonce
379
374
 
380
375
  order = Models::Order.where(certificate_id: params[:id]).first
381
- if order && order.status == "valid"
376
+ if order&.valid_status?
382
377
  content_type "application/pem-certificate-chain"
383
378
 
384
379
  cert = Models::Certificate.find(params[:id])
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bullion
4
- VERSION = "0.8.0"
4
+ VERSION = "0.10.0"
5
5
  end
data/lib/bullion.rb CHANGED
@@ -32,7 +32,7 @@ module Bullion
32
32
  LOGGER.level = ENV.fetch("LOG_LEVEL", :warn)
33
33
 
34
34
  setting :ca, reader: true do
35
- setting :dir, default: "tmp", constructor: -> { File.expand_path(_1) }
35
+ setting :dir, default: "tmp", constructor: -> { File.expand_path(it) }
36
36
  setting :secret, default: "SomeS3cret"
37
37
  setting(
38
38
  :key_path,
@@ -48,22 +48,22 @@ module Bullion
48
48
  v.include?("/") ? File.expand_path(v) : File.join(Bullion.config.ca.dir, v)
49
49
  }
50
50
  )
51
- setting :domains, default: "example.com", constructor: -> { _1.split(",") }
51
+ setting :domains, default: "example.com", constructor: -> { it.split(",") }
52
52
  # 90 days cert expiration
53
- setting :cert_validity_duration, default: 60 * 60 * 24 * 30 * 3, constructor: -> { Integer(_1) }
53
+ setting :cert_validity_duration, default: 60 * 60 * 24 * 30 * 3, constructor: -> { Integer(it) }
54
54
  end
55
55
 
56
56
  setting :acme, reader: true do
57
57
  setting(
58
58
  :challenge_clients,
59
59
  default: ["Bullion::ChallengeClients::DNS", "Bullion::ChallengeClients::HTTP"],
60
- constructor: -> { _1.map { |n| Kernel.const_get(n.to_s) } }
60
+ constructor: -> { it.map { |n| Kernel.const_get(n.to_s) } }
61
61
  )
62
62
  end
63
63
 
64
64
  setting :db_url, reader: true
65
65
 
66
- setting :nameservers, default: [], constructor: -> { _1.split(",") }
66
+ setting :nameservers, default: [], constructor: -> { it.split(",") }
67
67
 
68
68
  MetricsRegistry = Prometheus::Client.registry
69
69
 
@@ -79,7 +79,7 @@ module Bullion
79
79
  @ca_cert ||= OpenSSL::X509::Certificate.new(ca_cert_file)
80
80
  end
81
81
 
82
- def self.rotate_keys!
82
+ def self.rotate_keys! # rubocop:disable Naming/PredicateMethod
83
83
  @ca_key = nil
84
84
  @ca_cert = nil
85
85
  ca_key
@@ -2,8 +2,4 @@
2
2
 
3
3
  # Starts the server
4
4
  rake db:migrate
5
- puma \
6
- -p ${BULLION_PORT:-9292} \
7
- -e ${RACK_ENV:-production} \
8
- -t ${MIN_THREADS:-2}:${MAX_THREADS:-32} \
9
- config.ru
5
+ itsi
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bullion
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonathan Gnagy
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2025-03-14 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: benchmark
@@ -52,6 +51,20 @@ dependencies:
52
51
  - - "~>"
53
52
  - !ruby/object:Gem::Version
54
53
  version: '0.21'
54
+ - !ruby/object:Gem::Dependency
55
+ name: itsi
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '0.2'
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '0.2'
55
68
  - !ruby/object:Gem::Dependency
56
69
  name: json
57
70
  requirement: !ruby/object:Gem::Requirement
@@ -122,20 +135,6 @@ dependencies:
122
135
  - - "~>"
123
136
  - !ruby/object:Gem::Version
124
137
  version: '4.2'
125
- - !ruby/object:Gem::Dependency
126
- name: puma
127
- requirement: !ruby/object:Gem::Requirement
128
- requirements:
129
- - - "~>"
130
- - !ruby/object:Gem::Version
131
- version: '6.4'
132
- type: :runtime
133
- prerelease: false
134
- version_requirements: !ruby/object:Gem::Requirement
135
- requirements:
136
- - - "~>"
137
- - !ruby/object:Gem::Version
138
- version: '6.4'
139
138
  - !ruby/object:Gem::Dependency
140
139
  name: sinatra
141
140
  requirement: !ruby/object:Gem::Requirement
@@ -184,14 +183,14 @@ dependencies:
184
183
  requirements:
185
184
  - - "~>"
186
185
  - !ruby/object:Gem::Version
187
- version: '2.6'
186
+ version: '2.7'
188
187
  type: :runtime
189
188
  prerelease: false
190
189
  version_requirements: !ruby/object:Gem::Requirement
191
190
  requirements:
192
191
  - - "~>"
193
192
  - !ruby/object:Gem::Version
194
- version: '2.6'
193
+ version: '2.7'
195
194
  - !ruby/object:Gem::Dependency
196
195
  name: acme-client
197
196
  requirement: !ruby/object:Gem::Requirement
@@ -374,7 +373,6 @@ dependencies:
374
373
  - - "~>"
375
374
  - !ruby/object:Gem::Version
376
375
  version: '0.9'
377
- description:
378
376
  email:
379
377
  - jonathan.gnagy@gmail.com
380
378
  executables: []
@@ -394,6 +392,7 @@ files:
394
392
  - Dockerfile
395
393
  - Gemfile
396
394
  - Gemfile.lock
395
+ - Itsi.rb
397
396
  - LICENSE.txt
398
397
  - README.md
399
398
  - Rakefile
@@ -401,7 +400,6 @@ files:
401
400
  - bin/setup
402
401
  - bullion.gemspec
403
402
  - config.ru
404
- - config/puma.rb
405
403
  - db/migrate/20210104000000_create_accounts.rb
406
404
  - db/migrate/20210104060422_create_certificates.rb
407
405
  - db/migrate/20210105060406_create_orders.rb
@@ -424,6 +422,7 @@ files:
424
422
  - lib/bullion/models/challenge.rb
425
423
  - lib/bullion/models/nonce.rb
426
424
  - lib/bullion/models/order.rb
425
+ - lib/bullion/models/order_csr.rb
427
426
  - lib/bullion/rspec/challenge_clients/dns.rb
428
427
  - lib/bullion/rspec/challenge_clients/http.rb
429
428
  - lib/bullion/service.rb
@@ -442,7 +441,6 @@ licenses:
442
441
  metadata:
443
442
  homepage_uri: https://github.com/jgnagy/bullion
444
443
  source_code_uri: https://github.com/jgnagy/bullion
445
- post_install_message:
446
444
  rdoc_options: []
447
445
  require_paths:
448
446
  - lib
@@ -450,15 +448,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
450
448
  requirements:
451
449
  - - "~>"
452
450
  - !ruby/object:Gem::Version
453
- version: '3.3'
451
+ version: '3.4'
454
452
  required_rubygems_version: !ruby/object:Gem::Requirement
455
453
  requirements:
456
454
  - - ">="
457
455
  - !ruby/object:Gem::Version
458
456
  version: '0'
459
457
  requirements: []
460
- rubygems_version: 3.5.11
461
- signing_key:
458
+ rubygems_version: 3.6.7
462
459
  specification_version: 4
463
460
  summary: Ruby ACME v2 Certificate Authority
464
461
  test_files: []
data/config/puma.rb DELETED
@@ -1,3 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- threads 2, Integer(ENV.fetch("MAX_THREADS", 32))