record_store 7.0.1 → 7.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +9 -3
- data/lib/record_store/provider/cloudflare/client.rb +97 -0
- data/lib/record_store/provider/cloudflare/response.rb +60 -0
- data/lib/record_store/provider/cloudflare.rb +192 -0
- data/lib/record_store/provider.rb +5 -3
- data/lib/record_store/version.rb +1 -1
- data/lib/record_store.rb +1 -0
- data/record_store.gemspec +2 -2
- data/template/secrets.json +4 -0
- metadata +19 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e9f48a40d3262e148fff5aecff8c61e5f4f676bdc7f7bcb64e2964dc221ba078
|
4
|
+
data.tar.gz: 48a44aa9fc8a431653d09c1c524bcfee73ea09e6148ae9ff0552110b7db51173
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cb623045bb1b2db82232eb037adaf05a13c234d9d82e760603075ec590b5528f2daeb6dfe1df28bd6cc1987ba379f8ee070547af3336bb11213651012d527f5b
|
7
|
+
data.tar.gz: 73618a9cbae3b16028bcaa7dba64dda74e4324427fda3e364c7df0087ed72828f36965dae239bc0a2c37c1c7aece20950e0a0556a325e4cd10082e74c2da3429
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -95,6 +95,12 @@ Regarding the `fingerprint` and `key_content`, you'll need to generate an API Si
|
|
95
95
|
|
96
96
|
The `tenancy` and `region` are in the `Profile` menu. The `tenancy` starts with `ocid1.tenancy.oc1..`.
|
97
97
|
|
98
|
+
### Cloudflare
|
99
|
+
|
100
|
+
Record_store and the Cloudflare provider do not have any concept of a zone id or account. Zone names must be unique within all accounts the API key has access to, otherwise Cloudflare provider will error.
|
101
|
+
|
102
|
+
`ALIAS` records in zone files are supported and created in Cloudflare as [per-record flattened](https://developers.cloudflare.com/dns/cname-flattening/set-up-cname-flattening/#per-record) CNAME records.
|
103
|
+
|
98
104
|
----
|
99
105
|
|
100
106
|
# Architecture
|
@@ -184,14 +190,14 @@ class Provider
|
|
184
190
|
#
|
185
191
|
# Arguments:
|
186
192
|
# record - a kind of `Record`
|
187
|
-
def add(
|
193
|
+
def add(record, zone)
|
188
194
|
end
|
189
195
|
|
190
196
|
# Deletes an existing record from the zone. It is expected this call modifies external state.
|
191
197
|
#
|
192
198
|
# Arguments:
|
193
199
|
# record - a kind of `Record`
|
194
|
-
def remove(
|
200
|
+
def remove(record, zone)
|
195
201
|
end
|
196
202
|
|
197
203
|
# Updates an existing record in the zone. It is expected this call modifies external state.
|
@@ -199,7 +205,7 @@ class Provider
|
|
199
205
|
# Arguments:
|
200
206
|
# id - provider specific ID of record to update
|
201
207
|
# record - a kind of `Record` which the record with `id` should be updated to
|
202
|
-
def update(
|
208
|
+
def update(id, record, zone)
|
203
209
|
end
|
204
210
|
end
|
205
211
|
```
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require_relative 'response'
|
3
|
+
|
4
|
+
module Cloudflare
|
5
|
+
class Client
|
6
|
+
def initialize(api_fqdn, api_token)
|
7
|
+
@api_fqdn = api_fqdn
|
8
|
+
@api_token = api_token
|
9
|
+
end
|
10
|
+
|
11
|
+
def get(endpoint, params = {})
|
12
|
+
uri = build_uri(endpoint, params)
|
13
|
+
|
14
|
+
response = request(:get, uri)
|
15
|
+
Cloudflare::Response.new(response)
|
16
|
+
end
|
17
|
+
|
18
|
+
def post(endpoint, body = nil)
|
19
|
+
uri = build_uri(endpoint)
|
20
|
+
|
21
|
+
response = request(:post, uri, body: body)
|
22
|
+
Cloudflare::Response.new(response)
|
23
|
+
end
|
24
|
+
|
25
|
+
def put(endpoint, body = nil)
|
26
|
+
uri = build_uri(endpoint)
|
27
|
+
|
28
|
+
response = request(:put, uri, body: body)
|
29
|
+
Cloudflare::Response.new(response)
|
30
|
+
end
|
31
|
+
|
32
|
+
def patch(endpoint, body = nil)
|
33
|
+
uri = build_uri(endpoint)
|
34
|
+
|
35
|
+
response = request(:patch, uri, body: body)
|
36
|
+
Cloudflare::Response.new(response)
|
37
|
+
end
|
38
|
+
|
39
|
+
def delete(endpoint)
|
40
|
+
uri = build_uri(endpoint)
|
41
|
+
|
42
|
+
response = request(:delete, uri)
|
43
|
+
Cloudflare::Response.new(response)
|
44
|
+
end
|
45
|
+
|
46
|
+
def request(method, uri, body: nil)
|
47
|
+
Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |conn|
|
48
|
+
request = case method
|
49
|
+
when :get
|
50
|
+
Net::HTTP::Get.new(uri)
|
51
|
+
when :post
|
52
|
+
request = Net::HTTP::Post.new(uri)
|
53
|
+
request.body = body.to_json if body
|
54
|
+
request
|
55
|
+
when :put
|
56
|
+
request = Net::HTTP::Put.new(uri)
|
57
|
+
request.body = body.to_json if body
|
58
|
+
request
|
59
|
+
when :patch
|
60
|
+
request = Net::HTTP::Patch.new(uri)
|
61
|
+
request.body = body.to_json if body
|
62
|
+
request
|
63
|
+
when :delete
|
64
|
+
Net::HTTP::Delete.new(uri)
|
65
|
+
end
|
66
|
+
|
67
|
+
cloudflare_headers.each { |k, v| request[k] = v }
|
68
|
+
|
69
|
+
begin
|
70
|
+
response = conn.request(request)
|
71
|
+
rescue StandardError => e
|
72
|
+
raise "HTTP error: #{e.message}"
|
73
|
+
end
|
74
|
+
response
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def cloudflare_headers
|
81
|
+
@cloudflare_headers ||= {
|
82
|
+
'User-Agent' => "Ruby",
|
83
|
+
'Accept' => 'application/json',
|
84
|
+
'Content-Type' => 'application/json',
|
85
|
+
'Authorization' => "Bearer #{@api_token}"
|
86
|
+
}
|
87
|
+
end
|
88
|
+
|
89
|
+
def build_uri(endpoint, params = {})
|
90
|
+
URI::HTTPS.build(
|
91
|
+
host: @api_fqdn,
|
92
|
+
path: endpoint.chomp('/'),
|
93
|
+
query: URI.encode_www_form(params),
|
94
|
+
)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Cloudflare
|
4
|
+
class Response
|
5
|
+
attr_reader :http_response
|
6
|
+
|
7
|
+
def initialize(http_response)
|
8
|
+
@http_response = http_response
|
9
|
+
end
|
10
|
+
|
11
|
+
def status_code
|
12
|
+
@http_response.code.to_i
|
13
|
+
end
|
14
|
+
|
15
|
+
def result_raw
|
16
|
+
result = json['result']
|
17
|
+
|
18
|
+
return if result.nil? || result.empty? || !success
|
19
|
+
|
20
|
+
result
|
21
|
+
end
|
22
|
+
|
23
|
+
def result
|
24
|
+
result = result_raw
|
25
|
+
return result.first if result.is_a?(Array)
|
26
|
+
|
27
|
+
result
|
28
|
+
end
|
29
|
+
|
30
|
+
def success
|
31
|
+
json['success']
|
32
|
+
end
|
33
|
+
|
34
|
+
def errors
|
35
|
+
json.fetch('errors', [])
|
36
|
+
end
|
37
|
+
|
38
|
+
def messages
|
39
|
+
json.fetch('messages', [])
|
40
|
+
end
|
41
|
+
|
42
|
+
def error_messages
|
43
|
+
errors.map { |error| error['message'] }
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def json_content?
|
49
|
+
@http_response['Content-Type']&.match?(%r{application/json})
|
50
|
+
end
|
51
|
+
|
52
|
+
def json
|
53
|
+
return {} unless json_content?
|
54
|
+
|
55
|
+
JSON.parse(@http_response.body)
|
56
|
+
rescue JSON::ParserError => e
|
57
|
+
raise "JSON parsing error: #{e.message}"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,192 @@
|
|
1
|
+
require_relative 'cloudflare/client'
|
2
|
+
|
3
|
+
module RecordStore
|
4
|
+
class Provider::Cloudflare < Provider
|
5
|
+
class << self
|
6
|
+
def record_types
|
7
|
+
super | Set.new(%w(PTR))
|
8
|
+
end
|
9
|
+
|
10
|
+
def supports_alias?
|
11
|
+
true
|
12
|
+
end
|
13
|
+
|
14
|
+
def supports_spf?
|
15
|
+
# New as Cloudflare doesn't support the now deprecated spf type
|
16
|
+
false
|
17
|
+
end
|
18
|
+
|
19
|
+
# Returns: an array of `Record` for each record in the provider's zone
|
20
|
+
def retrieve_current_records(zone:, stdout: $stdout)
|
21
|
+
zone_id = zone_name_to_id(zone)
|
22
|
+
|
23
|
+
retry_on_connection_errors do
|
24
|
+
records = client.get("/client/v4/zones/#{zone_id}/dns_records").result_raw || []
|
25
|
+
records.map { |api_body| build_from_api(api_body) }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Returns an array of the zones managed by provider as strings
|
30
|
+
# Cloudflare returns zones across all accounts accessible by the API token
|
31
|
+
# Can implement filtering in request if needed
|
32
|
+
def zones
|
33
|
+
retry_on_connection_errors do
|
34
|
+
zones = client.get('/client/v4/zones').result_raw || []
|
35
|
+
zones.map { |zone| zone['name'] }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def apply_changeset(changeset, stdout = $stdout)
|
40
|
+
deletes = []
|
41
|
+
patches = []
|
42
|
+
posts = []
|
43
|
+
puts = []
|
44
|
+
|
45
|
+
changeset.changes.each do |change|
|
46
|
+
case change.type
|
47
|
+
when :removal
|
48
|
+
stdout.puts "Removing #{change.record}..."
|
49
|
+
deletes << { id: change.record.id }
|
50
|
+
when :addition
|
51
|
+
stdout.puts "Creating #{change.record}..."
|
52
|
+
posts << build_api_body(change.record)
|
53
|
+
when :update
|
54
|
+
stdout.puts "Updating record with ID #{change.id} to #{change.record}..."
|
55
|
+
patches << build_api_body(change.record).merge(id: change.id)
|
56
|
+
else
|
57
|
+
raise ArgumentError, "Unknown change type #{change.type.inspect}"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
zone_id = zone_name_to_id(changeset.zone)
|
62
|
+
api_body = {
|
63
|
+
deletes: deletes,
|
64
|
+
patches: patches,
|
65
|
+
posts: posts,
|
66
|
+
puts: puts
|
67
|
+
}
|
68
|
+
|
69
|
+
retry_on_connection_errors do
|
70
|
+
response = client.post("/client/v4/zones/#{zone_id}/dns_records/batch", api_body)
|
71
|
+
unless response.success
|
72
|
+
error_message = response.errors.map { |error| error['message'] }.join(', ')
|
73
|
+
raise RecordStore::Provider::Error, "Cloudflare API error: #{error_message}"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def secrets
|
81
|
+
super.fetch('cloudflare')
|
82
|
+
end
|
83
|
+
|
84
|
+
def build_api_body(record)
|
85
|
+
api_body = {
|
86
|
+
name: record.fqdn,
|
87
|
+
ttl: record.ttl,
|
88
|
+
type: record.type,
|
89
|
+
}
|
90
|
+
case record
|
91
|
+
when Record::A, Record::AAAA
|
92
|
+
api_body[:content] = record.rdata_txt
|
93
|
+
when Record::CNAME
|
94
|
+
api_body[:content] = record.rdata_txt
|
95
|
+
when Record::PTR
|
96
|
+
api_body[:content] = record.rdata_txt
|
97
|
+
when Record::MX
|
98
|
+
api_body[:content] = record.exchange
|
99
|
+
api_body[:priority] = record.preference
|
100
|
+
when Record::TXT, Record::SPF
|
101
|
+
api_body[:content] = record.txtdata.gsub('\;', ';')
|
102
|
+
when Record::CAA
|
103
|
+
api_body[:data] = record.rdata
|
104
|
+
when Record::SRV
|
105
|
+
api_body[:data] = rdata
|
106
|
+
when Record::ALIAS
|
107
|
+
api_body[:type] = 'CNAME'
|
108
|
+
api_body[:content] = record.rdata_txt
|
109
|
+
api_body[:settings] = { flatten_cname: true }
|
110
|
+
when Record::NS
|
111
|
+
api_body[:content] = record.nsdname
|
112
|
+
end
|
113
|
+
|
114
|
+
api_body
|
115
|
+
end
|
116
|
+
|
117
|
+
def build_from_api(api_response)
|
118
|
+
fqdn = Record.ensure_ends_with_dot(api_response['name'])
|
119
|
+
|
120
|
+
record_type = api_response['type']
|
121
|
+
|
122
|
+
record = {
|
123
|
+
record_id: api_response['id'],
|
124
|
+
ttl: api_response['ttl'],
|
125
|
+
fqdn: fqdn.downcase,
|
126
|
+
}
|
127
|
+
|
128
|
+
case record_type
|
129
|
+
when 'A', 'AAAA'
|
130
|
+
record.merge!(address: api_response['content'])
|
131
|
+
when 'CNAME'
|
132
|
+
if api_response.dig('settings', 'flatten_cname')
|
133
|
+
record_type = 'ALIAS'
|
134
|
+
record.merge!(alias: api_response['content'])
|
135
|
+
else
|
136
|
+
record.merge!(cname: api_response['content'])
|
137
|
+
end
|
138
|
+
when 'TXT'
|
139
|
+
record.merge!(txtdata: Record.unescape(api_response['content']).gsub(';', '\;'))
|
140
|
+
when 'MX'
|
141
|
+
record.merge!(preference: api_response['priority'], exchange: api_response['content'])
|
142
|
+
when 'PTR'
|
143
|
+
record.merge!(ptrdname: api_response['content'])
|
144
|
+
when 'CAA'
|
145
|
+
flags, tag, value = api_response['content'].split(' ')
|
146
|
+
|
147
|
+
record.merge!(
|
148
|
+
flags: flags.to_i,
|
149
|
+
tag: tag,
|
150
|
+
value: Record.unquote(value),
|
151
|
+
)
|
152
|
+
when 'SRV'
|
153
|
+
weight, port, host = api_response['content'].split(' ')
|
154
|
+
|
155
|
+
record.merge!(
|
156
|
+
priority: api_response['priority'].to_i,
|
157
|
+
weight: weight.to_i,
|
158
|
+
port: port.to_i,
|
159
|
+
target: Record.ensure_ends_with_dot(host),
|
160
|
+
)
|
161
|
+
when 'NS'
|
162
|
+
record.merge!(nsdname: api_response['content'])
|
163
|
+
end
|
164
|
+
|
165
|
+
Record.const_get(record_type).new(record)
|
166
|
+
end
|
167
|
+
|
168
|
+
def client
|
169
|
+
Cloudflare::Client.new(
|
170
|
+
secrets['api_fqdn'],
|
171
|
+
secrets['api_token'],
|
172
|
+
)
|
173
|
+
end
|
174
|
+
|
175
|
+
def zone_name_to_id(zone_name)
|
176
|
+
retry_on_connection_errors do
|
177
|
+
matching_zones = client.get('/client/v4/zones').result_raw.select { |zone| zone['name'] == zone_name }
|
178
|
+
|
179
|
+
case matching_zones.size
|
180
|
+
when 0
|
181
|
+
raise "Zone not found for #{zone_name}"
|
182
|
+
when 1
|
183
|
+
matching_zones.first['id']
|
184
|
+
else
|
185
|
+
raise "Multiple zones found for #{zone_name}. " \
|
186
|
+
"API key must only return the zone on which records are to be managed."
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
@@ -36,6 +36,8 @@ module RecordStore
|
|
36
36
|
'NS1'
|
37
37
|
when /\.oraclecloud\.net\z/
|
38
38
|
'OracleCloudDNS'
|
39
|
+
when /\.cloudflare\.com\z/
|
40
|
+
'Cloudflare'
|
39
41
|
end
|
40
42
|
end
|
41
43
|
|
@@ -121,15 +123,15 @@ module RecordStore
|
|
121
123
|
|
122
124
|
private
|
123
125
|
|
124
|
-
def add(record)
|
126
|
+
def add(record, zone)
|
125
127
|
raise NotImplementedError
|
126
128
|
end
|
127
129
|
|
128
|
-
def remove(record)
|
130
|
+
def remove(record, zone)
|
129
131
|
raise NotImplementedError
|
130
132
|
end
|
131
133
|
|
132
|
-
def update(id, record)
|
134
|
+
def update(id, record, zone)
|
133
135
|
raise NotImplementedError
|
134
136
|
end
|
135
137
|
|
data/lib/record_store/version.rb
CHANGED
data/lib/record_store.rb
CHANGED
@@ -36,6 +36,7 @@ require 'record_store/provider/dnsimple'
|
|
36
36
|
require 'record_store/provider/google_cloud_dns'
|
37
37
|
require 'record_store/provider/ns1'
|
38
38
|
require 'record_store/provider/oracle_cloud_dns'
|
39
|
+
require 'record_store/provider/cloudflare'
|
39
40
|
require 'record_store/cli'
|
40
41
|
|
41
42
|
module RecordStore
|
data/record_store.gemspec
CHANGED
@@ -35,7 +35,7 @@ Gem::Specification.new do |spec|
|
|
35
35
|
spec.add_runtime_dependency 'fog-dynect', '>= 0.4', '< 0.6'
|
36
36
|
spec.add_runtime_dependency 'fog-json'
|
37
37
|
spec.add_runtime_dependency 'fog-xml'
|
38
|
-
spec.add_runtime_dependency 'google-cloud-dns', '
|
38
|
+
spec.add_runtime_dependency 'google-cloud-dns', '>= 0.31', '< 2.0'
|
39
39
|
spec.add_runtime_dependency 'ns1'
|
40
40
|
spec.add_runtime_dependency 'oci', '>= 2.14', '< 2.22'
|
41
41
|
spec.add_runtime_dependency 'ruby-limiter', '>= 1.0.1', '< 3'
|
@@ -46,7 +46,7 @@ Gem::Specification.new do |spec|
|
|
46
46
|
spec.add_development_dependency 'mocha'
|
47
47
|
spec.add_development_dependency 'pry'
|
48
48
|
spec.add_development_dependency 'rake'
|
49
|
-
spec.add_development_dependency 'rubocop', '~> 1.
|
49
|
+
spec.add_development_dependency 'rubocop', '~> 1.67.0'
|
50
50
|
spec.add_development_dependency 'rubocop-shopify', '~> 2.15.1'
|
51
51
|
spec.add_development_dependency 'vcr'
|
52
52
|
spec.add_development_dependency 'webmock'
|
data/template/secrets.json
CHANGED
@@ -23,5 +23,9 @@
|
|
23
23
|
"token_uri": "https://oauth2.googleapis.com/token",
|
24
24
|
"auth_provider_x509_cert_url": "auth_provider_x509_cert_url",
|
25
25
|
"client_x509_cert_url": "client_x509_cert_url"
|
26
|
+
},
|
27
|
+
"cloudflare": {
|
28
|
+
"api_fqdn": "api.cloudflare.com",
|
29
|
+
"api_token": "local-dev-key"
|
26
30
|
}
|
27
31
|
}
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: record_store
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 7.
|
4
|
+
version: 7.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Willem van Bergen
|
8
8
|
- Emil Stolarsky
|
9
|
-
autorequire:
|
9
|
+
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2024-
|
12
|
+
date: 2024-10-22 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activemodel
|
@@ -145,16 +145,22 @@ dependencies:
|
|
145
145
|
name: google-cloud-dns
|
146
146
|
requirement: !ruby/object:Gem::Requirement
|
147
147
|
requirements:
|
148
|
-
- - "
|
148
|
+
- - ">="
|
149
149
|
- !ruby/object:Gem::Version
|
150
150
|
version: '0.31'
|
151
|
+
- - "<"
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: '2.0'
|
151
154
|
type: :runtime
|
152
155
|
prerelease: false
|
153
156
|
version_requirements: !ruby/object:Gem::Requirement
|
154
157
|
requirements:
|
155
|
-
- - "
|
158
|
+
- - ">="
|
156
159
|
- !ruby/object:Gem::Version
|
157
160
|
version: '0.31'
|
161
|
+
- - "<"
|
162
|
+
- !ruby/object:Gem::Version
|
163
|
+
version: '2.0'
|
158
164
|
- !ruby/object:Gem::Dependency
|
159
165
|
name: ns1
|
160
166
|
requirement: !ruby/object:Gem::Requirement
|
@@ -299,14 +305,14 @@ dependencies:
|
|
299
305
|
requirements:
|
300
306
|
- - "~>"
|
301
307
|
- !ruby/object:Gem::Version
|
302
|
-
version: 1.
|
308
|
+
version: 1.67.0
|
303
309
|
type: :development
|
304
310
|
prerelease: false
|
305
311
|
version_requirements: !ruby/object:Gem::Requirement
|
306
312
|
requirements:
|
307
313
|
- - "~>"
|
308
314
|
- !ruby/object:Gem::Version
|
309
|
-
version: 1.
|
315
|
+
version: 1.67.0
|
310
316
|
- !ruby/object:Gem::Dependency
|
311
317
|
name: rubocop-shopify
|
312
318
|
requirement: !ruby/object:Gem::Requirement
|
@@ -383,6 +389,9 @@ files:
|
|
383
389
|
- lib/record_store/changeset.rb
|
384
390
|
- lib/record_store/cli.rb
|
385
391
|
- lib/record_store/provider.rb
|
392
|
+
- lib/record_store/provider/cloudflare.rb
|
393
|
+
- lib/record_store/provider/cloudflare/client.rb
|
394
|
+
- lib/record_store/provider/cloudflare/response.rb
|
386
395
|
- lib/record_store/provider/dnsimple.rb
|
387
396
|
- lib/record_store/provider/dnsimple/patch_api_header.rb
|
388
397
|
- lib/record_store/provider/dnsimple/patch_request_error_to_include_errors.rb
|
@@ -431,7 +440,7 @@ licenses:
|
|
431
440
|
- MIT
|
432
441
|
metadata:
|
433
442
|
allowed_push_host: https://rubygems.org
|
434
|
-
post_install_message:
|
443
|
+
post_install_message:
|
435
444
|
rdoc_options: []
|
436
445
|
require_paths:
|
437
446
|
- lib
|
@@ -446,8 +455,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
446
455
|
- !ruby/object:Gem::Version
|
447
456
|
version: '0'
|
448
457
|
requirements: []
|
449
|
-
rubygems_version: 3.5.
|
450
|
-
signing_key:
|
458
|
+
rubygems_version: 3.5.22
|
459
|
+
signing_key:
|
451
460
|
specification_version: 4
|
452
461
|
summary: Manage DNS using git
|
453
462
|
test_files: []
|