acmesmith 2.6.0 → 2.7.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: 914be0de4c237bcd0db59a908f8ce70c3f7b364bb2ab0ac25b6e26ff95ecd7bc
4
- data.tar.gz: 14b96550d4ef0274d1546e78b5121c6b9356e9c71e479a4ed17b4d9ff8fc669e
3
+ metadata.gz: '00710093e0dc9f9ec6ba1d54bf67585d45efa053e8a6bd7250c638abfce17908'
4
+ data.tar.gz: ecff83969fbf75e8566f1f75638b35937615af3d9fe05a759663d1a82b5d11af
5
5
  SHA512:
6
- metadata.gz: ce305e972fcb06a4bc97b2ceea2177cd759601c55064dd5e22ea15b0981ea838e7c11d8e5401d08c41ec1f249cfa0d7a6489f67b2c3e52cc8d67bd1871d77e69
7
- data.tar.gz: dfabb130f347dc7829cbaad1b5de6aca553dfedc7172d53d163736baee2b07b00124ef7f5f31d9270df660f4b9381b05ed6ca6cfa2e9a96163f25d6fa2d83286
6
+ metadata.gz: 6df65f1bef30badd2f6691bebeeadf2548d878404a31b166a8fb607aae1027c02345162db7068bb3eb276718aae819dd31ec0188a6075d6fd69d28252d4c79d6
7
+ data.tar.gz: c2689ab6ffcd876a5af2c7c4b25c1b4b2553c20c07472b8698d1b43787ad2ed5bac72354381aa76b4da6fb64fd5a2f60b2ee09006f58caa1b16083e12067e391
@@ -18,20 +18,13 @@ jobs:
18
18
  strategy:
19
19
  fail-fast: false
20
20
  matrix:
21
- ruby-version: ['3.0', '3.1', '3.2']
22
- container:
23
- image: public.ecr.aws/sorah/ruby:${{ matrix.ruby-version }}-dev
21
+ ruby-version: ['3.2', '3.3', '3.4']
24
22
  steps:
25
-
26
- - name: Cache bundled gems
27
- uses: actions/cache@v1
28
- id: rspec-bundle
29
- with:
30
- path: ~/bundle
31
- key: ${{ runner.os }}-${{ matrix.ruby-version }}
32
-
33
23
  - uses: actions/checkout@master
34
- - run: 'bundle install --path ~/bundle'
24
+ - uses: sorah-rbpkg/actions@v2
25
+ with:
26
+ ruby-version: "${{ matrix.ruby-version }}"
27
+ bundler-cache: true
35
28
  - run: 'bundle exec rspec -fd'
36
29
 
37
30
  integration-pebble:
@@ -40,7 +33,7 @@ jobs:
40
33
  strategy:
41
34
  fail-fast: false
42
35
  matrix:
43
- ruby-version: ['3.0', '3.1', '3.2']
36
+ ruby-version: ['3.2', '3.3', '3.4']
44
37
 
45
38
  # FIXME: once GitHub Actions gains support of adding command line arguments to container
46
39
  # services:
@@ -63,16 +56,14 @@ jobs:
63
56
  steps:
64
57
  - uses: actions/checkout@master
65
58
 
66
- - name: Cache bundled gems
67
- uses: actions/cache@v1
68
- id: instegration-pebble-bundle
59
+ - uses: sorah-rbpkg/actions@v2
69
60
  with:
70
- path: ~/bundle
71
- key: ${{ runner.os }}-${{ matrix.ruby-version }}
61
+ ruby-version: "${{ matrix.ruby-version }}"
62
+ bundler-cache: true
72
63
 
73
64
  - run: 'docker run -d --net=host --rm letsencrypt/pebble pebble -config /test/config/pebble-config.json -strict -dnsserver 127.0.0.1:8053'
74
65
  - run: 'docker run -d --net=host --rm letsencrypt/pebble-challtestsrv pebble-challtestsrv -management :8055 -defaultIPv4 127.0.0.1'
75
- - run: 'docker run --net=host -e CI --rm -v $(pwd):/work -v $(realpath ~/bundle):/bundle public.ecr.aws/sorah/ruby:${{ matrix.ruby-version }}-dev sh -c "cd /work && bundle install --path /bundle && bundle exec rspec -fd -t integration_pebble"'
66
+ - run: 'bundle exec rspec -fd -t integration_pebble'
76
67
 
77
68
  docker-build:
78
69
  name: docker-build
data/CHANGELOG.md CHANGED
@@ -1,3 +1,21 @@
1
+ ## v2.7.0 (2025-04-28)
2
+
3
+ ### Enhancements
4
+
5
+ - autorenew: gains new option `--remaining-life` (`-r`) to specify threshold in ratio of remaining lifetime to total lifetime, e.g. `1/3`, `50%`.
6
+
7
+ ### New behaviour
8
+
9
+ - autonenew: in addition to above, the default option is now adjusted to `--reamining-life 1/3` instead of `--days 7`. This conforms to the Let's Encrypt recommendation to renew certificates when its remaining lifetime is less than 1/3 of the total lifetime.
10
+ - docker: our provided Docker image now bundles rexml instead of nokogiri for aws-sdk-route53.
11
+
12
+
13
+ ## v2.6.1 (2024-12-05)
14
+
15
+ ### Fixes
16
+
17
+ - route53: restore_to_original_records can have an error when querying existing record sets when it generates a name with leading empty labels (OTOH: double leading dots). [#65](https://github.com/sorah/acmesmith/pull/65)
18
+
1
19
  ## v2.6.0 (2023-10-05)
2
20
 
3
21
  ### Enhancement
data/Dockerfile CHANGED
@@ -1,4 +1,4 @@
1
- FROM sorah/ruby:3.2-dev as builder
1
+ FROM sorah/ruby:3.4-dev as builder
2
2
 
3
3
  #RUN apt-get update \
4
4
  # && apt-get install -y libmysqlclient-dev git-core \
@@ -12,7 +12,7 @@ RUN sed -i -e 's|Acmesmith::VERSION|"0.0.0"|g' -e '/^require.*acmesmith.version/
12
12
 
13
13
  RUN bundle install --path /gems --jobs 100 --without development
14
14
 
15
- FROM sorah/ruby:3.2
15
+ FROM sorah/ruby:3.4
16
16
 
17
17
  #RUN apt-get update \
18
18
  # && apt-get install -y libmysqlclient20 \
data/Gemfile CHANGED
@@ -3,4 +3,4 @@ source 'https://rubygems.org'
3
3
  # Specify your gem's dependencies in acmesmith.gemspec
4
4
  gemspec
5
5
 
6
- gem 'nokogiri'
6
+ gem 'rexml'
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- acmesmith (2.6.0)
4
+ acmesmith (2.7.0)
5
5
  acme-client (>= 2.0.7, < 3)
6
6
  aws-sdk-acm
7
7
  aws-sdk-route53
@@ -11,62 +11,64 @@ PATH
11
11
  GEM
12
12
  remote: https://rubygems.org/
13
13
  specs:
14
- acme-client (2.0.14)
14
+ acme-client (2.0.19)
15
+ base64 (~> 0.2.0)
15
16
  faraday (>= 1.0, < 3.0.0)
16
17
  faraday-retry (>= 1.0, < 3.0.0)
17
- aws-eventstream (1.2.0)
18
- aws-partitions (1.832.0)
19
- aws-sdk-acm (1.62.0)
20
- aws-sdk-core (~> 3, >= 3.184.0)
21
- aws-sigv4 (~> 1.1)
22
- aws-sdk-core (3.185.0)
23
- aws-eventstream (~> 1, >= 1.0.2)
24
- aws-partitions (~> 1, >= 1.651.0)
18
+ aws-eventstream (1.3.0)
19
+ aws-partitions (1.1018.0)
20
+ aws-sdk-acm (1.81.0)
21
+ aws-sdk-core (~> 3, >= 3.210.0)
25
22
  aws-sigv4 (~> 1.5)
23
+ aws-sdk-core (3.214.0)
24
+ aws-eventstream (~> 1, >= 1.3.0)
25
+ aws-partitions (~> 1, >= 1.992.0)
26
+ aws-sigv4 (~> 1.9)
26
27
  jmespath (~> 1, >= 1.6.1)
27
- aws-sdk-kms (1.72.0)
28
- aws-sdk-core (~> 3, >= 3.184.0)
29
- aws-sigv4 (~> 1.1)
30
- aws-sdk-route53 (1.79.0)
31
- aws-sdk-core (~> 3, >= 3.184.0)
32
- aws-sigv4 (~> 1.1)
33
- aws-sdk-s3 (1.136.0)
34
- aws-sdk-core (~> 3, >= 3.181.0)
28
+ aws-sdk-kms (1.96.0)
29
+ aws-sdk-core (~> 3, >= 3.210.0)
30
+ aws-sigv4 (~> 1.5)
31
+ aws-sdk-route53 (1.105.0)
32
+ aws-sdk-core (~> 3, >= 3.210.0)
33
+ aws-sigv4 (~> 1.5)
34
+ aws-sdk-s3 (1.176.0)
35
+ aws-sdk-core (~> 3, >= 3.210.0)
35
36
  aws-sdk-kms (~> 1)
36
- aws-sigv4 (~> 1.6)
37
- aws-sigv4 (1.6.0)
37
+ aws-sigv4 (~> 1.5)
38
+ aws-sigv4 (1.10.1)
38
39
  aws-eventstream (~> 1, >= 1.0.2)
39
- base64 (0.1.1)
40
- diff-lcs (1.4.4)
41
- faraday (2.7.11)
42
- base64
43
- faraday-net_http (>= 2.0, < 3.1)
44
- ruby2_keywords (>= 0.0.4)
45
- faraday-net_http (3.0.2)
46
- faraday-retry (2.2.0)
40
+ base64 (0.2.0)
41
+ diff-lcs (1.5.1)
42
+ faraday (2.12.1)
43
+ faraday-net_http (>= 2.0, < 3.5)
44
+ json
45
+ logger
46
+ faraday-net_http (3.4.0)
47
+ net-http (>= 0.5.0)
48
+ faraday-retry (2.2.1)
47
49
  faraday (~> 2.0)
48
50
  jmespath (1.6.2)
49
- mini_portile2 (2.8.1)
50
- nokogiri (1.14.3)
51
- mini_portile2 (~> 2.8.0)
52
- racc (~> 1.4)
53
- racc (1.6.2)
54
- rake (13.0.6)
55
- rspec (3.10.0)
56
- rspec-core (~> 3.10.0)
57
- rspec-expectations (~> 3.10.0)
58
- rspec-mocks (~> 3.10.0)
59
- rspec-core (3.10.1)
60
- rspec-support (~> 3.10.0)
61
- rspec-expectations (3.10.1)
51
+ json (2.9.0)
52
+ logger (1.6.2)
53
+ net-http (0.6.0)
54
+ uri
55
+ rake (13.2.1)
56
+ rexml (3.4.1)
57
+ rspec (3.13.0)
58
+ rspec-core (~> 3.13.0)
59
+ rspec-expectations (~> 3.13.0)
60
+ rspec-mocks (~> 3.13.0)
61
+ rspec-core (3.13.2)
62
+ rspec-support (~> 3.13.0)
63
+ rspec-expectations (3.13.3)
62
64
  diff-lcs (>= 1.2.0, < 2.0)
63
- rspec-support (~> 3.10.0)
64
- rspec-mocks (3.10.2)
65
+ rspec-support (~> 3.13.0)
66
+ rspec-mocks (3.13.2)
65
67
  diff-lcs (>= 1.2.0, < 2.0)
66
- rspec-support (~> 3.10.0)
67
- rspec-support (3.10.2)
68
- ruby2_keywords (0.0.5)
69
- thor (1.2.2)
68
+ rspec-support (~> 3.13.0)
69
+ rspec-support (3.13.2)
70
+ thor (1.3.2)
71
+ uri (1.0.3)
70
72
 
71
73
  PLATFORMS
72
74
  ruby
@@ -74,9 +76,9 @@ PLATFORMS
74
76
  DEPENDENCIES
75
77
  acmesmith!
76
78
  bundler
77
- nokogiri
78
79
  rake
80
+ rexml
79
81
  rspec
80
82
 
81
83
  BUNDLED WITH
82
- 2.1.4
84
+ 2.5.23
data/README.md CHANGED
@@ -67,7 +67,7 @@ $ acmesmith save-pkcs12 COMMON_NAME --output=PATH # Save certificate and p
67
67
  ```
68
68
 
69
69
  ```
70
- $ acmesmith autorenew [-d DAYS] # Renew certificates which being expired soon
70
+ $ acmesmith autorenew [-r RATIO] [-d DAYS] # Renew certificates which being expired soon. Default to -r 1/3
71
71
  ```
72
72
 
73
73
  ```
@@ -89,7 +89,7 @@ module Acmesmith
89
89
  domain_and_challenges.each do |domain, challenge|
90
90
 
91
91
  hosted_zone_id = find_hosted_zone(domain)
92
- name = "#{challenge.record_name}.#{domain}."
92
+ name = "#{challenge.record_name}.#{canonical_fqdn(domain)}."
93
93
 
94
94
  rrsets = list_existing_rrsets(hosted_zone_id, name)
95
95
  next if rrsets.empty?
@@ -122,14 +122,23 @@ module Acmesmith
122
122
  SaveCertificateService.new(cert, **kwargs).perform!
123
123
  end
124
124
 
125
- def autorenew(days: 7, common_names: nil)
125
+ def autorenew(days: 30, remaining_life: nil, common_names: nil)
126
126
  (common_names || storage.list_certificates).each do |cn|
127
127
  puts "=> #{cn}"
128
128
  cert = storage.get_certificate(cn)
129
129
  not_after = cert.certificate.not_after.utc
130
130
 
131
- puts " Not valid after: #{not_after}"
132
- next unless (cert.certificate.not_after.utc - Time.now.utc) < (days.to_i * 86400)
131
+ lifetime = cert.certificate.not_after.utc - cert.certificate.not_before.utc
132
+ remaining = cert.certificate.not_after.utc - Time.now.utc
133
+ ratio = Rational(remaining,lifetime)
134
+
135
+ has_to_renew = false
136
+ has_to_renew ||= days && remaining < (days.to_i * 86400)
137
+ has_to_renew ||= remaining_life && ratio < remaining_life
138
+
139
+ puts " Not valid after: #{not_after} (lifetime=#{format_duration(lifetime+1)}, remaining=#{format_duration(remaining)}, #{"%0.2f" % (ratio.to_f*100)}%)"
140
+ next unless has_to_renew
141
+
133
142
  puts " * Renewing: CN=#{cert.common_name}, SANs=#{cert.sans.join(',')}"
134
143
  order_with_private_key(cert.common_name, *cert.sans, private_key: regenerate_private_key(cert.public_key))
135
144
  end
@@ -145,6 +154,22 @@ module Acmesmith
145
154
 
146
155
  private
147
156
 
157
+ # @param [Numeric] duration
158
+ def format_duration(duration)
159
+ raise ArgumentError if !duration.is_a?(Numeric) || duration < 0
160
+
161
+ # Calculate components using divmod
162
+ days, remainder = duration.divmod(86400)
163
+ hours, remainder = remainder.divmod(3600)
164
+ minutes, seconds = remainder.divmod(60)
165
+
166
+ # Create [value, unit] pairs, filter out zero values, format, and join
167
+ [[days, 'd'], [hours, 'h'], [minutes, 'm'], [seconds, 's']]
168
+ .select { |v,| v > 0 }
169
+ .map { |v, unit| "#{v.to_i}#{unit}" }
170
+ .join
171
+ end
172
+
148
173
 
149
174
  def config
150
175
  @config
@@ -143,9 +143,20 @@ module Acmesmith
143
143
  end
144
144
 
145
145
  desc "autorenew [COMMON_NAMES]", "request renewal of certificates which expires soon"
146
- method_option :days, type: :numeric, aliases: %w(-d), default: 7, desc: 'specify threshold in days to select certificates to renew'
146
+ method_option :days, type: :numeric, aliases: %w(-d), default: nil, desc: 'specify threshold in days to select certificates to renew'
147
+ method_option :remaining_life, type: :string, aliases: %w(-r), default: '1/3', desc: "Specify threshold based on remaining life. Accepts a percentage ('20%') or fraction ('1/3')"
147
148
  def autorenew(*common_names)
148
- client.autorenew(days: options[:days], common_names: common_names.empty? ? nil : common_names)
149
+ remaining_life = case options[:remaining_life]
150
+ when %r{\A\d+/\d+\z}
151
+ Rational(options[:remaining_life])
152
+ when %r{\A([\d.]+)%\z}
153
+ Rational($1.to_f, 100)
154
+ when nil
155
+ nil
156
+ else
157
+ raise ArgumentError, "invalid format for --remaining-life: it must be in '..%' or '../..'"
158
+ end
159
+ client.autorenew(days: options[:days], remaining_life: remaining_life, common_names: common_names.empty? ? nil : common_names)
149
160
  end
150
161
 
151
162
  desc "add-san COMMON_NAME [ADDITIONAL_SANS]", "request renewal of existing certificate with additional SANs"
@@ -1,3 +1,3 @@
1
1
  module Acmesmith
2
- VERSION = "2.6.0"
2
+ VERSION = "2.7.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acmesmith
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.6.0
4
+ version: 2.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sorah Fukumori
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2023-10-04 00:00:00.000000000 Z
10
+ date: 2025-04-28 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: acme-client
@@ -200,7 +199,6 @@ homepage: https://github.com/sorah/acmesmith
200
199
  licenses:
201
200
  - MIT
202
201
  metadata: {}
203
- post_install_message:
204
202
  rdoc_options: []
205
203
  require_paths:
206
204
  - lib
@@ -215,8 +213,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
215
213
  - !ruby/object:Gem::Version
216
214
  version: '0'
217
215
  requirements: []
218
- rubygems_version: 3.4.6
219
- signing_key:
216
+ rubygems_version: 3.6.2
220
217
  specification_version: 4
221
218
  summary: ACME client (Let's encrypt client) to manage certificate in multi server
222
219
  environment with cloud services (e.g. AWS)