acmesmith 2.7.1 → 2.8.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: de52b6d87714b27035507ce19c8dccc5c876cebebed05ce06d9865858f2f0fec
4
- data.tar.gz: 7aef801a33ea26c22db4a38c1c3af2d9432862dc3ffa383e47b23a12ab296531
3
+ metadata.gz: 252b913c94d04e35760101aedc61410f00bc59c806830f86d1348237c213700b
4
+ data.tar.gz: e494fc15b7bbdbc1b5b59dfcbb654d654c7908defa749106c8e37cd52d3d882e
5
5
  SHA512:
6
- metadata.gz: fbcfef0acbd3e20a3f9245a41fd7f3bd74e33bf7333f307ee32047a330b7b30c213260e59cc4571b98fc650a89b9d424fa66097a776f52ad2f9a0ecbb1eb5a4a
7
- data.tar.gz: 94479e7616793c0cf51bfd3083a1ce6195c6ff886d7516fb62e841b5d93eaf14540dd9793030d33b273ef9b6fc3fa3f06abbb8be43af3a08e47b7f871aea2b60
6
+ metadata.gz: 2b075a5fc9d32491774864c8035a6de3b3eb8dd03ccea006330f63cce4beac3c8ca4304b51d6b6d6bf406aacf196424c8dd7aaa7f772226240aa2b0138c40474
7
+ data.tar.gz: c209c626c45fa16f547ca0bea14271bb8c850592b5ef205a7c19269d5c7f0cb941101caaf75e9cdd510e46f5731723bf7cf73abf9878de95171ecd07aed0f5cc
data/CHANGELOG.md CHANGED
@@ -1,3 +1,19 @@
1
+ ## v2.8.0 (2025-11-11)
2
+
3
+ ### Enhancements
4
+
5
+ - post_issuing_hooks/shell: Gained `$CERT_NAME` environment variable which is to replace `$COMMON_NAME` for certificates without CN field. [#76](https://github.com/sorah/acmesmith/pull/76)
6
+ - certificate: gained `name` method (Certificate#name) in addition to Certificate#common_name, for certificates without CN field. Plugin authors are encouraged to migrate on this new API. [#76](https://github.com/sorah/acmesmith/pull/76)
7
+
8
+ ### Fixes
9
+
10
+ - A certificate name is now inherited to a new certificate during autorenew and add-san command for stability, otherwise it could be saved under an another name when CA has issued the new certificate with different subject field or SANs field due to its policy/behaviour change; If you're using 3rd party storage plugins, it has to be updated to use Certificate#name instead of Certificate#common_name to support certificates without CN field. [#77](https://github.com/sorah/acmesmith/pull/77)
11
+
12
+ ### Updates
13
+
14
+ - Update gemspec to the latest bundler's provided template. This removes certain irrevant files from a released gem package. [#73](https://github.com/sorah/acmesmith/issues/73)
15
+ - Use rubygems.org trusted publishing via GitHub Actions [#73](https://github.com/sorah/acmesmith/issues/73)
16
+
1
17
  ## v2.7.1 (2025-08-21)
2
18
 
3
19
  ### Bug fixes
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Acmesmith: A simple, effective ACME v2 client to use with many servers and a cloud
2
2
 
3
- ![ci](https://github.com/sorah/acmesmith/workflows/ci/badge.svg?event=push) <a href='https://ko-fi.com/J3J8CKMUU' target='_blank'><img height='36' style='border:0px;height:36px;' src='https://cdn.ko-fi.com/cdn/kofi3.png?v=3' border='0' alt='Buy Me a Coffee at ko-fi.com' /></a>
3
+ [![ci](https://github.com/sorah/acmesmith/actions/workflows/build.yml/badge.svg?event=push)](https://github.com/sorah/acmesmith/actions/workflows/build.yml) <a href='https://ko-fi.com/J3J8CKMUU' target='_blank'><img height='36' style='border:0px;height:36px;' src='https://cdn.ko-fi.com/cdn/kofi3.png?v=3' border='0' alt='Buy Me a Coffee at ko-fi.com' /></a>
4
4
 
5
5
 
6
6
  Acmesmith is an [ACME (Automatic Certificate Management Environment)](https://github.com/ietf-wg-acme/acme) client that works perfect on environment with multiple servers. This client saves certificate and keys on cloud services (e.g. AWS S3) securely, then allow to deploy issued certificates onto your servers smoothly. This works well on [Let's encrypt](https://letsencrypt.org).
@@ -1,17 +1,20 @@
1
1
  # Post Issuing Hook: Shell
2
2
 
3
- Execute specified command on a shell. Environment variable `${COMMON_NAME}` is available.
3
+ Execute specified command on a shell. Environment variable `${CERT_NAME}` is available.
4
4
 
5
5
  ```yaml
6
6
  post_issuing_hooks:
7
7
  "test.example.com":
8
8
  - shell:
9
- command: mail -s "New cert for ${COMMON_NAME} has been issued" user@example.com < /dev/null
9
+ command: mail -s "New cert for ${CERT_NAME} has been issued" user@example.com < /dev/null
10
10
  - shell:
11
- command: touch /tmp/certs-has-been-issued-${COMMON_NAME}
11
+ command: touch /tmp/certs-has-been-issued-${CERT_NAME}
12
12
  "admin.example.com":
13
13
  - shell:
14
- command: /usr/bin/dosomethingelse ${COMMON_NAME}
14
+ command: /usr/bin/dosomethingelse ${CERT_NAME}
15
15
  ```
16
16
 
17
+ ## What happened to `${COMMON_NAME}`?
17
18
 
19
+ In modern CA behavior, certificates may be missing CN field, or entire subject field.
20
+ It is still available, but we recommend to use `${CERT_NAME}` instead, which obtains a certificate name from certain sources.
@@ -17,10 +17,11 @@ module Acmesmith
17
17
  # Return Acmesmith::Certificate by an issued certificate
18
18
  # @param pem_chain [String]
19
19
  # @param csr [Acme::Client::CertificateRequest]
20
+ # @param name [String, nil]
20
21
  # @return [Acmesmith::Certificate]
21
- def self.by_issuance(pem_chain, csr)
22
+ def self.by_issuance(pem_chain, csr, name: nil)
22
23
  pems = split_pems(pem_chain)
23
- new(pems[0], pems[1..-1], csr.private_key, nil, csr)
24
+ new(pems[0], pems[1..-1], csr.private_key, nil, csr, name: name)
24
25
  end
25
26
 
26
27
  # @param certificate [OpenSSL::X509::Certificate, String]
@@ -28,7 +29,9 @@ module Acmesmith
28
29
  # @param private_key [String, OpenSSL::PKey::PKey]
29
30
  # @param key_passphrase [String, nil]
30
31
  # @param csr [String, OpenSSL::X509::Request, nil]
31
- def initialize(certificate, chain, private_key, key_passphrase = nil, csr = nil)
32
+ # @param name [String, nil]
33
+ def initialize(certificate, chain, private_key, key_passphrase = nil, csr = nil, name: nil)
34
+ @name = name
32
35
  @certificate = case certificate
33
36
  when OpenSSL::X509::Certificate
34
37
  certificate
@@ -94,6 +97,8 @@ module Acmesmith
94
97
  # @return [OpenSSL::X509::Request]
95
98
  attr_reader :csr
96
99
 
100
+ attr_writer :name
101
+
97
102
  # Try to decrypt private_key if encrypted.
98
103
  # @param pw [String] passphrase for encrypted PEM
99
104
  # @raise [PrivateKeyDecrypted] if private_key is decrypted
@@ -128,18 +133,38 @@ module Acmesmith
128
133
  chain.map(&:to_pem).join("\n")
129
134
  end
130
135
 
131
- # @return [String] common name
136
+ # Returns a predicted certificate name, taken from common name or first SAN.
137
+ # Note that this value can contain colons (':') if name is taken from non-DNS subject alternative name.
138
+ # @return [String] certificate name
139
+ def name
140
+ @name || common_name || sans.first || all_sans.first
141
+ end
142
+
143
+ # Returns a certificate common name taken from the certificate subject's CN field.
144
+ # Under the real CA, CNs can be missing. Use #name instead to retrieve the certificate name for most cases.
145
+ # ref. https://github.com/letsencrypt/pebble/pull/491#pullrequestreview-2718607820
146
+ # @return [String, nil] common name
132
147
  def common_name
133
- certificate.subject.to_a.assoc('CN')[1]
148
+ certificate.subject.to_a.assoc('CN')&.fetch(1)
134
149
  end
135
150
 
136
- # @return [Array<String>] Subject Alternative Names (dNSname)
137
- def sans
151
+ # Returns a list of subject alternative names included in the certificate.
152
+ # @return [Array<String>] Subject Alternative Names
153
+ def all_sans
138
154
  certificate.extensions.select { |_| _.oid == 'subjectAltName' }.flat_map do |ext|
139
- ext.value.split(/,\s*/).select { |_| _.start_with?('DNS:') }.map { |_| _[4..-1] }
155
+ ext.value.split(/,\s*/)
140
156
  end
141
157
  end
142
158
 
159
+ # Returns a list of DNS subject alternative names included in the certificate.
160
+ # Strips DNS: prefix from returned values.
161
+ # @return [Array<String>] Subject Alternative Names (dNSname)
162
+ def sans
163
+ all_sans.select do |san|
164
+ san.start_with?('DNS:')
165
+ end.map { |_| _[4..-1] }
166
+ end
167
+
143
168
  # @return [String] Version string (consists of NotBefore time & certificate serial)
144
169
  def version
145
170
  "#{certificate.not_before.utc.strftime('%Y%m%d-%H%M%S')}_#{certificate.serial.to_i.to_s(16)}"
@@ -147,7 +172,7 @@ module Acmesmith
147
172
 
148
173
  # @return [OpenSSL::PKCS12]
149
174
  def pkcs12(passphrase)
150
- OpenSSL::PKCS12.create(passphrase, common_name, private_key, certificate, chain)
175
+ OpenSSL::PKCS12.create(passphrase, name, private_key, certificate, chain)
151
176
  end
152
177
 
153
178
  # @return [CertificateExport]
@@ -3,13 +3,13 @@ require 'acmesmith/certificate'
3
3
  module Acmesmith
4
4
  class CertificateRetrievingService
5
5
  # @param acme [Acme::Client]
6
- # @param common_name [String]
6
+ # @param name [String]
7
7
  # @param url [String] ACME Certificate URL
8
8
  # @param chain_preferences [Array<Acmesmith::Config::ChainPreference>]
9
- def initialize(acme, common_name, url, chain_preferences: [])
9
+ def initialize(acme, name, url, chain_preferences: [])
10
10
  @acme = acme
11
11
  @url = url
12
- @chain_preferences = chain_preferences.select { |_| _.filter.match?(common_name) }
12
+ @chain_preferences = chain_preferences.select { |_| _.filter.match?(name) }
13
13
  end
14
14
 
15
15
  attr_reader :acme
@@ -30,35 +30,35 @@ module Acmesmith
30
30
  raise NotImplementedError, "Domain authorization in advance is still not available in acme-client (v2). Required authorizations will be performed when ordering certificates"
31
31
  end
32
32
 
33
- def post_issue_hooks(common_name)
34
- cert = storage.get_certificate(common_name)
33
+ def post_issue_hooks(name)
34
+ cert = load_certificate_from_storage(name)
35
35
  execute_post_issue_hooks(cert)
36
36
  end
37
37
 
38
38
  def execute_post_issue_hooks(certificate)
39
- hooks = config.post_issuing_hooks(certificate.common_name)
39
+ hooks = config.post_issuing_hooks(certificate.name)
40
40
  return if hooks.empty?
41
- puts "=> Executing post issuing hooks for CN=#{certificate.common_name}"
41
+ puts "=> Executing post issuing hooks for CN=#{certificate.name}"
42
42
  hooks.each do |hook|
43
43
  hook.run(certificate: certificate)
44
44
  end
45
45
  puts
46
46
  end
47
47
 
48
- def certificate_versions(common_name)
49
- storage.list_certificate_versions(common_name).sort
48
+ def certificate_versions(name)
49
+ storage.list_certificate_versions(name).sort
50
50
  end
51
51
 
52
52
  def certificates_list
53
53
  storage.list_certificates.sort
54
54
  end
55
55
 
56
- def current(common_name)
57
- storage.get_current_certificate_version(common_name)
56
+ def current(name)
57
+ storage.get_current_certificate_version(name)
58
58
  end
59
59
 
60
- def get_certificate(common_name, version: 'current', type: 'text')
61
- cert = storage.get_certificate(common_name, version: version)
60
+ def get_certificate(name, version: 'current', type: 'text')
61
+ cert = storage.get_certificate(name, version: version)
62
62
 
63
63
  certs = []
64
64
  case type
@@ -76,8 +76,8 @@ module Acmesmith
76
76
  certs
77
77
  end
78
78
 
79
- def save_certificate(common_name, version: 'current', mode: '0600', output:, type: 'fullchain')
80
- cert = storage.get_certificate(common_name, version: version)
79
+ def save_certificate(name, version: 'current', mode: '0600', output:, type: 'fullchain')
80
+ cert = storage.get_certificate(name, version: version)
81
81
  File.open(output, 'w', mode.to_i(8)) do |f|
82
82
  case type
83
83
  when 'certificate'
@@ -90,23 +90,23 @@ module Acmesmith
90
90
  end
91
91
  end
92
92
 
93
- def get_private_key(common_name, version: 'current')
94
- cert = storage.get_certificate(common_name, version: version)
93
+ def get_private_key(name, version: 'current')
94
+ cert = storage.get_certificate(name, version: version)
95
95
  cert.key_passphrase = certificate_key_passphrase if certificate_key_passphrase
96
96
 
97
97
  cert.private_key.to_pem
98
98
  end
99
99
 
100
- def save_private_key(common_name, version: 'current', mode: '0600', output:)
101
- cert = storage.get_certificate(common_name, version: version)
100
+ def save_private_key(name, version: 'current', mode: '0600', output:)
101
+ cert = storage.get_certificate(name, version: version)
102
102
  cert.key_passphrase = certificate_key_passphrase if certificate_key_passphrase
103
103
  File.open(output, 'w', mode.to_i(8)) do |f|
104
104
  f.puts(cert.private_key)
105
105
  end
106
106
  end
107
107
 
108
- def save_pkcs12(common_name, version: 'current', mode: '0600', output:, passphrase:)
109
- cert = storage.get_certificate(common_name, version: version)
108
+ def save_pkcs12(name, version: 'current', mode: '0600', output:, passphrase:)
109
+ cert = storage.get_certificate(name, version: version)
110
110
  cert.key_passphrase = certificate_key_passphrase if certificate_key_passphrase
111
111
 
112
112
  p12 = cert.pkcs12(passphrase)
@@ -115,17 +115,18 @@ module Acmesmith
115
115
  end
116
116
  end
117
117
 
118
- def save(common_name, version: 'current', **kwargs)
119
- cert = storage.get_certificate(common_name, version: version)
118
+ def save(name, version: 'current', **kwargs)
119
+ cert = storage.get_certificate(name, version: version)
120
120
  cert.key_passphrase = certificate_key_passphrase if certificate_key_passphrase
121
121
 
122
122
  SaveCertificateService.new(cert, **kwargs).perform!
123
123
  end
124
124
 
125
- def autorenew(days: 30, remaining_life: nil, common_names: nil)
126
- (common_names || storage.list_certificates).each do |cn|
125
+ def autorenew(days: 30, remaining_life: nil, names: nil)
126
+ (names || storage.list_certificates).each do |cn|
127
127
  puts "=> #{cn}"
128
- cert = storage.get_certificate(cn)
128
+ cert = load_certificate_from_storage(cn)
129
+
129
130
  not_after = cert.certificate.not_after.utc
130
131
 
131
132
  lifetime = cert.certificate.not_after.utc - cert.certificate.not_before.utc
@@ -139,17 +140,17 @@ module Acmesmith
139
140
  puts " Not valid after: #{not_after} (lifetime=#{format_duration(lifetime+1)}, remaining=#{format_duration(remaining)}, #{"%0.2f" % (ratio.to_f*100)}%)"
140
141
  next unless has_to_renew
141
142
 
142
- puts " * Renewing: CN=#{cert.common_name}, SANs=#{cert.sans.join(',')}"
143
- order_with_private_key(cert.common_name, *cert.sans, private_key: regenerate_private_key(cert.public_key))
143
+ puts " * Renewing: #{cert.name.inspect}, SANs=#{cert.sans.join(',')}"
144
+ order_with_private_key(cert.name, *cert.sans, private_key: regenerate_private_key(cert.public_key))
144
145
  end
145
146
  end
146
147
 
147
- def add_san(common_name, *add_sans)
148
- puts "=> reissuing CN=#{common_name} with new SANs #{add_sans.join(?,)}"
149
- cert = storage.get_certificate(common_name)
148
+ def add_san(name, *add_sans)
149
+ puts "=> reissuing #{name.inspect} with new SANs #{add_sans.join(?,)}"
150
+ cert = load_certificate_from_storage(name)
150
151
  sans = cert.sans + add_sans
151
152
  puts " * SANs will be: #{sans.join(?,)}"
152
- order_with_private_key(cert.common_name, *sans, private_key: regenerate_private_key(cert.public_key))
153
+ order_with_private_key(cert.name, *sans, private_key: regenerate_private_key(cert.public_key))
153
154
  end
154
155
 
155
156
  private
@@ -212,10 +213,11 @@ module Acmesmith
212
213
  end
213
214
  end
214
215
 
215
- def order_with_private_key(*identifiers, private_key:, not_before: nil, not_after: nil)
216
+ def order_with_private_key(name, *identifiers, private_key:, not_before: nil, not_after: nil)
216
217
  order = OrderingService.new(
217
218
  acme: acme,
218
- identifiers: identifiers,
219
+ common_name: name,
220
+ identifiers: [name, *identifiers],
219
221
  private_key: private_key,
220
222
  challenge_responder_rules: config.challenge_responders,
221
223
  chain_preferences: config.chain_preferences,
@@ -258,5 +260,12 @@ module Acmesmith
258
260
  raise ArgumentError, "Unknown key type: #{template.class}"
259
261
  end
260
262
  end
263
+
264
+ # Load certificate from storage, inherit name property to loaded certificate to ensure stability of #name during renewal.
265
+ def load_certificate_from_storage(name)
266
+ retval = storage.get_certificate(name)
267
+ retval.name = name
268
+ retval
269
+ end
261
270
  end
262
271
  end
@@ -30,14 +30,14 @@ module Acmesmith
30
30
  # client.authorize(*domains)
31
31
  end
32
32
 
33
- desc "order COMMON_NAME [SAN]", "order certificate for CN +COMMON_NAME+ with SANs +SAN+"
33
+ desc "order NAME [SAN]", "order certificate for CN +NAME+ with SANs +SAN+"
34
34
  method_option :show_certificate, type: :boolean, aliases: %w(-s), default: true, desc: 'show an issued certificate in PEM and text when exiting'
35
35
  method_option :key_type, type: :string, enum: %w(rsa ec), default: 'rsa', desc: 'key type'
36
36
  method_option :rsa_key_size, type: :numeric, default: 2048, desc: 'size of RSA key'
37
37
  method_option :elliptic_curve, type: :string, default: 'prime256v1', desc: 'elliptic curve group for EC key'
38
- def order(common_name, *sans)
38
+ def order(name, *sans)
39
39
  cert = client.order(
40
- common_name, *sans,
40
+ name, *sans,
41
41
  key_type: options[:key_type],
42
42
  rsa_key_size: options[:rsa_key_size],
43
43
  elliptic_curve: options[:elliptic_curve],
@@ -48,60 +48,60 @@ module Acmesmith
48
48
  end
49
49
  end
50
50
 
51
- desc "post-issue-hooks COMMON_NAME", "Run all post-issuing hooks for common name. (for testing purpose)"
52
- def post_issue_hooks(common_name)
53
- client.post_issue_hooks(common_name)
51
+ desc "post-issue-hooks NAME", "Run all post-issuing hooks for common name. (for testing purpose)"
52
+ def post_issue_hooks(name)
53
+ client.post_issue_hooks(name)
54
54
  end
55
55
  map 'post-issue-hooks' => :post_issue_hooks
56
56
 
57
- desc "list [COMMON_NAME]", "list certificates or its versions"
58
- def list(common_name = nil)
59
- if common_name
60
- puts client.certificate_versions(common_name)
57
+ desc "list [NAME]", "list certificates or its versions"
58
+ def list(name = nil)
59
+ if name
60
+ puts client.certificate_versions(name)
61
61
  else
62
62
  puts client.certificates_list
63
63
  end
64
64
  end
65
65
 
66
- desc "current COMMON_NAME", "show current version for certificate"
67
- def current(common_name)
68
- puts client.current(common_name)
66
+ desc "current NAME", "show current version for certificate"
67
+ def current(name)
68
+ puts client.current(name)
69
69
  end
70
70
 
71
- desc "show-certificate COMMON_NAME", "show certificate"
71
+ desc "show-certificate NAME", "show certificate"
72
72
  method_option :version, type: :string, default: 'current'
73
73
  method_option :type, type: :string, enum: %w(text certificate chain fullchain), default: 'text'
74
- def show_certificate(common_name)
75
- certs = client.get_certificate(common_name, version: options[:version], type: options[:type])
74
+ def show_certificate(name)
75
+ certs = client.get_certificate(name, version: options[:version], type: options[:type])
76
76
  puts certs
77
77
  end
78
78
  map 'show-certiticate' => :show_certificate
79
79
 
80
- desc 'save-certificate COMMON_NAME', 'Save certificate to a file'
80
+ desc 'save-certificate NAME', 'Save certificate to a file'
81
81
  method_option :version, type: :string, default: 'current'
82
82
  method_option :type, type: :string, enum: %w(certificate chain fullchain), default: 'fullchain'
83
83
  method_option :output, type: :string, required: true, banner: 'PATH', desc: 'Path to output file'
84
84
  method_option :mode, type: :string, default: '0600', desc: 'Mode (permission) of the output file on create'
85
- def save_certificate(common_name)
86
- client.save_certificate(common_name, version: options[:version], mode: options[:mode], output: options[:output], type: options[:type])
85
+ def save_certificate(name)
86
+ client.save_certificate(name, version: options[:version], mode: options[:mode], output: options[:output], type: options[:type])
87
87
  end
88
88
 
89
- desc "show-private-key COMMON_NAME", "show private key"
89
+ desc "show-private-key NAME", "show private key"
90
90
  method_option :version, type: :string, default: 'current'
91
- def show_private_key(common_name)
92
- puts client.get_private_key(common_name, version: options[:version])
91
+ def show_private_key(name)
92
+ puts client.get_private_key(name, version: options[:version])
93
93
  end
94
94
  map 'show-private-key' => :show_private_key
95
95
 
96
- desc 'save-private-key COMMON_NAME', 'Save private key to a file'
96
+ desc 'save-private-key NAME', 'Save private key to a file'
97
97
  method_option :version, type: :string, default: 'current'
98
98
  method_option :output, type: :string, required: true, banner: 'PATH', desc: 'Path to output file'
99
99
  method_option :mode, type: :string, default: '0600', desc: 'Mode (permission) of the output file on create'
100
- def save_private_key(common_name)
101
- client.save_private_key(common_name, version: options[:version], mode: options[:mode], output: options[:output])
100
+ def save_private_key(name)
101
+ client.save_private_key(name, version: options[:version], mode: options[:mode], output: options[:output])
102
102
  end
103
103
 
104
- desc 'save COMMON_NAME', 'Save (or update) certificate and key files.'
104
+ desc 'save NAME', 'Save (or update) certificate and key files.'
105
105
  method_option :version, type: :string, default: 'current'
106
106
  method_option :key_mode, type: :string, default: '0600', desc: 'Mode (permission) of the key file on create'
107
107
  method_option :certificate_mode, type: :string, default: '0644', desc: 'Mode (permission) of the certificate files on create'
@@ -111,9 +111,9 @@ module Acmesmith
111
111
  method_option :chain_file, type: :string, required: false , banner: 'PATH', desc: 'Path to save a certificate chain (root and intermediate CA)'
112
112
  method_option :certificate_file, type: :string, required: false, banner: 'PATH', desc: 'Path to save a certficiate'
113
113
  method_option :atomic, type: :boolean, default: true, desc: 'Enable atomic file update with rename(2)'
114
- def save(common_name)
114
+ def save(name)
115
115
  client.save(
116
- common_name,
116
+ name,
117
117
  version: options[:version],
118
118
  key_mode: options[:key_mode],
119
119
  certificate_mode: options[:certificate_mode],
@@ -127,11 +127,11 @@ module Acmesmith
127
127
  )
128
128
  end
129
129
 
130
- desc 'save-pkcs12 COMMON_NAME', 'Save ceriticate and private key to .p12 file'
130
+ desc 'save-pkcs12 NAME', 'Save ceriticate and private key to .p12 file'
131
131
  method_option :version, type: :string, default: 'current'
132
132
  method_option :output, type: :string, required: true, banner: 'PATH', desc: 'Path to output file'
133
133
  method_option :mode, type: :string, default: '0600', desc: 'Mode (permission) of the output file on create'
134
- def save_pkcs12(common_name)
134
+ def save_pkcs12(name)
135
135
  print 'Passphrase: '
136
136
  passphrase = $stdin.noecho { $stdin.gets }.chomp
137
137
  print "\nPassphrase (confirm): "
@@ -139,13 +139,13 @@ module Acmesmith
139
139
  puts
140
140
 
141
141
  raise ArgumentError, "Passphrase doesn't match" if passphrase != passphrase2
142
- client.save_pkcs12(common_name, version: options[:version], mode: options[:mode], output: options[:output], passphrase: passphrase)
142
+ client.save_pkcs12(name, version: options[:version], mode: options[:mode], output: options[:output], passphrase: passphrase)
143
143
  end
144
144
 
145
- desc "autorenew [COMMON_NAMES]", "request renewal of certificates which expires soon"
145
+ desc "autorenew [NAMES]", "request renewal of certificates which expires soon"
146
146
  method_option :days, type: :numeric, aliases: %w(-d), default: nil, desc: 'specify threshold in days to select certificates to renew'
147
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')"
148
- def autorenew(*common_names)
148
+ def autorenew(*names)
149
149
  remaining_life = case options[:remaining_life]
150
150
  when %r{\A\d+/\d+\z}
151
151
  Rational(options[:remaining_life])
@@ -156,12 +156,12 @@ module Acmesmith
156
156
  else
157
157
  raise ArgumentError, "invalid format for --remaining-life: it must be in '..%' or '../..'"
158
158
  end
159
- client.autorenew(days: options[:days], remaining_life: remaining_life, common_names: common_names.empty? ? nil : common_names)
159
+ client.autorenew(days: options[:days], remaining_life: remaining_life, names: names.empty? ? nil : names)
160
160
  end
161
161
 
162
- desc "add-san COMMON_NAME [ADDITIONAL_SANS]", "request renewal of existing certificate with additional SANs"
163
- def add_san(common_name, *add_sans)
164
- client.add_san(common_name, *add_sans)
162
+ desc "add-san NAME [ADDITIONAL_SANS]", "request renewal of existing certificate with additional SANs"
163
+ def add_san(name, *add_sans)
164
+ client.add_san(name, *add_sans)
165
165
  end
166
166
 
167
167
  desc "register CONTACT", "(deprecated, use 'acmesmith new-account')"
@@ -175,16 +175,16 @@ module Acmesmith
175
175
  new_account(contact)
176
176
  end
177
177
 
178
- desc "request COMMON_NAME [SAN]", "(deprecated, use 'acmesmith order')"
178
+ desc "request NAME [SAN]", "(deprecated, use 'acmesmith order')"
179
179
  method_option :show_certificate, type: :boolean, aliases: %w(-s), default: true, desc: 'show an issued certificate in PEM and text when exiting'
180
- def request(common_name, *sans)
180
+ def request(name, *sans)
181
181
  warn "!"
182
182
  warn "! DEPRECATION WARNING: Use 'acmesmith order' command"
183
183
  warn "! There is no user-facing breaking changes. It takes the same arguments with 'acmesmith request'."
184
184
  warn "!"
185
185
  warn "! This is due to change in semantics of ACME v2. ACME v2 defines 'order' instead of 'request' in v1."
186
186
  warn "!"
187
- order(common_name, *sans)
187
+ order(name, *sans)
188
188
  end
189
189
 
190
190
  private
@@ -7,14 +7,16 @@ module Acmesmith
7
7
  class NotCompleted < StandardError; end
8
8
 
9
9
  # @param acme [Acme::Client] ACME client
10
- # @param identifiers [Array<String>] Array of domain names for a ordering certificate. The first item will be a common name.
10
+ # @param common_name [String] Common Name for a ordering certificate
11
+ # @param identifiers [Array<String>] Array of domain names for a ordering certificate. common_name has to be explicitly included in this argument.
11
12
  # @param private_key [OpenSSL::PKey::PKey] Private key
12
13
  # @param challenge_responder_rules [Array<Acmesmith::Config::ChallengeResponderRule>] responders
13
14
  # @param chain_preferences [Array<Acmesmith::Config::ChainPreference>] chain_preferences
14
15
  # @param not_before [Time]
15
16
  # @param not_after [Time]
16
- def initialize(acme:, identifiers:, private_key:, challenge_responder_rules:, chain_preferences:, not_before: nil, not_after: nil)
17
+ def initialize(acme:, common_name:, identifiers:, private_key:, challenge_responder_rules:, chain_preferences:, not_before: nil, not_after: nil)
17
18
  @acme = acme
19
+ @common_name = common_name
18
20
  @identifiers = identifiers
19
21
  @private_key = private_key
20
22
  @challenge_responder_rules = challenge_responder_rules
@@ -23,7 +25,7 @@ module Acmesmith
23
25
  @not_after = not_after
24
26
  end
25
27
 
26
- attr_reader :acme, :identifiers, :private_key, :challenge_responder_rules, :chain_preferences, :not_before, :not_after
28
+ attr_reader :acme, :common_name, :identifiers, :private_key, :challenge_responder_rules, :chain_preferences, :not_before, :not_after
27
29
 
28
30
  def perform!
29
31
  puts "=> Ordering a certificate for the following identifiers:"
@@ -43,7 +45,7 @@ module Acmesmith
43
45
  finalize_order()
44
46
  wait_order_for_complete()
45
47
 
46
- @certificate = Certificate.by_issuance(pem_chain, csr)
48
+ @certificate = Certificate.by_issuance(pem_chain, csr, name: common_name)
47
49
 
48
50
  puts
49
51
  puts "=> Certificate issued"
@@ -97,11 +99,6 @@ module Acmesmith
97
99
  @order or raise "BUG: order not yet generated"
98
100
  end
99
101
 
100
- # @return [String]
101
- def common_name
102
- identifiers.first
103
- end
104
-
105
102
  # @return [Array<String>]
106
103
  def sans
107
104
  identifiers[1..-1]
@@ -10,10 +10,10 @@ module Acmesmith
10
10
  end
11
11
 
12
12
  def execute
13
- puts "=> Executing Post Issueing Hook for #{common_name} in #{self.class.name}"
13
+ puts "=> Executing Post Issuing Hook for #{certificate.name.inspect} in #{self.class.name}"
14
14
  puts " $ #{@command}"
15
15
 
16
- status = system({"COMMON_NAME" => common_name}, @command)
16
+ status = system({"CERT_NAME" => certificate.name, "COMMON_NAME" => common_name}.compact, @command)
17
17
 
18
18
  unless status
19
19
  if @ignore_failure
@@ -23,7 +23,7 @@ module Acmesmith
23
23
  return
24
24
  end
25
25
 
26
- log "Saving certificate CN=#{cert.common_name} (ver: #{cert.version})"
26
+ log "Saving certificate #{cert.name.inspect} (ver: #{cert.version})"
27
27
 
28
28
  write_file(key_file, key_mode, cert.private_key)
29
29
  write_file(certificate_file, certificate_mode, cert.certificate.to_pem)
@@ -25,28 +25,28 @@ module Acmesmith
25
25
  raise NotImplementedError
26
26
  end
27
27
 
28
- # @param common_name [String]
28
+ # @param name [String]
29
29
  # @param version [String, nil]
30
30
  # @return [Acmesmith::Certificate]
31
- def get_certificate(common_name, version: 'current')
31
+ def get_certificate(name, version: 'current')
32
32
  raise NotImplementedError
33
33
  end
34
34
 
35
- # @param common_name [String]
36
- # @return [String] array of common_names
35
+ # @param name [String]
36
+ # @return [String] array of certificate names
37
37
  def list_certificates
38
38
  raise NotImplementedError
39
39
  end
40
40
 
41
- # @param common_name [String]
41
+ # @param name [String]
42
42
  # @return [String] array of versions
43
- def list_certificate_versions(common_name)
43
+ def list_certificate_versions(name)
44
44
  raise NotImplementedError
45
45
  end
46
46
 
47
- # @param common_name [String]
47
+ # @param name [String]
48
48
  # @return [String] current version
49
- def get_current_certificate_version(common_name)
49
+ def get_current_certificate_version(name)
50
50
  raise NotImplementedError
51
51
  end
52
52
  end
@@ -25,22 +25,22 @@ module Acmesmith
25
25
 
26
26
  def put_certificate(cert, passphrase = nil, update_current: true)
27
27
  h = cert.export(passphrase)
28
- certificate_base_path(cert.common_name, cert.version).mkpath
29
- File.write certificate_path(cert.common_name, cert.version), "#{h[:certificate].rstrip}\n"
30
- File.write chain_path(cert.common_name, cert.version), "#{h[:chain].rstrip}\n"
31
- File.write fullchain_path(cert.common_name, cert.version), "#{h[:fullchain].rstrip}\n"
32
- File.write private_key_path(cert.common_name, cert.version), "#{h[:private_key].rstrip}\n", 0, perm: 0600
28
+ certificate_base_path(cert.name, cert.version).mkpath
29
+ File.write certificate_path(cert.name, cert.version), "#{h[:certificate].rstrip}\n"
30
+ File.write chain_path(cert.name, cert.version), "#{h[:chain].rstrip}\n"
31
+ File.write fullchain_path(cert.name, cert.version), "#{h[:fullchain].rstrip}\n"
32
+ File.write private_key_path(cert.name, cert.version), "#{h[:private_key].rstrip}\n", 0, perm: 0600
33
33
  if update_current
34
- File.symlink(cert.version, certificate_base_path(cert.common_name, 'current.new'))
35
- File.rename(certificate_base_path(cert.common_name, 'current.new'), certificate_base_path(cert.common_name, 'current'))
34
+ File.symlink(cert.version, certificate_base_path(cert.name, 'current.new'))
35
+ File.rename(certificate_base_path(cert.name, 'current.new'), certificate_base_path(cert.name, 'current'))
36
36
  end
37
37
  end
38
38
 
39
- def get_certificate(common_name, version: 'current')
40
- raise NotExist.new("Certificate for #{common_name.inspect} of #{version} version doesn't exist") unless certificate_base_path(common_name, version).exist?
41
- certificate = certificate_path(common_name, version).read
42
- chain = chain_path(common_name, version).read
43
- private_key = private_key_path(common_name, version).read
39
+ def get_certificate(name, version: 'current')
40
+ raise NotExist.new("Certificate for #{name.inspect} of #{version} version doesn't exist") unless certificate_base_path(name, version).exist?
41
+ certificate = certificate_path(name, version).read
42
+ chain = chain_path(name, version).read
43
+ private_key = private_key_path(name, version).read
44
44
  Certificate.new(certificate, chain, private_key)
45
45
  end
46
46
 
@@ -48,12 +48,12 @@ module Acmesmith
48
48
  Dir[path.join('certs', '*').to_s].map { |_| File.basename(_) }
49
49
  end
50
50
 
51
- def list_certificate_versions(common_name)
52
- Dir[path.join('certs', common_name, '*').to_s].map { |_| File.basename(_) }.reject { |_| _ == 'current' }
51
+ def list_certificate_versions(name)
52
+ Dir[path.join('certs', name, '*').to_s].map { |_| File.basename(_) }.reject { |_| _ == 'current' }
53
53
  end
54
54
 
55
- def get_current_certificate_version(common_name)
56
- path.join('certs', common_name, 'current').readlink
55
+ def get_current_certificate_version(name)
56
+ path.join('certs', name, 'current').readlink
57
57
  end
58
58
 
59
59
  private
@@ -83,34 +83,34 @@ module Acmesmith
83
83
  @s3.put_object(params)
84
84
  end
85
85
 
86
- put.call certificate_key(cert.common_name, cert.version), "#{h[:certificate].rstrip}\n", false
87
- put.call chain_key(cert.common_name, cert.version), "#{h[:chain].rstrip}\n", false
88
- put.call fullchain_key(cert.common_name, cert.version), "#{h[:fullchain].rstrip}\n", false
89
- put.call private_key_key(cert.common_name, cert.version), "#{h[:private_key].rstrip}\n", use_kms
86
+ put.call certificate_key(cert.name, cert.version), "#{h[:certificate].rstrip}\n", false
87
+ put.call chain_key(cert.name, cert.version), "#{h[:chain].rstrip}\n", false
88
+ put.call fullchain_key(cert.name, cert.version), "#{h[:fullchain].rstrip}\n", false
89
+ put.call private_key_key(cert.name, cert.version), "#{h[:private_key].rstrip}\n", use_kms
90
90
 
91
91
  if generate_pkcs12?(cert)
92
- put.call pkcs12_key(cert.common_name, cert.version), "#{cert.pkcs12(@pkcs12_passphrase).to_der}\n", use_kms, 'application/x-pkcs12'
92
+ put.call pkcs12_key(cert.name, cert.version), "#{cert.pkcs12(@pkcs12_passphrase).to_der}\n", use_kms, 'application/x-pkcs12'
93
93
  end
94
94
 
95
95
  if update_current
96
96
  @s3.put_object(
97
97
  bucket: bucket,
98
- key: certificate_current_key(cert.common_name),
98
+ key: certificate_current_key(cert.name),
99
99
  content_type: 'text/plain',
100
100
  body: cert.version,
101
101
  )
102
102
  end
103
103
  end
104
104
 
105
- def get_certificate(common_name, version: 'current')
106
- version = certificate_current(common_name) if version == 'current'
105
+ def get_certificate(name, version: 'current')
106
+ version = certificate_current(name) if version == 'current'
107
107
 
108
- certificate = @s3.get_object(bucket: bucket, key: certificate_key(common_name, version)).body.read
109
- chain = @s3.get_object(bucket: bucket, key: chain_key(common_name, version)).body.read
110
- private_key = @s3.get_object(bucket: bucket, key: private_key_key(common_name, version)).body.read
108
+ certificate = @s3.get_object(bucket: bucket, key: certificate_key(name, version)).body.read
109
+ chain = @s3.get_object(bucket: bucket, key: chain_key(name, version)).body.read
110
+ private_key = @s3.get_object(bucket: bucket, key: private_key_key(name, version)).body.read
111
111
  Certificate.new(certificate, chain, private_key)
112
112
  rescue Aws::S3::Errors::NoSuchKey
113
- raise NotExist.new("Certificate for #{common_name.inspect} of #{version} version doesn't exist")
113
+ raise NotExist.new("Certificate for #{name.inspect} of #{version} version doesn't exist")
114
114
  end
115
115
 
116
116
  def list_certificates
@@ -125,8 +125,8 @@ module Acmesmith
125
125
  end
126
126
  end
127
127
 
128
- def list_certificate_versions(common_name)
129
- cert_ver_prefix = "#{prefix}certs/#{common_name}/"
128
+ def list_certificate_versions(name)
129
+ cert_ver_prefix = "#{prefix}certs/#{name}/"
130
130
  @s3.list_objects(
131
131
  bucket: bucket,
132
132
  delimiter: '/',
@@ -137,8 +137,8 @@ module Acmesmith
137
137
  end.reject { |_| _ == 'current' }
138
138
  end
139
139
 
140
- def get_current_certificate_version(common_name)
141
- certificate_current(common_name)
140
+ def get_current_certificate_version(name)
141
+ certificate_current(name)
142
142
  end
143
143
 
144
144
  private
@@ -1,3 +1,3 @@
1
1
  module Acmesmith
2
- VERSION = "2.7.1"
2
+ VERSION = "2.8.0"
3
3
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acmesmith
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.7.1
4
+ version: 2.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sorah Fukumori
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-08-20 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: acme-client
@@ -141,20 +141,12 @@ extensions: []
141
141
  extra_rdoc_files: []
142
142
  files:
143
143
  - ".dockerignore"
144
- - ".github/FUNDING.yml"
145
- - ".github/stale.yml"
146
- - ".github/workflows/build.yml"
147
- - ".gitignore"
148
- - ".rspec"
149
144
  - ".travis.yml"
150
145
  - CHANGELOG.md
151
146
  - Dockerfile
152
- - Gemfile
153
- - Gemfile.lock
154
147
  - LICENSE.txt
155
148
  - README.md
156
149
  - Rakefile
157
- - acmesmith.gemspec
158
150
  - bin/acmesmith
159
151
  - config.sample.yml
160
152
  - docs/challenge_responders/route53.md
@@ -193,12 +185,13 @@ files:
193
185
  - lib/acmesmith/storages/s3.rb
194
186
  - lib/acmesmith/utils/finder.rb
195
187
  - lib/acmesmith/version.rb
196
- - script/console
197
- - script/setup
198
188
  homepage: https://github.com/sorah/acmesmith
199
189
  licenses:
200
190
  - MIT
201
- metadata: {}
191
+ metadata:
192
+ homepage_uri: https://github.com/sorah/acmesmith
193
+ source_code_uri: https://github.com/sorah/acmesmith
194
+ changelog_uri: https://github.com/sorah/acmesmith/blob/master/CHANGELOG.md
202
195
  rdoc_options: []
203
196
  require_paths:
204
197
  - lib
@@ -213,7 +206,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
213
206
  - !ruby/object:Gem::Version
214
207
  version: '0'
215
208
  requirements: []
216
- rubygems_version: 3.6.2
209
+ rubygems_version: 3.6.9
217
210
  specification_version: 4
218
211
  summary: ACME client (Let's encrypt client) to manage certificate in multi server
219
212
  environment with cloud services (e.g. AWS)
data/.github/FUNDING.yml DELETED
@@ -1,2 +0,0 @@
1
- ko_fi: sorah
2
- github: [sorah]
data/.github/stale.yml DELETED
@@ -1,17 +0,0 @@
1
- # Number of days of inactivity before an issue becomes stale
2
- daysUntilStale: 30
3
- # Number of days of inactivity before a stale issue is closed
4
- daysUntilClose: 7
5
- # Issues with these labels will never be considered stale
6
- exemptLabels:
7
- - pinned
8
- - security
9
- # Label to use when marking an issue as stale
10
- staleLabel: rotten
11
- # Comment to post when marking an issue as stale. Set to `false` to disable
12
- markComment: >
13
- This issue has been automatically marked as stale because it has not had
14
- recent activity. It will be closed if no further activity occurs. Thank you
15
- for your contributions.
16
- # Comment to post when closing a stale issue. Set to `false` to disable
17
- closeComment: false
@@ -1,113 +0,0 @@
1
- name: ci
2
- on:
3
- schedule:
4
- - cron: '36 7 2,12,22 * *'
5
- create: {}
6
- pull_request:
7
- branches: [master]
8
- push:
9
- branches: [master, ci-test]
10
-
11
- env:
12
- DOCKER_REPO: 'sorah/acmesmith'
13
-
14
- jobs:
15
- test:
16
- name: rspec
17
- runs-on: ubuntu-latest
18
- strategy:
19
- fail-fast: false
20
- matrix:
21
- ruby-version: ['3.2', '3.3', '3.4']
22
- steps:
23
- - uses: actions/checkout@master
24
- - uses: sorah-rbpkg/actions@v2
25
- with:
26
- ruby-version: "${{ matrix.ruby-version }}"
27
- bundler-cache: true
28
- - run: 'bundle exec rspec -fd'
29
-
30
- integration-pebble:
31
- name: integration-pebble
32
- runs-on: ubuntu-latest
33
- strategy:
34
- fail-fast: false
35
- matrix:
36
- ruby-version: ['3.2', '3.3', '3.4']
37
-
38
- # FIXME: once GitHub Actions gains support of adding command line arguments to container
39
- # services:
40
- # # https://github.com/letsencrypt/pebble
41
- # pebble:
42
- # image: letsencrypt/pebble
43
- # ports:
44
- # - 14000:14000 # ACME port
45
- # - 15000:15000 # Management port
46
- # options: "pebble -config /test/config/pebble-config.json -strict -dnsserver 127.0.0.1:8053"
47
- #
48
- # challtestsrv:
49
- # image: letsencrypt/pebble-challtestsrv:latest
50
- # ports:
51
- # - 8055:8055 # HTTP Management API
52
- # - 8053:8053/udp # DNS
53
- # - 8053:8053 # DNS
54
- # options: 'pebble-challtestsrv -management :8055 -defaultIPv4 127.0.0.1'
55
-
56
- steps:
57
- - uses: actions/checkout@master
58
-
59
- - uses: sorah-rbpkg/actions@v2
60
- with:
61
- ruby-version: "${{ matrix.ruby-version }}"
62
- bundler-cache: true
63
-
64
- - run: 'docker run -d --net=host --rm letsencrypt/pebble pebble -config /test/config/pebble-config.json -strict -dnsserver 127.0.0.1:8053'
65
- - run: 'docker run -d --net=host --rm letsencrypt/pebble-challtestsrv pebble-challtestsrv -management :8055 -defaultIPv4 127.0.0.1'
66
- - run: 'bundle exec rspec -fd -t integration_pebble'
67
-
68
- docker-build:
69
- name: docker-build
70
- runs-on: ubuntu-latest
71
- steps:
72
- - uses: actions/checkout@master
73
- - run: 'echo $GITHUB_SHA > REVISION'
74
-
75
- - run: "docker pull ${DOCKER_REPO}:latest || :"
76
- - name: "docker tag ${DOCKER_REPO}:${TAG} ${DOCKER_REPO}:latest"
77
- run: |
78
- TAG=$(basename "${{ github.ref }}")
79
- docker pull ${DOCKER_REPO}:${TAG} || :
80
- docker tag ${DOCKER_REPO}:${TAG} ${DOCKER_REPO}:latest || :
81
- if: "${{ startsWith(github.ref, 'refs/tags/v') }}"
82
-
83
- - run: "docker pull ${DOCKER_REPO}:builder || :"
84
-
85
- - run: "docker build --pull --cache-from ${DOCKER_REPO}:builder --target builder -t ${DOCKER_REPO}:builder -f Dockerfile ."
86
- - run: "docker build --pull --cache-from ${DOCKER_REPO}:builder --cache-from ${DOCKER_REPO}:latest -t ${DOCKER_REPO}:${GITHUB_SHA} -f Dockerfile ."
87
-
88
- - run: "echo ${{ secrets.DOCKERHUB_TOKEN }} | docker login -u sorah --password-stdin"
89
- if: "${{ github.event_name != 'pull_request' }}"
90
-
91
- - run: "docker push ${DOCKER_REPO}:builder"
92
- if: "${{ github.ref == 'refs/heads/master' }}"
93
- - run: "docker push ${DOCKER_REPO}:${GITHUB_SHA}"
94
- if: "${{ github.event_name != 'pull_request' }}"
95
-
96
- docker-push:
97
- name: docker-push
98
- needs: [test, integration-pebble, docker-build]
99
- if: "${{ github.event_name == 'push' || github.event_name == 'create' }}"
100
- runs-on: ubuntu-latest
101
- steps:
102
- - run: "echo ${{ secrets.DOCKERHUB_TOKEN }} | docker login -u sorah --password-stdin"
103
- - run: "docker pull ${DOCKER_REPO}:${GITHUB_SHA}"
104
-
105
- - run: |
106
- docker tag ${DOCKER_REPO}:${GITHUB_SHA} ${DOCKER_REPO}:latest
107
- docker push ${DOCKER_REPO}:latest
108
- if: "${{ github.ref == 'refs/heads/master' }}"
109
- - run: |
110
- TAG=$(basename "${{ github.ref }}")
111
- docker tag ${DOCKER_REPO}:${GITHUB_SHA} ${DOCKER_REPO}:${TAG}
112
- docker push ${DOCKER_REPO}:${TAG}
113
- if: "${{ startsWith(github.ref, 'refs/tags/v') }}"
data/.gitignore DELETED
@@ -1,12 +0,0 @@
1
- /.bundle/
2
- /.yardoc
3
- /_yardoc/
4
- /coverage/
5
- /doc/
6
- /pkg/
7
- /spec/reports/
8
- /tmp/
9
- acmesmith.yml
10
- config.yml
11
- config.dev.yml
12
- /storage/
data/.rspec DELETED
@@ -1,2 +0,0 @@
1
- --format documentation
2
- --color
data/Gemfile DELETED
@@ -1,6 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- # Specify your gem's dependencies in acmesmith.gemspec
4
- gemspec
5
-
6
- gem 'rexml'
data/Gemfile.lock DELETED
@@ -1,84 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- acmesmith (2.7.1)
5
- acme-client (>= 2.0.7, < 3)
6
- aws-sdk-acm
7
- aws-sdk-route53
8
- aws-sdk-s3
9
- thor
10
-
11
- GEM
12
- remote: https://rubygems.org/
13
- specs:
14
- acme-client (2.0.19)
15
- base64 (~> 0.2.0)
16
- faraday (>= 1.0, < 3.0.0)
17
- faraday-retry (>= 1.0, < 3.0.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)
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)
27
- jmespath (~> 1, >= 1.6.1)
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)
36
- aws-sdk-kms (~> 1)
37
- aws-sigv4 (~> 1.5)
38
- aws-sigv4 (1.10.1)
39
- aws-eventstream (~> 1, >= 1.0.2)
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)
49
- faraday (~> 2.0)
50
- jmespath (1.6.2)
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)
64
- diff-lcs (>= 1.2.0, < 2.0)
65
- rspec-support (~> 3.13.0)
66
- rspec-mocks (3.13.2)
67
- diff-lcs (>= 1.2.0, < 2.0)
68
- rspec-support (~> 3.13.0)
69
- rspec-support (3.13.2)
70
- thor (1.4.0)
71
- uri (1.0.3)
72
-
73
- PLATFORMS
74
- ruby
75
-
76
- DEPENDENCIES
77
- acmesmith!
78
- bundler
79
- rake
80
- rexml
81
- rspec
82
-
83
- BUNDLED WITH
84
- 2.5.23
data/acmesmith.gemspec DELETED
@@ -1,33 +0,0 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'acmesmith/version'
5
-
6
- Gem::Specification.new do |spec|
7
- spec.name = "acmesmith"
8
- spec.version = Acmesmith::VERSION
9
- spec.authors = ["Sorah Fukumori"]
10
- spec.email = ["her@sorah.jp"]
11
-
12
- spec.summary = %q{ACME client (Let's encrypt client) to manage certificate in multi server environment with cloud services (e.g. AWS)}
13
- spec.description = <<-EOF
14
- Acmesmith is an [ACME (Automatic Certificate Management Environment)](https://github.com/ietf-wg-acme/acme) client that works perfect on environment with multiple servers. This client saves certificate and keys on cloud services (e.g. AWS S3) securely, then allow to deploy issued certificates onto your servers smoothly. This works well on [Let's encrypt](https://letsencrypt.org).
15
- EOF
16
- spec.homepage = "https://github.com/sorah/acmesmith"
17
- spec.license = "MIT"
18
-
19
- spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
20
- spec.bindir = "bin"
21
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
22
- spec.require_paths = ["lib"]
23
-
24
- spec.add_dependency "acme-client", '>= 2.0.7', '< 3'
25
- spec.add_dependency "aws-sdk-acm"
26
- spec.add_dependency "aws-sdk-route53"
27
- spec.add_dependency "aws-sdk-s3"
28
- spec.add_dependency "thor"
29
-
30
- spec.add_development_dependency "bundler"
31
- spec.add_development_dependency "rake"
32
- spec.add_development_dependency "rspec"
33
- end
data/script/console DELETED
@@ -1,14 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require "bundler/setup"
4
- require "acmesmith"
5
-
6
- # You can add fixtures and/or initialization code here to make experimenting
7
- # with your gem easier. You can also use a different console, if you like.
8
-
9
- # (If you use this, don't forget to add pry to your Gemfile!)
10
- # require "pry"
11
- # Pry.start
12
-
13
- require "irb"
14
- IRB.start
data/script/setup DELETED
@@ -1,7 +0,0 @@
1
- #!/bin/bash
2
- set -euo pipefail
3
- IFS=$'\n\t'
4
-
5
- bundle install
6
-
7
- # Do any other automated setup that you need to do here