From e604c27282122c19c9f5611d3c26407e69d10add Mon Sep 17 00:00:00 2001 From: Kaka Ruto Date: Tue, 19 Dec 2023 17:14:22 +0300 Subject: [PATCH 1/7] Add dotenv gem and the .env file to load environment variables --- .env.example | 3 +++ README.md | 7 ++++--- gems.rb | 1 + spec/spec_helper.rb | 2 ++ 4 files changed, 10 insertions(+), 3 deletions(-) create mode 100644 .env.example diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..ea141b7 --- /dev/null +++ b/.env.example @@ -0,0 +1,3 @@ +CLOUDFLARE_EMAIL='your_cloudlare_email' +CLOUDFLARE_KEY='your_cloudflare_api_key' +CLOUDFLARE_TEST_ZONE_MANAGEMENT=true diff --git a/README.md b/README.md index 8545b56..54a0f7a 100644 --- a/README.md +++ b/README.md @@ -88,9 +88,10 @@ end 1. Fork it 2. Create your feature branch (`git checkout -b my-new-feature`) -3. Commit your changes (`git commit -am 'Add some feature'`) -4. Push to the branch (`git push origin my-new-feature`) -5. Create new Pull Request +3. Run `cp .env.example .env` to create a .env file and populate it with the required environment variables. Edit the new file appropriately +4. Commit your changes (`git commit -am 'Add some feature'`) +5. Push to the branch (`git push origin my-new-feature`) +6. Create new Pull Request ## See Also diff --git a/gems.rb b/gems.rb index 68877f6..f133799 100644 --- a/gems.rb +++ b/gems.rb @@ -19,4 +19,5 @@ gem 'simplecov' gem 'sinatra' gem 'webmock' + gem 'dotenv' end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 95093e3..c4f319f 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +require 'dotenv/load' + AUTH_EMAIL = ENV['CLOUDFLARE_EMAIL'] AUTH_KEY = ENV['CLOUDFLARE_KEY'] From b56a6dd7eedbe822dfa8a1275a9e22549f52963d Mon Sep 17 00:00:00 2001 From: Kaka Ruto Date: Tue, 19 Dec 2023 17:15:13 +0300 Subject: [PATCH 2/7] Add the pry gem for help with debugging --- gems.rb | 1 + spec/spec_helper.rb | 1 + 2 files changed, 2 insertions(+) diff --git a/gems.rb b/gems.rb index f133799..20f6996 100644 --- a/gems.rb +++ b/gems.rb @@ -20,4 +20,5 @@ gem 'sinatra' gem 'webmock' gem 'dotenv' + gem 'pry' end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index c4f319f..38c6785 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -21,6 +21,7 @@ require 'covered/rspec' require 'async/rspec' +require 'pry' require 'cloudflare/rspec/connection' require 'cloudflare/zones' From 56b0463f3aaa20400af5190ec1a38836aa488c40 Mon Sep 17 00:00:00 2001 From: Kaka Ruto Date: Tue, 19 Dec 2023 17:17:34 +0300 Subject: [PATCH 3/7] Add an endpoint to update all the values of a DNS record --- README.md | 5 +++++ lib/cloudflare/dns.rb | 11 +++++++++++ spec/cloudflare/dns_spec.rb | 27 +++++++++++++++++++++++++-- 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 54a0f7a..47aafd6 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,11 @@ Cloudflare.connect(key: key, email: email) do |connection| # Add a DNS record. Here we add an A record for `batman.example.com`: zone = zones.find_by_name("example.com") zone.dns_records.create('A', 'batman', '1.2.3.4', proxied: false) + + # Update a DNS record. Here we update the A record above to be a CNAME record to 'nairobi.kanairo.com' + record = zone.dns_records.find_by_name("example.com") } + record.update(type: "CNAME", name: "nairobi", content: "kanairo.com", proxied: true) + # Get firewall rules: all_rules = zone.firewall_rules diff --git a/lib/cloudflare/dns.rb b/lib/cloudflare/dns.rb index 0c4567c..dea2304 100644 --- a/lib/cloudflare/dns.rb +++ b/lib/cloudflare/dns.rb @@ -45,6 +45,17 @@ def update_content(content, **options) @value = response.result end + def update(type: nil, name: nil, content: nil, **options) + response = put( + type: type || @record[:type], + name: name || @record[:name], + content: content || @record[:content], + **options + ) + + @value = response.result + end + def type value[:type] end diff --git a/spec/cloudflare/dns_spec.rb b/spec/cloudflare/dns_spec.rb index 1c76e62..302fb59 100644 --- a/spec/cloudflare/dns_spec.rb +++ b/spec/cloudflare/dns_spec.rb @@ -12,7 +12,7 @@ end end - context "new record" do + describe "#create" do it "can create dns record" do @record = zone.dns_records.create("A", subdomain, "1.2.3.4") expect(@record.type).to be == "A" @@ -29,8 +29,9 @@ end end - context "with existing record" do + describe "#update_content" do let(:record) {@record = zone.dns_records.create("A", subdomain, "1.2.3.4")} + it "can update dns content" do record.update_content("4.3.2.1") expect(record.content).to be == "4.3.2.1" @@ -47,4 +48,26 @@ expect(fetched_record.proxied).to be_truthy end end + + describe "#update" do + let(:subject) { record.update(**new_params)} + + let(:record) { @record = zone.dns_records.create("A", "old", "1.2.3.4", proxied: false) } + + let(:new_params) do + { + type: "CNAME", + name: "new", + content: "example.com", + proxied: true + } + end + + it "can update dns record" do + expect { subject }.to change { record.name }.to("#{new_params[:name]}.#{zone.name}") + .and change { record.type }.to(new_params[:type]) + .and change { record.content }.to(new_params[:content]) + .and change { record.proxied }.to(new_params[:proxied]) + end + end end From 08ac2a034769b1a9cd0f9c8f7d426998478f0de0 Mon Sep 17 00:00:00 2001 From: Kaka Ruto Date: Tue, 19 Dec 2023 17:18:13 +0300 Subject: [PATCH 4/7] Move helper files into spec/support --- spec/spec_helper.rb | 30 +----------------------------- spec/support/cloudflare/account.rb | 13 +++++++++++++ spec/support/cloudflare/zone.rb | 17 +++++++++++++++++ 3 files changed, 31 insertions(+), 29 deletions(-) create mode 100644 spec/support/cloudflare/account.rb create mode 100644 spec/support/cloudflare/zone.rb diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 38c6785..e07d884 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -26,35 +26,7 @@ require 'cloudflare/rspec/connection' require 'cloudflare/zones' -RSpec.shared_context Cloudflare::Account do - include_context Cloudflare::RSpec::Connection - - let(:account) do - if ACCOUNT_ID - connection.accounts.find_by_id(ACCOUNT_ID) - else - connection.accounts.first - end - end -end - -RSpec.shared_context Cloudflare::Zone do - include_context Cloudflare::Account - - let(:job_id) {JOB_ID} - let(:names) {NAMES.dup} - let(:name) {ZONE_NAME.dup} - - let(:zones) {connection.zones} - - let(:zone) {@zone = zones.find_by_name(name) || zones.create(name, account)} - - # after do - # if defined? @zone - # @zone.delete - # end - # end -end +Dir[File.expand_path('../support/**/*.rb', __FILE__)].each{|path| require path} RSpec.configure do |config| # Enable flags like --only-failures and --next-failure diff --git a/spec/support/cloudflare/account.rb b/spec/support/cloudflare/account.rb new file mode 100644 index 0000000..88e56a0 --- /dev/null +++ b/spec/support/cloudflare/account.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +RSpec.shared_context Cloudflare::Account do + include_context Cloudflare::RSpec::Connection + + let(:account) do + if ACCOUNT_ID + connection.accounts.find_by_id(ACCOUNT_ID) + else + connection.accounts.first + end + end +end diff --git a/spec/support/cloudflare/zone.rb b/spec/support/cloudflare/zone.rb new file mode 100644 index 0000000..07b194a --- /dev/null +++ b/spec/support/cloudflare/zone.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +RSpec.shared_context Cloudflare::Zone do + include_context Cloudflare::Account + + let(:job_id) { JOB_ID } + let(:names) { NAMES.dup } + let(:name) { ZONE_NAME.dup } + + let(:zones) { connection.zones } + + let(:zone) { @zone = zones.find_by_name(name) || zones.create(name, account) } + + after do + @zone.delete if defined? @zone + end +end From 0610714a64def957eb81aa5db031403deb6c43a0 Mon Sep 17 00:00:00 2001 From: Kaka Ruto Date: Mon, 16 Sep 2024 10:52:04 +0100 Subject: [PATCH 5/7] fixup! Add dotenv gem and the .env file to load environment variables --- gems.rb | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/gems.rb b/gems.rb index 7859daf..5ff9915 100644 --- a/gems.rb +++ b/gems.rb @@ -11,23 +11,26 @@ gemspec group :maintenance, optional: true do - gem "bake-gem" - gem "bake-modernize" - - gem "utopia-project" + gem "bake-gem" + gem "bake-modernize" + + gem "utopia-project" end group :test do - gem "sus" - gem "covered" - gem "decode" - gem "rubocop" - - gem "sus-fixtures-async" - - gem "sinatra" - gem "webmock" - - gem "bake-test" - gem "bake-test-external" + gem "sus" + gem "covered" + gem "decode" + gem "rubocop" + + gem "sus-fixtures-async" + + gem "sinatra" + gem "webmock" + + gem "bake-test" + gem "bake-test-external" + + gem "dotenv" + gem "pry" end From d800631e71f1b6c33d301a5b3d63dbd0ef2755ce Mon Sep 17 00:00:00 2001 From: Kaka Ruto Date: Mon, 16 Sep 2024 10:53:04 +0100 Subject: [PATCH 6/7] fixup! Add an endpoint to update all the values of a DNS record --- test/cloudflare/dns.rb | 56 +++++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 17 deletions(-) diff --git a/test/cloudflare/dns.rb b/test/cloudflare/dns.rb index 7f3bf45..c408fa1 100644 --- a/test/cloudflare/dns.rb +++ b/test/cloudflare/dns.rb @@ -9,53 +9,75 @@ describe Cloudflare::DNS do include_context Cloudflare::AConnection - - let(:subdomain) {"www-#{job_id || SecureRandom.hex(4)}"} - + + let(:subdomain) { "www-#{job_id || SecureRandom.hex(4)}" } + with "new record" do it "can create dns record" do record = zone.dns_records.create("A", subdomain, "1.2.3.4") - + expect(record.type).to be == "A" expect(record.name).to be(:start_with?, subdomain) expect(record.content).to be == "1.2.3.4" - ensure - record&.delete + ensure + record&.delete end - + it "can create dns record with proxied option" do record = zone.dns_records.create("A", subdomain, "1.2.3.4", proxied: true) - + expect(record.type).to be == "A" expect(record.name).to be(:start_with?, subdomain) expect(record.content).to be == "1.2.3.4" expect(record.proxied).to be_truthy - ensure - record&.delete + ensure + record&.delete end end - + with "existing record" do - let(:record) {zone.dns_records.create("A", subdomain, "1.2.3.4")} - + let(:record) { zone.dns_records.create("A", subdomain, "1.2.3.4") } + after do @record&.delete end - + it "can update dns content" do record.update_content("4.3.2.1") expect(record.content).to be == "4.3.2.1" - + fetched_record = zone.dns_records.find_by_name(record.name) expect(fetched_record.content).to be == record.content end - + it "can update dns content with proxied option" do record.update_content("4.3.2.1", proxied: true) expect(record).to be(:proxied?) - + fetched_record = zone.dns_records.find_by_name(record.name) expect(fetched_record).to be(:proxied?) end end + + describe "#update" do + let(:subject) { record.update(**new_params) } + + let(:record) { @record = zone.dns_records.create("A", "old", "1.2.3.4", proxied: false) } + + let(:new_params) do + { + type: "CNAME", + name: "new", + content: "example.com", + proxied: true + } + end + + it "can update dns record" do + expect { subject }.to change { record.name }.to("#{new_params[:name]}.#{zone.name}") + .and change { record.type }.to(new_params[:type]) + .and change { record.content }.to(new_params[:content]) + .and change { record.proxied }.to(new_params[:proxied]) + end + end end From 2222b901437ab1ce55bb5d9ea5a611c630a42ba8 Mon Sep 17 00:00:00 2001 From: Kaka Ruto Date: Mon, 16 Sep 2024 10:53:34 +0100 Subject: [PATCH 7/7] Rebase with upstream --- readme.md | 46 ++++++++++++++++++---------------------------- 1 file changed, 18 insertions(+), 28 deletions(-) diff --git a/readme.md b/readme.md index f1c5784..794dc42 100644 --- a/readme.md +++ b/readme.md @@ -1,6 +1,6 @@ # Cloudflare -It is a Ruby wrapper for the Cloudflare V4 API. It provides a light weight wrapper using `RestClient::Resource`. The wrapper functionality is limited to zones and DNS records at this time, *PRs welcome*. +It is a Ruby wrapper for the Cloudflare V4 API. It provides a light weight wrapper using `RestClient::Resource`. The wrapper functionality is limited to zones and DNS records at this time, _PRs welcome_. [![Development Status](https://github.com/socketry/cloudflare/workflows/Test/badge.svg)](https://github.com/socketry/cloudflare/actions?workflow=Test) @@ -8,7 +8,7 @@ It is a Ruby wrapper for the Cloudflare V4 API. It provides a light weight wrapp Add this line to your application's Gemfile: -``` ruby +```ruby gem 'cloudflare' ``` @@ -24,7 +24,7 @@ Or install it yourself as: Here are some basic examples. For more details, refer to the code and specs. -``` ruby +```ruby require 'cloudflare' # Grab some details from somewhere: @@ -34,18 +34,18 @@ key = ENV['CLOUDFLARE_KEY'] Cloudflare.connect(key: key, email: email) do |connection| # Get all available zones: zones = connection.zones - + # Get a specific zone: zone = connection.zones.find_by_id("...") zone = connection.zones.find_by_name("example.com") - + # Get DNS records for a given zone: dns_records = zone.dns_records - + # Show some details of the DNS record: dns_record = dns_records.first puts dns_record.name - + # Add a DNS record. Here we add an A record for `batman.example.com`: zone = zones.find_by_name("example.com") zone.dns_records.create('A', 'batman', '1.2.3.4', proxied: false) @@ -54,10 +54,10 @@ Cloudflare.connect(key: key, email: email) do |connection| record = zone.dns_records.find_by_name("example.com") } record.update(type: "CNAME", name: "nairobi", content: "kanairo.com", proxied: true) - + # Get firewall rules: all_rules = zone.firewall_rules - + # Block an ip: rule = zone.firewall_rules.set('block', '1.2.3.4', notes: "ssh dictionary attack") end @@ -67,7 +67,7 @@ end You can read more about [bearer tokens here](https://blog.cloudflare.com/api-tokens-general-availability/). This allows you to limit priviledges. -``` ruby +```ruby require 'cloudflare' token = 'a_generated_api_token' @@ -79,10 +79,10 @@ end ### Using with Async -``` ruby +```ruby Async do connection = Cloudflare.connect(...) - + # ... do something with connection ... ensure connection.close @@ -91,24 +91,14 @@ end ## Contributing -1. Fork it -2. Create your feature branch (`git checkout -b my-new-feature`) -3. Run `cp .env.example .env` to create a .env file and populate it with the required environment variables. Edit the new file appropriately -4. Commit your changes (`git commit -am 'Add some feature'`) -5. Push to the branch (`git push origin my-new-feature`) -6. Create new Pull Request -1. Fork it -2. Create your feature branch (`git checkout -b my-new-feature`) -3. Commit your changes (`git commit -am 'Add some feature'`) -4. Push to the branch (`git push origin my-new-feature`) -5. Create new Pull Request We welcome contributions to this project. 1. Fork it. 2. Create your feature branch (`git checkout -b my-new-feature`). -3. Commit your changes (`git commit -am 'Add some feature'`). -4. Push to the branch (`git push origin my-new-feature`). -5. Create new Pull Request. +3. Run `cp .env.example .env` to create a .env file and populate it with the required environment variables. Edit the new file appropriately +4. Commit your changes (`git commit -am 'Add some feature'`). +5. Push to the branch (`git push origin my-new-feature`). +6. Create new Pull Request. ### Developer Certificate of Origin @@ -120,5 +110,5 @@ This project is best served by a collaborative and respectful environment. Treat ## See Also - - [Cloudflare::DNS::Update](https://github.com/ioquatix/cloudflare-dns-update) - A dynamic DNS updater based on this gem. - - [Rubyflare](https://github.com/trev/rubyflare) - Another implementation. +- [Cloudflare::DNS::Update](https://github.com/ioquatix/cloudflare-dns-update) - A dynamic DNS updater based on this gem. +- [Rubyflare](https://github.com/trev/rubyflare) - Another implementation.