From 87249f6a037e28d4ea649c6303f19e2f651a9577 Mon Sep 17 00:00:00 2001 From: Manuel Bergler Date: Thu, 16 May 2024 07:51:21 -0600 Subject: [PATCH 01/19] Add GHES Manage API client --- lib/octokit.rb | 16 ++++- lib/octokit/manage_ghes_client.rb | 64 +++++++++++++++++++ lib/octokit/manage_ghes_client/manage_ghes.rb | 47 ++++++++++++++ 3 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 lib/octokit/manage_ghes_client.rb create mode 100644 lib/octokit/manage_ghes_client/manage_ghes.rb diff --git a/lib/octokit.rb b/lib/octokit.rb index cf5340aad..dadaab7d6 100644 --- a/lib/octokit.rb +++ b/lib/octokit.rb @@ -41,12 +41,24 @@ def enterprise_management_console_client @enterprise_management_console_client = Octokit::EnterpriseManagementConsoleClient.new(options) end + # ManageGHESClient client based on configured options {Configurable} + # + # @return [Octokit::ManageGHESClient] API wrapper + def manage_ghes_client + if defined?(@manage_ghes_client) && @manage_ghes_client.same_options?(options) + return @manage_ghes_client + end + + @manage_ghes_client = Octokit::ManageGHESClient.new(options) + end + private def respond_to_missing?(method_name, include_private = false) client.respond_to?(method_name, include_private) || enterprise_admin_client.respond_to?(method_name, include_private) || - enterprise_management_console_client.respond_to?(method_name, include_private) + enterprise_management_console_client.respond_to?(method_name, include_private) || + manage_ghes_client.respond_to?(method_name, include_private) end def method_missing(method_name, *args, &block) @@ -56,6 +68,8 @@ def method_missing(method_name, *args, &block) return enterprise_admin_client.send(method_name, *args, &block) elsif enterprise_management_console_client.respond_to?(method_name) return enterprise_management_console_client.send(method_name, *args, &block) + elsif manage_ghes_client.respond_to?(method_name) + return manage_ghes_client.send(method_name, *args, &block) end super diff --git a/lib/octokit/manage_ghes_client.rb b/lib/octokit/manage_ghes_client.rb new file mode 100644 index 000000000..dfa7a3d38 --- /dev/null +++ b/lib/octokit/manage_ghes_client.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +require 'octokit/configurable' +require 'octokit/connection' +require 'octokit/warnable' +require 'octokit/manage_ghes_client/manage_ghes' + +module Octokit + # ManageGHESClient is only meant to be used by GitHub Enterprise Server (GHES) operators + # and provides access to the Manage GHES API endpoints. + # + # @see Octokit::Client Use Octokit::Client for regular API use for GitHub + # and GitHub Enterprise. + # @see https://developer.github.com/v3/enterprise-admin/manage-ghes/ + class ManageGHESClient + include Octokit::Configurable + include Octokit::Connection + include Octokit::Warnable + include Octokit::ManageGHESClient::ManageAPI + + def initialize(options = {}) + # Use options passed in, but fall back to module defaults + # rubocop:disable Style/HashEachMethods + # + # This may look like a `.keys.each` which should be replaced with `#each_key`, but + # this doesn't actually work, since `#keys` is just a method we've defined ourselves. + # The class doesn't fulfill the whole `Enumerable` contract. + Octokit::Configurable.keys.each do |key| + # rubocop:enable Style/HashEachMethods + instance_variable_set(:"@#{key}", options[key] || Octokit.instance_variable_get(:"@#{key}")) + end + end + + protected + + def endpoint + manage_ghes_endpoint + end + + # Set Manage GHES API username + # + # @param value [String] Manage GHES API username + def manage_api_username=(value) + reset_agent + @manage_api_username = value + end + + # Set Manage GHES API password + # + # @param value [String] Manage GHES API password + def manage_api_password=(value) + reset_agent + @manage_api_password = value + end + + # Set Manage GHES API endpoint + # + # @param value [String] Manage GHES API endpoint + def manage_ghes_endpoint=(value) + reset_agent + @manage_ghes_endpoint = value + end + end +end diff --git a/lib/octokit/manage_ghes_client/manage_ghes.rb b/lib/octokit/manage_ghes_client/manage_ghes.rb new file mode 100644 index 000000000..b9e6428b3 --- /dev/null +++ b/lib/octokit/manage_ghes_client/manage_ghes.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +module Octokit + class ManageGHESClient + # Methods for the Manage GitHub Enterprise Server API + # + # @see https://developer.github.com/v3/enterprise-admin/manage-ghes + module ManageAPI + end + + private + + def password_hash + { query: { api_key: @management_console_password } } + end + + def basic_authenticated? + !!(@manage_api_username && @manage_api_password) + end + + def root_site_admin_assumed? + !!(@manage_api_username) + end + + def faraday_configuration + @faraday_configuration ||= Faraday.new(url: @manage_ghes_endpoint) do |http| + http.headers[:user_agent] = user_agent + http.headers[:content_type] = 'application/json' + + if root_site_admin_assumed? + http.basic_auth('api_key', @manage_api_password) + elsif basic_authenticated? + http.basic_auth(@manage_api_username, @manage_api_password) + end + + # Disabling SSL is essential for certain self-hosted Enterprise instances + if connection_options[:ssl] && !connection_options[:ssl][:verify] + http.ssl[:verify] = false + end + + http.use Octokit::Response::RaiseError + http.adapter Faraday.default_adapter + end + end + + end +end From 8a5028a077d51584c74928a1de80539868336433 Mon Sep 17 00:00:00 2001 From: Manuel Bergler Date: Wed, 22 May 2024 12:29:55 -0600 Subject: [PATCH 02/19] Rework setting basic auth --- lib/octokit/manage_ghes_client/manage_ghes.rb | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/lib/octokit/manage_ghes_client/manage_ghes.rb b/lib/octokit/manage_ghes_client/manage_ghes.rb index b9e6428b3..19176ea96 100644 --- a/lib/octokit/manage_ghes_client/manage_ghes.rb +++ b/lib/octokit/manage_ghes_client/manage_ghes.rb @@ -10,10 +10,6 @@ module ManageAPI private - def password_hash - { query: { api_key: @management_console_password } } - end - def basic_authenticated? !!(@manage_api_username && @manage_api_password) end @@ -23,23 +19,24 @@ def root_site_admin_assumed? end def faraday_configuration - @faraday_configuration ||= Faraday.new(url: @manage_ghes_endpoint) do |http| - http.headers[:user_agent] = user_agent - http.headers[:content_type] = 'application/json' + @faraday_configuration ||= Faraday.new(url: @manage_ghes_endpoint) do |c| + c.headers[:user_agent] = user_agent + c.request :json + c.response :json if root_site_admin_assumed? - http.basic_auth('api_key', @manage_api_password) + c.basic_auth('api_key', @manage_api_password) elsif basic_authenticated? - http.basic_auth(@manage_api_username, @manage_api_password) + c.basic_auth(@manage_api_username, @manage_api_password) end # Disabling SSL is essential for certain self-hosted Enterprise instances if connection_options[:ssl] && !connection_options[:ssl][:verify] - http.ssl[:verify] = false + c.ssl[:verify] = false end - http.use Octokit::Response::RaiseError - http.adapter Faraday.default_adapter + c.use Octokit::Response::RaiseError + c.adapter Faraday.default_adapter end end From cc27cf9c8ab8d012330b554f1927ca811cc398c7 Mon Sep 17 00:00:00 2001 From: Manuel Bergler Date: Wed, 22 May 2024 12:30:08 -0600 Subject: [PATCH 03/19] Add maintenance endpoints --- lib/octokit/manage_ghes_client/manage_ghes.rb | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/lib/octokit/manage_ghes_client/manage_ghes.rb b/lib/octokit/manage_ghes_client/manage_ghes.rb index 19176ea96..925a39f4d 100644 --- a/lib/octokit/manage_ghes_client/manage_ghes.rb +++ b/lib/octokit/manage_ghes_client/manage_ghes.rb @@ -6,6 +6,23 @@ class ManageGHESClient # # @see https://developer.github.com/v3/enterprise-admin/manage-ghes module ManageAPI + # Get information about the maintenance status of the GHES instance + # + # @return [Sawyer::Resource] The maintenance mode status + def get_maintenance_mode + get '/manage/v1/maintenance' + end + alias maintenance_mode get_maintenance_mode + + # Configure the maintenance mode of the GHES instance + # + # @param maintenance [Hash] A hash configuration of the maintenance mode status + # @return [nil] + def set_maintenance_mode(enabled, options = {}) + options[:enabled] = enabled + post '/manage/v1/maintenance', options + end + alias configure_maintenance_mode set_maintenance_mode end private From a5a4bad14d30d28e09340c47d02cbfeb97110da2 Mon Sep 17 00:00:00 2001 From: Manuel Bergler Date: Wed, 22 May 2024 14:49:26 -0600 Subject: [PATCH 04/19] Fix Manage API client --- lib/octokit.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/octokit.rb b/lib/octokit.rb index dadaab7d6..b029d8bc9 100644 --- a/lib/octokit.rb +++ b/lib/octokit.rb @@ -4,6 +4,7 @@ require 'octokit/client' require 'octokit/enterprise_admin_client' require 'octokit/enterprise_management_console_client' +require 'octokit/manage_ghes_client' # Ruby toolkit for the GitHub API module Octokit From 42d013a87d713a96772b2a39b804ba70f1e3d896 Mon Sep 17 00:00:00 2001 From: Manuel Bergler Date: Wed, 22 May 2024 15:13:18 -0600 Subject: [PATCH 05/19] Rename Manage API auth params for clarity --- lib/octokit/manage_ghes_client.rb | 8 ++++---- lib/octokit/manage_ghes_client/manage_ghes.rb | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/octokit/manage_ghes_client.rb b/lib/octokit/manage_ghes_client.rb index dfa7a3d38..9b9899bf4 100644 --- a/lib/octokit/manage_ghes_client.rb +++ b/lib/octokit/manage_ghes_client.rb @@ -40,17 +40,17 @@ def endpoint # Set Manage GHES API username # # @param value [String] Manage GHES API username - def manage_api_username=(value) + def manage_ghes_username=(value) reset_agent - @manage_api_username = value + @manage_ghes_username = value end # Set Manage GHES API password # # @param value [String] Manage GHES API password - def manage_api_password=(value) + def manage_ghes_password=(value) reset_agent - @manage_api_password = value + @manage_ghes_password = value end # Set Manage GHES API endpoint diff --git a/lib/octokit/manage_ghes_client/manage_ghes.rb b/lib/octokit/manage_ghes_client/manage_ghes.rb index 925a39f4d..974191b49 100644 --- a/lib/octokit/manage_ghes_client/manage_ghes.rb +++ b/lib/octokit/manage_ghes_client/manage_ghes.rb @@ -28,11 +28,11 @@ def set_maintenance_mode(enabled, options = {}) private def basic_authenticated? - !!(@manage_api_username && @manage_api_password) + !!(@manage_ghes_username && @manage_ghes_password) end def root_site_admin_assumed? - !!(@manage_api_username) + !!(@manage_ghes_username) end def faraday_configuration @@ -42,9 +42,9 @@ def faraday_configuration c.response :json if root_site_admin_assumed? - c.basic_auth('api_key', @manage_api_password) + c.basic_auth('api_key', @manage_ghes_password) elsif basic_authenticated? - c.basic_auth(@manage_api_username, @manage_api_password) + c.basic_auth(@manage_ghes_username, @manage_ghes_password) end # Disabling SSL is essential for certain self-hosted Enterprise instances From 271cc146fa4ca1354940a0487d92b3cd3cb5a609 Mon Sep 17 00:00:00 2001 From: Manuel Bergler Date: Wed, 22 May 2024 15:16:42 -0600 Subject: [PATCH 06/19] Make Manage API params usable as options --- lib/octokit/configurable.rb | 18 +++++++++++++++++- lib/octokit/default.rb | 18 ++++++++++++++++++ lib/octokit/manage_ghes_client.rb | 16 ++++++++-------- 3 files changed, 43 insertions(+), 9 deletions(-) diff --git a/lib/octokit/configurable.rb b/lib/octokit/configurable.rb index 1ec590b45..af750190a 100644 --- a/lib/octokit/configurable.rb +++ b/lib/octokit/configurable.rb @@ -32,6 +32,12 @@ module Configurable # @return [String] An admin password set up for your GitHub Enterprise management console # @!attribute management_console_endpoint # @return [String] Base URL for API requests to the GitHub Enterprise management console + # @!attribute manage_ghes_endpoint + # @return [String] Base URL for API requests to the GitHub Enterprise Server Manage API + # @!attribute manage_ghes_username + # @return [String] API username for requests to the GitHub Enterprise Server Manage API + # @!attribute manage_ghes_password + # @return [String] API user password for requests to the GitHub Enterprise Server Manage API # @!attribute middleware # @see https://github.com/lostisland/faraday # @return [Faraday::Builder or Faraday::RackBuilder] Configure middleware for Faraday @@ -59,7 +65,10 @@ module Configurable :middleware, :netrc, :netrc_file, :per_page, :proxy, :ssl_verify_mode, :user_agent attr_writer :password, :web_endpoint, :api_endpoint, :login, - :management_console_endpoint, :management_console_password + :management_console_endpoint, :management_console_password, + :manage_ghes_endpoint, + :manage_ghes_username, + :manage_ghes_password class << self # List of configurable keys for {Octokit::Client} @@ -77,6 +86,9 @@ def keys login management_console_endpoint management_console_password + manage_ghes_endpoint + manage_ghes_username + manage_ghes_password middleware netrc netrc_file @@ -126,6 +138,10 @@ def management_console_endpoint File.join(@management_console_endpoint, '') end + def manage_ghes_endpoint + File.join(@manage_ghes_endpoint, '') + end + # Base URL for generated web URLs # # @return [String] Default: https://github.com/ diff --git a/lib/octokit/default.rb b/lib/octokit/default.rb index 852e4def1..ca2e2fb73 100644 --- a/lib/octokit/default.rb +++ b/lib/octokit/default.rb @@ -102,6 +102,24 @@ def management_console_endpoint ENV.fetch('OCTOKIT_ENTERPRISE_MANAGEMENT_CONSOLE_ENDPOINT', nil) end + # Default GHES Manage API endpoint from ENV + # @return [String] + def manage_ghes_endpoint + ENV.fetch('OCTOKIT_MANAGE_GHES_ENDPOINT', nil) + end + + # Default GHES Manage API username from ENV + # @return [String] + def manage_ghes_username + ENV.fetch('OCTOKIT_MANAGE_GHES_USERNAME', nil) + end + + # Default GHES Manage API password from ENV + # @return [String] + def manage_ghes_password + ENV.fetch('OCTOKIT_MANAGE_GHES_PASSWORD', nil) + end + # Default options for Faraday::Connection # @return [Hash] def connection_options diff --git a/lib/octokit/manage_ghes_client.rb b/lib/octokit/manage_ghes_client.rb index 9b9899bf4..8570a93ad 100644 --- a/lib/octokit/manage_ghes_client.rb +++ b/lib/octokit/manage_ghes_client.rb @@ -37,6 +37,14 @@ def endpoint manage_ghes_endpoint end + # Set Manage GHES API endpoint + # + # @param value [String] Manage GHES API endpoint + def manage_ghes_endpoint=(value) + reset_agent + @manage_ghes_endpoint = value + end + # Set Manage GHES API username # # @param value [String] Manage GHES API username @@ -52,13 +60,5 @@ def manage_ghes_password=(value) reset_agent @manage_ghes_password = value end - - # Set Manage GHES API endpoint - # - # @param value [String] Manage GHES API endpoint - def manage_ghes_endpoint=(value) - reset_agent - @manage_ghes_endpoint = value - end end end From 141f94c31d52df535d003d426750069f9ba419de Mon Sep 17 00:00:00 2001 From: Manuel Bergler Date: Fri, 24 May 2024 13:06:25 -0600 Subject: [PATCH 07/19] Use custom client and fix basic auth --- lib/octokit/manage_ghes_client/manage_ghes.rb | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/lib/octokit/manage_ghes_client/manage_ghes.rb b/lib/octokit/manage_ghes_client/manage_ghes.rb index 974191b49..71286d545 100644 --- a/lib/octokit/manage_ghes_client/manage_ghes.rb +++ b/lib/octokit/manage_ghes_client/manage_ghes.rb @@ -10,7 +10,9 @@ module ManageAPI # # @return [Sawyer::Resource] The maintenance mode status def get_maintenance_mode - get '/manage/v1/maintenance' + conn = authenticated_client + + @last_response = conn.get('/manage/v1/maintenance') end alias maintenance_mode get_maintenance_mode @@ -19,8 +21,10 @@ def get_maintenance_mode # @param maintenance [Hash] A hash configuration of the maintenance mode status # @return [nil] def set_maintenance_mode(enabled, options = {}) + conn = authenticated_client + options[:enabled] = enabled - post '/manage/v1/maintenance', options + @last_response = conn.post('/manage/v1/maintenance', options) end alias configure_maintenance_mode set_maintenance_mode end @@ -35,17 +39,20 @@ def root_site_admin_assumed? !!(@manage_ghes_username) end - def faraday_configuration - @faraday_configuration ||= Faraday.new(url: @manage_ghes_endpoint) do |c| + def authenticated_client + @authenticated_client ||= Faraday.new(url: @manage_ghes_endpoint) do |c| c.headers[:user_agent] = user_agent c.request :json c.response :json + c.adapter Faraday.default_adapter if root_site_admin_assumed? - c.basic_auth('api_key', @manage_ghes_password) + username = "api_key" elsif basic_authenticated? - c.basic_auth(@manage_ghes_username, @manage_ghes_password) + username = @manage_ghes_username end + c.request :authorization, :basic, username, @manage_ghes_password + # Disabling SSL is essential for certain self-hosted Enterprise instances if connection_options[:ssl] && !connection_options[:ssl][:verify] @@ -53,7 +60,6 @@ def faraday_configuration end c.use Octokit::Response::RaiseError - c.adapter Faraday.default_adapter end end From 41ace394528f434503d03dbb7f22721652f2f4af Mon Sep 17 00:00:00 2001 From: Manuel Bergler Date: Fri, 24 May 2024 13:39:56 -0600 Subject: [PATCH 08/19] Fix assuming root site admin --- lib/octokit/manage_ghes_client/manage_ghes.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/octokit/manage_ghes_client/manage_ghes.rb b/lib/octokit/manage_ghes_client/manage_ghes.rb index 71286d545..6beda4a91 100644 --- a/lib/octokit/manage_ghes_client/manage_ghes.rb +++ b/lib/octokit/manage_ghes_client/manage_ghes.rb @@ -35,8 +35,9 @@ def basic_authenticated? !!(@manage_ghes_username && @manage_ghes_password) end + # If no username is provided, we assume root site admin should be used def root_site_admin_assumed? - !!(@manage_ghes_username) + !(@manage_ghes_username) end def authenticated_client From 43f6845fadd13311e5a27a1cd4c05a7ae2aec176 Mon Sep 17 00:00:00 2001 From: alejndr0 Date: Mon, 27 May 2024 12:25:31 +0200 Subject: [PATCH 09/19] Add spec files for manage_ghes_client --- README.md | 3 + lib/octokit/manage_ghes_client/manage_ghes.rb | 16 ++--- .../get_maintenance_mode.json | 69 ++++++++++++++++++ .../disable_maintenance_mode.json | 72 +++++++++++++++++++ .../enable_maintenance_mode.json | 72 +++++++++++++++++++ spec/octokit/client_spec.rb | 6 ++ .../ghes_manage_client/ghes_manage_spec.rb | 31 ++++++++ spec/octokit/ghes_manage_spec.rb | 10 +++ spec/spec_helper.rb | 41 +++++++++++ 9 files changed, 310 insertions(+), 10 deletions(-) create mode 100644 spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_maintenance_mode/get_maintenance_mode.json create mode 100644 spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_set_maintenance_mode/disable_maintenance_mode.json create mode 100644 spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_set_maintenance_mode/enable_maintenance_mode.json create mode 100644 spec/octokit/ghes_manage_client/ghes_manage_spec.rb create mode 100644 spec/octokit/ghes_manage_spec.rb diff --git a/README.md b/README.md index c900cbbf2..4cf4f3cf4 100644 --- a/README.md +++ b/README.md @@ -709,6 +709,9 @@ Octokit: | `OCTOKIT_TEST_GITHUB_ENTERPRISE_MANAGEMENT_CONSOLE_PASSWORD` | GitHub Enterprise management console password. | | `OCTOKIT_TEST_GITHUB_ENTERPRISE_ENDPOINT` | GitHub Enterprise hostname. | | `OCTOKIT_TEST_GITHUB_ENTERPRISE_MANAGEMENT_CONSOLE_ENDPOINT` | GitHub Enterprise Management Console endpoint. | +| `OCTOKIT_TEST_GITHUB_MANAGE_GHES_ENDPOINT` | GitHub Enterprise Server GHES Manage Endpoint. | +| `OCTOKIT_TEST_GITHUB_MANAGE_GHES_USERNAME` | GitHub Enterprise Server GHES Manage Username. | +| `OCTOKIT_TEST_GITHUB_MANAGE_GHES_PASSWORD` | GitHub Enterprise Server GHES Manage Password. | | `OCTOKIT_TEST_GITHUB_INTEGRATION` | [GitHub Integration](https://developer.github.com/early-access/integrations/) owned by your test organization. | | `OCTOKIT_TEST_GITHUB_INTEGRATION_INSTALLATION` | Installation of the GitHub Integration specified above. | | `OCTOKIT_TEST_INTEGRATION_PEM_KEY` | File path to the private key generated from your integration. | diff --git a/lib/octokit/manage_ghes_client/manage_ghes.rb b/lib/octokit/manage_ghes_client/manage_ghes.rb index 6beda4a91..9d815ada7 100644 --- a/lib/octokit/manage_ghes_client/manage_ghes.rb +++ b/lib/octokit/manage_ghes_client/manage_ghes.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true module Octokit + # Client for the Manage GitHub Enterprise Server API class ManageGHESClient # Methods for the Manage GitHub Enterprise Server API # @@ -9,12 +10,11 @@ module ManageAPI # Get information about the maintenance status of the GHES instance # # @return [Sawyer::Resource] The maintenance mode status - def get_maintenance_mode + def maintenance_mode conn = authenticated_client @last_response = conn.get('/manage/v1/maintenance') end - alias maintenance_mode get_maintenance_mode # Configure the maintenance mode of the GHES instance # @@ -28,7 +28,7 @@ def set_maintenance_mode(enabled, options = {}) end alias configure_maintenance_mode set_maintenance_mode end - + private def basic_authenticated? @@ -37,7 +37,7 @@ def basic_authenticated? # If no username is provided, we assume root site admin should be used def root_site_admin_assumed? - !(@manage_ghes_username) + !@manage_ghes_username end def authenticated_client @@ -48,21 +48,17 @@ def authenticated_client c.adapter Faraday.default_adapter if root_site_admin_assumed? - username = "api_key" + username = 'api_key' elsif basic_authenticated? username = @manage_ghes_username end c.request :authorization, :basic, username, @manage_ghes_password - # Disabling SSL is essential for certain self-hosted Enterprise instances - if connection_options[:ssl] && !connection_options[:ssl][:verify] - c.ssl[:verify] = false - end + c.ssl[:verify] = false if connection_options[:ssl] && !connection_options[:ssl][:verify] c.use Octokit::Response::RaiseError end end - end end diff --git a/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_maintenance_mode/get_maintenance_mode.json b/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_maintenance_mode/get_maintenance_mode.json new file mode 100644 index 000000000..adee1e996 --- /dev/null +++ b/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_maintenance_mode/get_maintenance_mode.json @@ -0,0 +1,69 @@ +{ + "http_interactions": [ + { + "request": { + "method": "get", + "uri": "<>/manage/v1/maintenance", + "body": { + "encoding": "US-ASCII", + "base64_string": "" + }, + "headers": { + "User-Agent": [ + "Octokit Ruby Gem 8.1.0" + ], + "Authorization": [ + "Basic YXBpX2tleTpRMjBVcm45aWs=" + ], + "Accept-Encoding": [ + "gzip;q=1.0,deflate;q=0.6,identity;q=0.3" + ], + "Accept": [ + "*/*" + ] + } + }, + "response": { + "status": { + "code": 200, + "message": "OK" + }, + "headers": { + "Content-Security-Policy": [ + "default-src 'none';" + ], + "Content-Type": [ + "application/json; charset=utf-8" + ], + "Server": [ + "GHES Manage" + ], + "Strict-Transport-Security": [ + "max-age=63072000; includeSubDomains; preload" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "DENY" + ], + "X-Xss-Protection": [ + "0" + ], + "Date": [ + "Mon, 27 May 2024 10:23:40 GMT" + ], + "Content-Length": [ + "313" + ] + }, + "body": { + "encoding": "UTF-8", + "base64_string": "W3siaG9zdG5hbWUiOiJhbGVqbmRyMC0wNWUwODQxYjIwNzY3MjcyNy5naGUt\ndGVzdC5jb20iLCJ1dWlkIjoiYzYyYzgyOTItMWMwOS0xMWVmLWEzZTMtMDYy\nYWMwZTlkZGIxIiwic3RhdHVzIjoib24iLCJjb25uZWN0aW9uX3NlcnZpY2Vz\nIjpbeyJuYW1lIjoiZ2l0IG9wZXJhdGlvbnMiLCJudW1iZXIiOjB9LHsibmFt\nZSI6Im15c3FsIHF1ZXJpZXMiLCJudW1iZXIiOjB9LHsibmFtZSI6InJlc3F1\nZSBqb2JzIiwibnVtYmVyIjowfSx7Im5hbWUiOiJhcXVlZHVjdCBqb2JzIiwi\nbnVtYmVyIjowfV0sImNhbl91bnNldF9tYWludGVuYW5jZSI6dHJ1ZX1dCg==\n" + } + }, + "recorded_at": "Mon, 27 May 2024 10:23:41 GMT" + } + ], + "recorded_with": "VCR 6.2.0" +} \ No newline at end of file diff --git a/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_set_maintenance_mode/disable_maintenance_mode.json b/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_set_maintenance_mode/disable_maintenance_mode.json new file mode 100644 index 000000000..060f1d45f --- /dev/null +++ b/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_set_maintenance_mode/disable_maintenance_mode.json @@ -0,0 +1,72 @@ +{ + "http_interactions": [ + { + "request": { + "method": "post", + "uri": "<>/manage/v1/maintenance", + "body": { + "encoding": "UTF-8", + "base64_string": "eyJlbmFibGVkIjpmYWxzZX0=\n" + }, + "headers": { + "User-Agent": [ + "Octokit Ruby Gem 8.1.0" + ], + "Content-Type": [ + "application/json" + ], + "Authorization": [ + "Basic YXBpX2tleTpRMjBVcm45aWs=" + ], + "Accept-Encoding": [ + "gzip;q=1.0,deflate;q=0.6,identity;q=0.3" + ], + "Accept": [ + "*/*" + ] + } + }, + "response": { + "status": { + "code": 200, + "message": "OK" + }, + "headers": { + "Content-Security-Policy": [ + "default-src 'none';" + ], + "Content-Type": [ + "application/json; charset=utf-8" + ], + "Server": [ + "GHES Manage" + ], + "Strict-Transport-Security": [ + "max-age=63072000; includeSubDomains; preload" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "DENY" + ], + "X-Xss-Protection": [ + "0" + ], + "Date": [ + "Mon, 27 May 2024 10:23:32 GMT" + ], + "Content-Length": [ + "141" + ] + }, + "body": { + "encoding": "UTF-8", + "base64_string": "W3siaG9zdG5hbWUiOiJhbGVqbmRyMC0wNWUwODQxYjIwNzY3MjcyNy5naGUt\ndGVzdC5jb20iLCJ1dWlkIjoiYzYyYzgyOTItMWMwOS0xMWVmLWEzZTMtMDYy\nYWMwZTlkZGIxIiwibWVzc2FnZSI6Im1haW50ZW5hbmNlIG1vZGUgZGlzYWJs\nZWQifV0K\n" + } + }, + "recorded_at": "Mon, 27 May 2024 10:23:32 GMT" + } + ], + "recorded_with": "VCR 6.2.0" +} \ No newline at end of file diff --git a/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_set_maintenance_mode/enable_maintenance_mode.json b/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_set_maintenance_mode/enable_maintenance_mode.json new file mode 100644 index 000000000..1e4778dc3 --- /dev/null +++ b/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_set_maintenance_mode/enable_maintenance_mode.json @@ -0,0 +1,72 @@ +{ + "http_interactions": [ + { + "request": { + "method": "post", + "uri": "<>/manage/v1/maintenance", + "body": { + "encoding": "UTF-8", + "base64_string": "eyJlbmFibGVkIjp0cnVlfQ==\n" + }, + "headers": { + "User-Agent": [ + "Octokit Ruby Gem 8.1.0" + ], + "Content-Type": [ + "application/json" + ], + "Authorization": [ + "Basic YXBpX2tleTpRMjBVcm45aWs=" + ], + "Accept-Encoding": [ + "gzip;q=1.0,deflate;q=0.6,identity;q=0.3" + ], + "Accept": [ + "*/*" + ] + } + }, + "response": { + "status": { + "code": 200, + "message": "OK" + }, + "headers": { + "Content-Security-Policy": [ + "default-src 'none';" + ], + "Content-Type": [ + "application/json; charset=utf-8" + ], + "Server": [ + "GHES Manage" + ], + "Strict-Transport-Security": [ + "max-age=63072000; includeSubDomains; preload" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "DENY" + ], + "X-Xss-Protection": [ + "0" + ], + "Date": [ + "Mon, 27 May 2024 10:23:37 GMT" + ], + "Content-Length": [ + "140" + ] + }, + "body": { + "encoding": "UTF-8", + "base64_string": "W3siaG9zdG5hbWUiOiJhbGVqbmRyMC0wNWUwODQxYjIwNzY3MjcyNy5naGUt\ndGVzdC5jb20iLCJ1dWlkIjoiYzYyYzgyOTItMWMwOS0xMWVmLWEzZTMtMDYy\nYWMwZTlkZGIxIiwibWVzc2FnZSI6Im1haW50ZW5hbmNlIG1vZGUgZW5hYmxl\nZCJ9XQo=\n" + } + }, + "recorded_at": "Mon, 27 May 2024 10:23:37 GMT" + } + ], + "recorded_with": "VCR 6.2.0" +} \ No newline at end of file diff --git a/spec/octokit/client_spec.rb b/spec/octokit/client_spec.rb index 67e4fddb6..0ed906058 100644 --- a/spec/octokit/client_spec.rb +++ b/spec/octokit/client_spec.rb @@ -1219,20 +1219,26 @@ Octokit.reset! @client = oauth_client @ent_management_console = enterprise_management_console_client + @ent_manage_ghes_client = manage_ghes_client end it 'has no method collisions' do client_methods = collect_methods(Octokit::Client) admin_client = collect_methods(Octokit::EnterpriseAdminClient) console_client = collect_methods(Octokit::EnterpriseManagementConsoleClient) + manage_ghes_client = collect_methods(Octokit::ManageGHESClient) expect(client_methods & admin_client).to eql [] expect(client_methods & console_client).to eql [] + expect(client_methods & manage_ghes_client).to eql [] expect(admin_client & console_client).to eql [] + expect(admin_client & manage_ghes_client).to eql [] + expect(console_client & manage_ghes_client).to eql [] end it 'uniquely separates method missing calls' do expect { @ent_management_console.public_events }.to raise_error NoMethodError + expect { @ent_manage_ghes_client.public_events }.to raise_error NoMethodError end def collect_methods(clazz) diff --git a/spec/octokit/ghes_manage_client/ghes_manage_spec.rb b/spec/octokit/ghes_manage_client/ghes_manage_spec.rb new file mode 100644 index 000000000..3d38baf0e --- /dev/null +++ b/spec/octokit/ghes_manage_client/ghes_manage_spec.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +describe Octokit::ManageGHESClient::ManageAPI do + before do + Octokit.reset! + @manage_ghes = manage_ghes_client + end + + describe '.maintenance_mode', :vcr do + it 'get maintenance mode' do + @manage_ghes.maintenance_mode + expect(@manage_ghes.last_response.status).to eq(200) + assert_requested :get, github_manage_ghes_url('/manage/v1/maintenance') + end + end # .maintenance_mode + + describe '.set_maintenance_mode', :vcr do + it 'enable maintenance mode' do + @manage_ghes.set_maintenance_mode(true) + expect(@manage_ghes.last_response.status).to eq(200) + expect(@manage_ghes.last_response.body[0]['message']).to eq('maintenance mode enabled') + assert_requested :post, github_manage_ghes_url('/manage/v1/maintenance') + end + it 'disable maintenance mode' do + @manage_ghes.set_maintenance_mode(false) + expect(@manage_ghes.last_response.status).to eq(200) + expect(@manage_ghes.last_response.body[0]['message']).to eq('maintenance mode disabled') + assert_requested :post, github_manage_ghes_url('/manage/v1/maintenance') + end + end # .set_maintenance_mode +end diff --git a/spec/octokit/ghes_manage_spec.rb b/spec/octokit/ghes_manage_spec.rb new file mode 100644 index 000000000..c30caf8ad --- /dev/null +++ b/spec/octokit/ghes_manage_spec.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +describe Octokit::ManageGHESClient do + describe 'module configuration' do + it 'inherits Octokit::Client' do + manage_ghes = Octokit::ManageGHESClient.new + expect manage_ghes.is_a? Octokit::Client + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index ba3be28fe..477f62759 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -73,6 +73,12 @@ c.filter_sensitive_data('<>') do test_github_enterprise_management_console_endpoint end + c.filter_sensitive_data('<>') do + test_github_manage_ghes_endpoint + end + c.filter_sensitive_data('<>') do + test_github_manage_ghes_password + end c.filter_sensitive_data('<>') do test_github_enterprise_endpoint end @@ -208,6 +214,18 @@ def test_github_enterprise_endpoint ENV.fetch 'OCTOKIT_TEST_GITHUB_ENTERPRISE_ENDPOINT', 'http://enterprise.github.dev/api/v3/' end +def test_github_manage_ghes_endpoint + ENV.fetch 'OCTOKIT_TEST_GITHUB_MANAGE_GHES_ENDPOINT', 'http://enterprise.github.dev:8443' +end + +def test_github_manage_ghes_username + ENV.fetch 'OCTOKIT_TEST_GITHUB_MANAGE_GHES_USERNAME', 'api_key' +end + +def test_github_manage_ghes_password + ENV.fetch 'OCTOKIT_TEST_GITHUB_MANAGE_GHES_PASSWORD', 'passworD1' +end + def test_github_repository ENV.fetch 'OCTOKIT_TEST_GITHUB_REPOSITORY', 'api-sandbox' end @@ -295,6 +313,10 @@ def github_management_console_url(url) test_github_enterprise_management_console_endpoint + url end +def github_manage_ghes_url(url) + test_github_manage_ghes_endpoint + url +end + def basic_auth_client(login: test_github_login, password: test_github_password) Octokit::Client.new(login: login, password: password) end @@ -339,6 +361,25 @@ def enterprise_management_console_client client end +def manage_ghes_client + stack = Faraday::RackBuilder.new do |builder| + builder.request :multipart + builder.request :url_encoded + builder.adapter Faraday.default_adapter + end + + client = Octokit::ManageGHESClient.new \ + manage_ghes_endpoint: test_github_manage_ghes_endpoint, + manage_ghes_username: test_github_manage_ghes_username, + manage_ghes_password: test_github_manage_ghes_password, + connection_options: { ssl: { verify: false } } + + client.configure do |c| + c.middleware = stack + end + client +end + def new_jwt_token private_pem = File.read(test_github_integration_pem_key) private_key = OpenSSL::PKey::RSA.new(private_pem) From 521070b83d946e4cfacff84746e1bde92e2c60e7 Mon Sep 17 00:00:00 2001 From: alejndr0 Date: Tue, 28 May 2024 13:54:16 +0200 Subject: [PATCH 10/19] Add rest of endpoints and tests --- lib/octokit/manage_ghes_client/manage_ghes.rb | 107 ++++++++++++++++++ ..._authorized_SSH_keys_via_a_file_path_.json | 72 ++++++++++++ .../_authorized_keys/get_authorized_keys.json | 69 +++++++++++ .../get_ghe-config-apply_status.json | 69 +++++++++++ .../_edit_settings/set_settings.json | 69 +++++++++++ .../get_maintenance_mode.json | 8 +- ...n_authorized_SSH_key_via_a_file_path_.json | 72 ++++++++++++ .../disable_maintenance_mode.json | 4 +- .../enable_maintenance_mode.json | 4 +- .../_settings/get_settings.json | 69 +++++++++++ .../start_a_ghe-config-apply.json | 72 ++++++++++++ .../_upload_license/upload_a_new_license.json | 75 ++++++++++++ .../ghes_manage_client/ghes_manage_spec.rb | 86 +++++++++++++- 13 files changed, 766 insertions(+), 10 deletions(-) create mode 100644 spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_add_authorized_key/adds_a_new_authorized_SSH_keys_via_a_file_path_.json create mode 100644 spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_authorized_keys/get_authorized_keys.json create mode 100644 spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_config_status/get_ghe-config-apply_status.json create mode 100644 spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_edit_settings/set_settings.json create mode 100644 spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_remove_authorized_key/delete_an_authorized_SSH_key_via_a_file_path_.json create mode 100644 spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_settings/get_settings.json create mode 100644 spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_start_configuration/start_a_ghe-config-apply.json create mode 100644 spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_upload_license/upload_a_new_license.json diff --git a/lib/octokit/manage_ghes_client/manage_ghes.rb b/lib/octokit/manage_ghes_client/manage_ghes.rb index 9d815ada7..4a78437c9 100644 --- a/lib/octokit/manage_ghes_client/manage_ghes.rb +++ b/lib/octokit/manage_ghes_client/manage_ghes.rb @@ -29,6 +29,113 @@ def set_maintenance_mode(enabled, options = {}) alias configure_maintenance_mode set_maintenance_mode end + # Uploads a license for the first time + # + # @param license [String] The path to your .ghl license file. + # + # @see https://docs.github.com/en/enterprise-server@3.4/rest/enterprise-admin/management-console#create-a-github-license + # @return nil + def upload_license(license) + conn = authenticated_client + conn.request :multipart + params = {} + params[:license] = Faraday::FilePart.new(license, 'binary') + @last_response = conn.put('/manage/v1/config/license', params, { 'Content-Type' => 'multipart/form-data' }) + end + + # Start a configuration process. + # + # @return nil + def start_configuration + conn = authenticated_client + @last_response = conn.post('/manage/v1/config/apply') + end + + # Get information about the Enterprise installation + # + # @return [Sawyer::Resource] The installation information + def config_status + conn = authenticated_client + @last_response = conn.get('/manage/v1/config/apply') + end + alias config_check config_status + + # Get information about the Enterprise installation + # + # @return [Sawyer::Resource] The settings + def settings + conn = authenticated_client + @last_response = conn.get('/manage/v1/config/settings') + end + alias get_settings settings + + # Modify the Enterprise settings + # + # @param settings [Hash] A hash configuration of the new settings + # + # @return [nil] + def edit_settings(settings) + conn = authenticated_client + @last_response = conn.put('/manage/v1/config/settings', settings.to_json.to_s) + end + + def authorized_keys + conn = authenticated_client + @last_response = conn.get('/manage/v1/access/ssh') + end + alias get_authorized_keys authorized_keys + + # Add an authorized SSH keys on the Enterprise install + # + # @param key Either the file path to a key, a File handler to the key, or the contents of the key itself + # @return [Sawyer::Resource] An array of authorized SSH keys + def add_authorized_key(key) + conn = authenticated_client + case key + when String + if File.exist?(key) + key = File.open(key, 'r') + content = key.read.strip + key.close + else + content = key + end + when File + content = key.read.strip + key.close + end + + queries = {} + queries[:key] = content + @last_response = conn.post('/manage/v1/access/ssh', queries) + end + + # Removes an authorized SSH keys from the Enterprise install + # + # @param key Either the file path to a key, a File handler to the key, or the contents of the key itself + # @return [Sawyer::Resource] An array of authorized SSH keys + def remove_authorized_key(key) + conn = authenticated_client + case key + when String + if File.exist?(key) + key = File.open(key, 'r') + content = key.read.strip + key.close + else + content = key + end + when File + content = key.read.strip + key.close + end + + queries = {} + queries[:key] = content + @last_response = conn.run_request(:delete, '/manage/v1/access/ssh', queries, nil) + end + alias delete_authorized_key remove_authorized_key + private def basic_authenticated? diff --git a/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_add_authorized_key/adds_a_new_authorized_SSH_keys_via_a_file_path_.json b/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_add_authorized_key/adds_a_new_authorized_SSH_keys_via_a_file_path_.json new file mode 100644 index 000000000..365f641c9 --- /dev/null +++ b/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_add_authorized_key/adds_a_new_authorized_SSH_keys_via_a_file_path_.json @@ -0,0 +1,72 @@ +{ + "http_interactions": [ + { + "request": { + "method": "post", + "uri": "<>/manage/v1/access/ssh", + "body": { + "encoding": "UTF-8", + "base64_string": "eyJrZXkiOiJzc2gtcnNhIEFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQSJ9" + }, + "headers": { + "User-Agent": [ + "Octokit Ruby Gem 8.1.0" + ], + "Content-Type": [ + "application/json" + ], + "Authorization": [ + "Basic YXBpX2tleTpRMjBVcm45aWs=" + ], + "Accept-Encoding": [ + "gzip;q=1.0,deflate;q=0.6,identity;q=0.3" + ], + "Accept": [ + "*/*" + ] + } + }, + "response": { + "status": { + "code": 200, + "message": "OK" + }, + "headers": { + "Content-Security-Policy": [ + "default-src 'none';" + ], + "Content-Type": [ + "application/json; charset=utf-8" + ], + "Server": [ + "GHES Manage" + ], + "Strict-Transport-Security": [ + "max-age=63072000; includeSubDomains; preload" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "DENY" + ], + "X-Xss-Protection": [ + "0" + ], + "Date": [ + "Tue, 28 May 2024 11:07:14 GMT" + ], + "Content-Length": [ + "158" + ] + }, + "body": { + "encoding": "UTF-8", + "base64_string": "W3siaG9zdG5hbWUiOiJhbGVqbmRyMC0wNWUwODQxYjIwNzY3MjcyNy5naGUt\ndGVzdC5jb20iLCJ1dWlkIjoiYzYyYzgyOTItMWMwOS0xMWVmLWEzZTMtMDYy\nYWMwZTlkZGIxIiwibWVzc2FnZSI6IlNTSCBrZXkgYWRkZWQgc3VjY2Vzc2Z1\nbGx5IiwibW9kaWZpZWQiOnRydWV9XQo=\n" + } + }, + "recorded_at": "Tue, 28 May 2024 11:07:14 GMT" + } + ], + "recorded_with": "VCR 6.2.0" +} \ No newline at end of file diff --git a/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_authorized_keys/get_authorized_keys.json b/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_authorized_keys/get_authorized_keys.json new file mode 100644 index 000000000..2bf744639 --- /dev/null +++ b/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_authorized_keys/get_authorized_keys.json @@ -0,0 +1,69 @@ +{ + "http_interactions": [ + { + "request": { + "method": "get", + "uri": "<>/manage/v1/access/ssh", + "body": { + "encoding": "US-ASCII", + "base64_string": "" + }, + "headers": { + "User-Agent": [ + "Octokit Ruby Gem 8.1.0" + ], + "Authorization": [ + "Basic YXBpX2tleTpRMjBVcm45aWs=" + ], + "Accept-Encoding": [ + "gzip;q=1.0,deflate;q=0.6,identity;q=0.3" + ], + "Accept": [ + "*/*" + ] + } + }, + "response": { + "status": { + "code": 200, + "message": "OK" + }, + "headers": { + "Content-Security-Policy": [ + "default-src 'none';" + ], + "Content-Type": [ + "application/json; charset=utf-8" + ], + "Server": [ + "GHES Manage" + ], + "Strict-Transport-Security": [ + "max-age=63072000; includeSubDomains; preload" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "DENY" + ], + "X-Xss-Protection": [ + "0" + ], + "Date": [ + "Tue, 28 May 2024 11:24:12 GMT" + ], + "Transfer-Encoding": [ + "chunked" + ] + }, + "body": { + "encoding": "UTF-8", + "base64_string": "WwogICAgewogICAgICAgICJrZXkiOiAic3NoLXJzYSBBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUEiLAogICAgICAgICJmaW5nZXJwcmludCI6ICIxMjo2MzowNTo0ZjphNzoyNTpmYTo2ODoxMjo5YTozYjowNzo1ZDo3NzoxMzoxMiIKICAgIH0KXQ==" + } + }, + "recorded_at": "Tue, 28 May 2024 11:24:12 GMT" + } + ], + "recorded_with": "VCR 6.2.0" +} \ No newline at end of file diff --git a/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_config_status/get_ghe-config-apply_status.json b/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_config_status/get_ghe-config-apply_status.json new file mode 100644 index 000000000..4e915341c --- /dev/null +++ b/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_config_status/get_ghe-config-apply_status.json @@ -0,0 +1,69 @@ +{ + "http_interactions": [ + { + "request": { + "method": "get", + "uri": "<>/manage/v1/config/apply", + "body": { + "encoding": "US-ASCII", + "base64_string": "" + }, + "headers": { + "User-Agent": [ + "Octokit Ruby Gem 8.1.0" + ], + "Authorization": [ + "Basic YXBpX2tleTpRMjBVcm45aWs=" + ], + "Accept-Encoding": [ + "gzip;q=1.0,deflate;q=0.6,identity;q=0.3" + ], + "Accept": [ + "*/*" + ] + } + }, + "response": { + "status": { + "code": 200, + "message": "OK" + }, + "headers": { + "Content-Security-Policy": [ + "default-src 'none';" + ], + "Content-Type": [ + "application/json; charset=utf-8" + ], + "Server": [ + "GHES Manage" + ], + "Strict-Transport-Security": [ + "max-age=63072000; includeSubDomains; preload" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "DENY" + ], + "X-Xss-Protection": [ + "0" + ], + "Date": [ + "Tue, 28 May 2024 10:39:59 GMT" + ], + "Content-Length": [ + "175" + ] + }, + "body": { + "encoding": "UTF-8", + "base64_string": "eyJydW5faWQiOiI5ODI0ZjE2ZSIsInJ1bm5pbmciOmZhbHNlLCJzdWNjZXNz\nZnVsIjp0cnVlLCJub2RlcyI6W3sicnVuX2lkIjoiOTgyNGYxNmUiLCJob3N0\nbmFtZSI6ImFsZWpuZHIwLTA1ZTA4NDFiMjA3NjcyNzI3LmdoZS10ZXN0LmNv\nbSIsInJ1bm5pbmciOmZhbHNlLCJzdWNjZXNzZnVsIjp0cnVlfV19Cg==\n" + } + }, + "recorded_at": "Tue, 28 May 2024 10:39:59 GMT" + } + ], + "recorded_with": "VCR 6.2.0" +} \ No newline at end of file diff --git a/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_edit_settings/set_settings.json b/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_edit_settings/set_settings.json new file mode 100644 index 000000000..7d2735433 --- /dev/null +++ b/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_edit_settings/set_settings.json @@ -0,0 +1,69 @@ +{ + "http_interactions": [ + { + "request": { + "method": "put", + "uri": "<>/manage/v1/config/settings", + "body": { + "encoding": "UTF-8", + "base64_string": "eyJhYnVzZV9yYXRlX2xpbWl0aW5nIjp7InJlcXVlc3RzX3Blcl9taW51dGUi\nOjkwMX19\n" + }, + "headers": { + "User-Agent": [ + "Octokit Ruby Gem 8.1.0" + ], + "Content-Type": [ + "application/json" + ], + "Authorization": [ + "Basic YXBpX2tleTpRMjBVcm45aWs=" + ], + "Accept-Encoding": [ + "gzip;q=1.0,deflate;q=0.6,identity;q=0.3" + ], + "Accept": [ + "*/*" + ] + } + }, + "response": { + "status": { + "code": 204, + "message": "No Content" + }, + "headers": { + "Content-Security-Policy": [ + "default-src 'none';" + ], + "Content-Type": [ + "application/json; charset=utf-8" + ], + "Server": [ + "GHES Manage" + ], + "Strict-Transport-Security": [ + "max-age=63072000; includeSubDomains; preload" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "DENY" + ], + "X-Xss-Protection": [ + "0" + ], + "Date": [ + "Tue, 28 May 2024 10:57:15 GMT" + ] + }, + "body": { + "encoding": "UTF-8", + "base64_string": "" + } + }, + "recorded_at": "Tue, 28 May 2024 10:57:16 GMT" + } + ], + "recorded_with": "VCR 6.2.0" +} \ No newline at end of file diff --git a/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_maintenance_mode/get_maintenance_mode.json b/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_maintenance_mode/get_maintenance_mode.json index adee1e996..800453c18 100644 --- a/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_maintenance_mode/get_maintenance_mode.json +++ b/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_maintenance_mode/get_maintenance_mode.json @@ -51,18 +51,18 @@ "0" ], "Date": [ - "Mon, 27 May 2024 10:23:40 GMT" + "Tue, 28 May 2024 10:16:56 GMT" ], "Content-Length": [ - "313" + "314" ] }, "body": { "encoding": "UTF-8", - "base64_string": "W3siaG9zdG5hbWUiOiJhbGVqbmRyMC0wNWUwODQxYjIwNzY3MjcyNy5naGUt\ndGVzdC5jb20iLCJ1dWlkIjoiYzYyYzgyOTItMWMwOS0xMWVmLWEzZTMtMDYy\nYWMwZTlkZGIxIiwic3RhdHVzIjoib24iLCJjb25uZWN0aW9uX3NlcnZpY2Vz\nIjpbeyJuYW1lIjoiZ2l0IG9wZXJhdGlvbnMiLCJudW1iZXIiOjB9LHsibmFt\nZSI6Im15c3FsIHF1ZXJpZXMiLCJudW1iZXIiOjB9LHsibmFtZSI6InJlc3F1\nZSBqb2JzIiwibnVtYmVyIjowfSx7Im5hbWUiOiJhcXVlZHVjdCBqb2JzIiwi\nbnVtYmVyIjowfV0sImNhbl91bnNldF9tYWludGVuYW5jZSI6dHJ1ZX1dCg==\n" + "base64_string": "W3siaG9zdG5hbWUiOiJhbGVqbmRyMC0wNWUwODQxYjIwNzY3MjcyNy5naGUt\ndGVzdC5jb20iLCJ1dWlkIjoiYzYyYzgyOTItMWMwOS0xMWVmLWEzZTMtMDYy\nYWMwZTlkZGIxIiwic3RhdHVzIjoib2ZmIiwiY29ubmVjdGlvbl9zZXJ2aWNl\ncyI6W3sibmFtZSI6ImdpdCBvcGVyYXRpb25zIiwibnVtYmVyIjowfSx7Im5h\nbWUiOiJteXNxbCBxdWVyaWVzIiwibnVtYmVyIjowfSx7Im5hbWUiOiJyZXNx\ndWUgam9icyIsIm51bWJlciI6MH0seyJuYW1lIjoiYXF1ZWR1Y3Qgam9icyIs\nIm51bWJlciI6MH1dLCJjYW5fdW5zZXRfbWFpbnRlbmFuY2UiOnRydWV9XQo=\n" } }, - "recorded_at": "Mon, 27 May 2024 10:23:41 GMT" + "recorded_at": "Tue, 28 May 2024 10:16:56 GMT" } ], "recorded_with": "VCR 6.2.0" diff --git a/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_remove_authorized_key/delete_an_authorized_SSH_key_via_a_file_path_.json b/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_remove_authorized_key/delete_an_authorized_SSH_key_via_a_file_path_.json new file mode 100644 index 000000000..e7e36c452 --- /dev/null +++ b/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_remove_authorized_key/delete_an_authorized_SSH_key_via_a_file_path_.json @@ -0,0 +1,72 @@ +{ + "http_interactions": [ + { + "request": { + "method": "delete", + "uri": "<>/manage/v1/access/ssh", + "body": { + "encoding": "UTF-8", + "base64_string": "eyJrZXkiOiJzc2gtcnNhIEFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQSJ9" + }, + "headers": { + "User-Agent": [ + "Octokit Ruby Gem 8.1.0" + ], + "Content-Type": [ + "application/json" + ], + "Authorization": [ + "Basic YXBpX2tleTpRMjBVcm45aWs=" + ], + "Accept-Encoding": [ + "gzip;q=1.0,deflate;q=0.6,identity;q=0.3" + ], + "Accept": [ + "*/*" + ] + } + }, + "response": { + "status": { + "code": 200, + "message": "OK" + }, + "headers": { + "Content-Security-Policy": [ + "default-src 'none';" + ], + "Content-Type": [ + "application/json; charset=utf-8" + ], + "Server": [ + "GHES Manage" + ], + "Strict-Transport-Security": [ + "max-age=63072000; includeSubDomains; preload" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "DENY" + ], + "X-Xss-Protection": [ + "0" + ], + "Date": [ + "Tue, 28 May 2024 11:40:00 GMT" + ], + "Content-Length": [ + "144" + ] + }, + "body": { + "encoding": "UTF-8", + "base64_string": "W3siaG9zdG5hbWUiOiJhbGVqbmRyMC0wNWUwODQxYjIwNzY3MjcyNy5naGUt\ndGVzdC5jb20iLCJ1dWlkIjoiYzYyYzgyOTItMWMwOS0xMWVmLWEzZTMtMDYy\nYWMwZTlkZGIxIiwibWVzc2FnZSI6IlNTSCBrZXkgcmVtb3ZlZCBzdWNjZXNz\nZnVsbHkifV0K\n" + } + }, + "recorded_at": "Tue, 28 May 2024 11:40:00 GMT" + } + ], + "recorded_with": "VCR 6.2.0" +} \ No newline at end of file diff --git a/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_set_maintenance_mode/disable_maintenance_mode.json b/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_set_maintenance_mode/disable_maintenance_mode.json index 060f1d45f..81c9b79ca 100644 --- a/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_set_maintenance_mode/disable_maintenance_mode.json +++ b/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_set_maintenance_mode/disable_maintenance_mode.json @@ -54,7 +54,7 @@ "0" ], "Date": [ - "Mon, 27 May 2024 10:23:32 GMT" + "Tue, 28 May 2024 10:16:52 GMT" ], "Content-Length": [ "141" @@ -65,7 +65,7 @@ "base64_string": "W3siaG9zdG5hbWUiOiJhbGVqbmRyMC0wNWUwODQxYjIwNzY3MjcyNy5naGUt\ndGVzdC5jb20iLCJ1dWlkIjoiYzYyYzgyOTItMWMwOS0xMWVmLWEzZTMtMDYy\nYWMwZTlkZGIxIiwibWVzc2FnZSI6Im1haW50ZW5hbmNlIG1vZGUgZGlzYWJs\nZWQifV0K\n" } }, - "recorded_at": "Mon, 27 May 2024 10:23:32 GMT" + "recorded_at": "Tue, 28 May 2024 10:16:52 GMT" } ], "recorded_with": "VCR 6.2.0" diff --git a/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_set_maintenance_mode/enable_maintenance_mode.json b/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_set_maintenance_mode/enable_maintenance_mode.json index 1e4778dc3..f1e6486ae 100644 --- a/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_set_maintenance_mode/enable_maintenance_mode.json +++ b/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_set_maintenance_mode/enable_maintenance_mode.json @@ -54,7 +54,7 @@ "0" ], "Date": [ - "Mon, 27 May 2024 10:23:37 GMT" + "Tue, 28 May 2024 10:16:43 GMT" ], "Content-Length": [ "140" @@ -65,7 +65,7 @@ "base64_string": "W3siaG9zdG5hbWUiOiJhbGVqbmRyMC0wNWUwODQxYjIwNzY3MjcyNy5naGUt\ndGVzdC5jb20iLCJ1dWlkIjoiYzYyYzgyOTItMWMwOS0xMWVmLWEzZTMtMDYy\nYWMwZTlkZGIxIiwibWVzc2FnZSI6Im1haW50ZW5hbmNlIG1vZGUgZW5hYmxl\nZCJ9XQo=\n" } }, - "recorded_at": "Mon, 27 May 2024 10:23:37 GMT" + "recorded_at": "Tue, 28 May 2024 10:16:43 GMT" } ], "recorded_with": "VCR 6.2.0" diff --git a/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_settings/get_settings.json b/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_settings/get_settings.json new file mode 100644 index 000000000..40c67ad97 --- /dev/null +++ b/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_settings/get_settings.json @@ -0,0 +1,69 @@ +{ + "http_interactions": [ + { + "request": { + "method": "get", + "uri": "<>/manage/v1/config/settings", + "body": { + "encoding": "US-ASCII", + "base64_string": "" + }, + "headers": { + "User-Agent": [ + "Octokit Ruby Gem 8.1.0" + ], + "Authorization": [ + "Basic YXBpX2tleTpRMjBVcm45aWs=" + ], + "Accept-Encoding": [ + "gzip;q=1.0,deflate;q=0.6,identity;q=0.3" + ], + "Accept": [ + "*/*" + ] + } + }, + "response": { + "status": { + "code": 200, + "message": "OK" + }, + "headers": { + "Content-Security-Policy": [ + "default-src 'none';" + ], + "Content-Type": [ + "application/json; charset=utf-8" + ], + "Server": [ + "GHES Manage" + ], + "Strict-Transport-Security": [ + "max-age=63072000; includeSubDomains; preload" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "DENY" + ], + "X-Xss-Protection": [ + "0" + ], + "Date": [ + "Tue, 28 May 2024 10:41:27 GMT" + ], + "Transfer-Encoding": [ + "chunked" + ] + }, + "body": { + "encoding": "UTF-8", + "base64_string": "eyJhYnVzZV9yYXRlX2xpbWl0aW5nIjp7ImNwdV9taWxsaXNfcGVyX21pbnV0\nZSI6OTAwMDAsImVuYWJsZWQiOmZhbHNlLCJncmFwaHFsX2NwdV9taWxsaXNf\ncGVyX21pbnV0ZSI6NjAwMDAsInJlcXVlc3RzX3Blcl9taW51dGUiOjkwMCwi\nc2VhcmNoX2NwdV9taWxsaXNfcGVyX21pbnV0ZSI6NzUwMH0sImFkbWluX3Bh\nc3N3b3JkIjpudWxsLCJhcGlfcmF0ZV9saW1pdGluZyI6eyJkZWZhdWx0X3Jh\ndGVfbGltaXQiOjE1MDAwLCJlbmFibGVkIjpmYWxzZSwiZ3JhcGhxbF9kZWZh\ndWx0X3JhdGVfbGltaXQiOjUwMDAsImdyYXBocWxfdW5hdXRoZW50aWNhdGVk\nX3JhdGVfbGltaXQiOjAsImxmc19kZWZhdWx0X3JhdGVfbGltaXQiOjMwMDAs\nImxmc191bmF1dGhlbnRpY2F0ZWRfcmF0ZV9saW1pdCI6MTAwLCJzZWFyY2hf\nZGVmYXVsdF9yYXRlX2xpbWl0IjozMCwic2VhcmNoX3VuYXV0aGVudGljYXRl\nZF9yYXRlX2xpbWl0IjoxMCwidW5hdXRoZW50aWNhdGVkX3JhdGVfbGltaXQi\nOjYwfSwiYXBwbGljYXRpb25zIjp7ImF2YXRhcnNfbWF4X2FnZSI6MzYwMH0s\nImFzc2V0cyI6bnVsbCwiYXV0aF9tb2RlIjoiZGVmYXVsdCIsImJ1aWx0aW5f\nYXV0aF9mYWxsYmFjayI6ZmFsc2UsImNhcyI6bnVsbCwiY2hlY2tzX3JldGVu\ndGlvbiI6eyJhcmNoaXZlX3RocmVzaG9sZCI6NDAwLCJkZWxldGVfdGhyZXNo\nb2xkIjozMCwiZW5hYmxlZCI6ZmFsc2V9LCJjb2RlX3NjYW5uaW5nIjp7ImVu\nYWJsZWQiOnRydWV9LCJjb2xsZWN0ZCI6bnVsbCwiY29uZmlndXJhdGlvbl9p\nZCI6MTcxNjgwMTQ0MSwiY29uZmlndXJhdGlvbl9ydW5fY291bnQiOjEsImN1\nc3RvbWVyIjp7ImVtYWlsIjoibGVlQGdpdGh1Yi5jb20iLCJuYW1lIjoiR2l0\nSHViIiwicHVibGljX2tleV9kYXRhIjoiLS0tLS1CRUdJTiBQR1AgUFVCTElD\nIEtFWSBCTE9DSy0tLS0tXG5WZXJzaW9uOiBHbnVQRyB2MS40LjEwIChHTlUv\nTGludXgpXG5cbm1JMEVUcXpaWWdFRUFMU2U2WHlxdkxmU1EzNEhXRDZDN1Nv\nRndEazBPUEFhWmpUc2k0YTdoMjhjOGdZNEJCWWZcbk5TOWFMdjhDSXpvOHQx\nY1RXaVlFbUVabVp0VnJ1dklGM3JjWkM3UklrRXRBRkxlcXFZU2dGNE1pektT\nK3AyRXVcbi9lVEg1VXBncjVySVRlMTUyV2d3SU5MZ1ZnbVJNc01DV3JyM1Ur\ndStxY2J0TlpiS3ZZbGRhWHRCQUJFQkFBRzBcblBrZHBkRWgxWWlBb1lXWTJZ\nMkZqT0RBdFpUUmxNUzB3TVRKbExXUTRNakl0TVRJek1UTTRNR1UxTW1VNUtT\nQThcbmJHVmxRR2RwZEdoMVlpNWpiMjAraUxnRUV3RUNBQ0lGQWs2czJXSUNH\neThHQ3drSUJ3TUNCaFVJQWdrS0N3UVdcbkFnTUJBaDRCQWhlQUFBb0pFTDVZ\nY2loRmtHYUoyVzBEL2lzSlY1NmhaaUdzZUVwWmxQR2hwekJLS0tNSnBZa2dc\nblZNdkVoNm5SRElWV2doZlp5NW9BdUlVaW02WVMyeGg3VDhJbCt5cVJMTk9v\nekZrcUlvMFZvS1czNyt1cExnK0tcbkZBRmNncUxka3MzakFpYSt6bkdTTXN0\nSTFHR2hkQTF3NWt5dEV4ZTZId3FXTEN3Mlhqa3A3eTF2aGpRUThJOXhcbitH\nbUVRVkZDTjdSdWlRSWNCQkFCQWdBR0JRSk9yTm1FQUFvSkVJdmZRcDd5bjUx\nK0ttc1AvUjFTUHVwaVY0ZGVcblBvVnhibElnVzZVL0srMjZGY3RjeldIWFZ6\nWEVuTUN2dlA2VWNyZjFITll0N0x6Yk9kWDgxUFFjSnhWSUlQeFhcbnNaZ2tP\ndFpwS1NhWGxISE41WW5yek9CQ2hQVEg5RE9EMnJQSGY0d2hvV3Y3ZkxwY3N5\nYnBVUHBIR1VPaGhLQzhcbkZtSUYvbjFucXJnOElrdDE2K2N5RGoxaks5c3Ry\nZWs3L1pMZnE5OFpxSGh0Y3hML1JXWEdKeUt4YzM2SkZzdU1cbjh3anlHUm9V\nTm9oVzI5aTZ3Um5WUXg5NTkrSVRYNU1CaFdvbStFQzJOc24zR3BSdmxiQjRx\nWm9OQkFiT1BlMEZcbnA3ZXZOUm05aCtJamVrN0ZwTEpnNjB0VVUrcENiSUJJ\nVTVNTGZLc1BQY0U3bTFmQUo2R201THUwUWl6WjZ1ZFlcbnZXb3pTRkRSWkJW\ndzloVU5hMi9FYi82YUs4TWdRZlFOeGFaQmtGM3BTVitWbU0wUDlaU1hQMFc4\nMmtKbGZaTWpcbmRiT0wzb1Z0clk3ZlZFc1YxQ0F6OFlVdWtsckMzcGNMazJJ\nbHhRcDJXbDJkR05tak0zQVc5TU9NdWhkcDF0NXNcbnhWb3NqME9tS1Z2dUly\nQW94dlVPOGtENTdNSUNvN01zUTdCN3FMRHFHZEE5czM4WmJEOUhxd1hTYTVv\nS09oWUtcbnlSbW1oS3NQYi9ndERMcVFsR2c1YWlCN0UzVU9pdVlvREY0eGsz\ncTZoaHo0SmhYblBCcTlSZ2QzYzNZUXM0MTlcbkV4TWxtWHJpY2Q4ak1RcnJj\nZW44WFJiTE8zd2N3c1g0M1VPRTIyQ3RjR3lCcnhRcTh5aVBjbXpsSmk1V3JN\nS0tcblUxbGUrSHgvZmg5K3VKOE9rc3ZyV2lDT25CR1VyZGhjdUkwRVRxelpZ\nZ0VFQU40U29uSGF6cVZic3RVR3MyUzZcbnFMQXllQUR5czNaeDJYSHcwaVEy\nSjErWFFSYXdKSloyUlRZcVBPMjk2SllTZEljeVVSM3dkUnRjNk5jekJDWTFc\nbmo5UklVS2NRc1NwVFlibndhNWM5cHRvNUVEN3lOSVRGeGVneFZVWExoekgy\nYnM0WExpbzhtVU5UeDVHdzVZd2dcbllsSEJCSEk3VElKWmNXTkVmbWYxQUNE\nckFCRUJBQUdKQVQwRUdBRUNBQWtGQWs2czJXSUNHeTRBcUFrUXZsaHlcbktF\nV1Fab21kSUFRWkFRSUFCZ1VDVHF6WllnQUtDUkI4RGtqaXRJR0NiUHpVQS85\nVDk1SWt0aTZWRGw3ZzdWVm9cbjdqZFJ2UUFVQXU3N1kyOVVadk9pZ3hjam1J\nUzQwZEM5akM4TXNmUk9lMUs4aFhGbkdRbzRXWXF0dk1LRk1Zdmdcbm5rRk5Y\nOUh4bzMzVFBaUVFVczRkWGVWdlJOL1NFYkQwY2N6Uy9LWWZHQThaR204QWIv\nUm4reDM0RE5XaWdIc1dcblBMaThqaCtQdXZ2TGdkVkZUMjdrUnk3VXU4ektB\nLzluSTdzSmFlQzAyS1pvRmNwNlZWWlJwdzArV0RJRk9GcTlcbkc1NWMxL3FB\nUDkrbmR5Z2ZGYTIwQ2tMaDlRM0UvQzAycG5RZ0dSdWE2QlphbkgwbjdoMUxr\nOTFENnJrcmRPdUVcbk9sa21XU3FXRy9uZ1hac2FJV2dDUUZMZXk5bEx1TnFq\nOVcvM1ZVa3o1Y243cWZ2OWx4TXp0My9lcm5oeVpUTE1cbjVOWjk2cGF1UlE9\nPVxuPXROampcbi0tLS0tRU5EIFBHUCBQVUJMSUMgS0VZIEJMT0NLLS0tLS0i\nLCJzZWNyZXRfa2V5X2RhdGEiOiItLS0tLUJFR0lOIFBHUCBQUklWQVRFIEtF\nWSBCTE9DSy0tLS0tXG5WZXJzaW9uOiBHbnVQRyB2MS40LjEwIChHTlUvTGlu\ndXgpXG5cbmxRY1lCRTVUQ2dzQkVBQ2s0eUhwVWNCTVhZTWlMRituQ1EwbHhw\neFU0S0pDbTV2cGdsZEFDRzF4V0pweWQ4RVpcbmxZOUMxRDYyQ3djbjhiWFhZ\nQ2hkRDVQMkg5N2JBSzZpc0lGdmhNYXJqeWpCb1dCbDBWM0RmcFJDbHpkdWtH\nbEFcbnphQ1dYaUQ5aXhUa3pBdHU3WU83OUNXZ0xnbi9KaEZBQ0xPNWJpU0V1\nbElLOTlESk92N1cxSzRUZzNUWWhYMHdcbnR5QzZEWjlUNHpFYXMrWWtCbzhW\nK1gwYzlvNVh3QlJxSTZ4NGllL0VCYXZYSlQ5cW40aWI5UWdEeXFlTjh1YXNc\nbmdwVzJXczBudlBPT2gwanJJNFdOejZHeEw3ZlJVUENsVkVuOGJtV1VhT1Jx\neDJYOVhFcEJEdDUvTEEwa3NJMXVcbk0rTmI2Ty91cmVBeUY4WWx0M2hrdDRi\nYmpQaG91Vmd5c0E2NDJVTStJazQ5MnRkWUNDQmRhQW05b3Y1TUt5UGpcbklM\ndXIzeDAyVjJIejYrWnA4M05wTVJ3c3pETnM2VGxOeUNOeG43SG4rNUpac1lT\nZERVRkpIUXI0bjUwK2J6dmFcblFmdGxlOEpid0xIT1hUUDJFTTUwMHdySmRr\nNzhzcTJ1K1lyQ3lBMWVmTEFNRm5sWDJBemFyOHRxMWlwYWlSTnZcbjZjNDNw\nOW4xU0dKWVBIMWI2b3B6S2VJc1U0YzhDOVFKNGpKWjlraTg0NndHMmhmRGty\nbEt1clV1MVdyanVtUC9cbnpXaFlaaXZnVDlkRVdUeFVwQXBpcGJIT3RhZUNm\na1BpVGUzWkUwWERSNlJoOFI3OHdpUldGQ1lSSDBURklxbmRcbkJLcEU5SlZw\ndHdxYmpnWkV3Z0xVMWNmM1d6NzJTb1VyYWozMko2V1Z0NXVBVDZJY3Vxa0Ja\nVGNNSndBUkFRQUJcbkFBLytLUXFSLzhuRjlCd1lqbEorTW96cHRWdmt3S216\nS2FJaTRqSDd0cWdDV2NLa210WmMvWm5BOFhEejlRcjBcbnFvZ2E2M04zU0lh\nZW5SWWN1ZVZIRXA2ZGNSMGErRXZuYUo3YTZDei9TakJCQmZ3dW8zb1ZnTGhO\nL3UrS0JhSHZcblB1M2M4S3owNjcwZSttcExPYk9IZXFsUDF0bG9CSk45NVZY\nK3BYL21PNkh2ZkZMdHJCRTU4bnk2akNUazRoUDhcblBubkYwSFREZThSQVZJ\ndTRMWFpWZm4vSHA2OHB1MkJ2LzlxNUdMaUIzOVBUUFdKZFoxTXRBSVoyYmsv\nV25jd0ZcbjBaV3gzRGxZdms0T29KUlFqQ3k1NFdVRUQyMkpJaklqbk1KcUMv\nRERXTU16TlhOSkNEZGIxTERjcUIxb1R6Ly9cblBHaTNmTjdZZkRWRVAzU3N4\naUJRS0RtelIvLzBxWUl5Y3NYSnM2Rm40L3NibXJ5aGllVVJsVkdCbWNaYVV2\ndTVcbjZDUSt1ZXk3cHdzZDJHTC9lNTNMSHUyYUtiWnlnWnFxZDMySkhrYksy\nVDdrbThObVUxMmhubUdqTXRhbTBja0hcbnhkeHlqdWtqZ0RNZFUzVHkrOUhS\naDJsRHZTSkg2QkFJZk1TOXM5ZzQxNlNBRzc5TG1NSWVWeDdKS0lQRkVDSW5c\nblhTT0s2d0VySDRheXJiSElFNGhUNFk5UXR4MW41aUVjYm9lVURaRU4xREta\naFhjMlpHNDMveEphSnJNMU1nQU5cbi81a05CYXlJUnphNWVkbVJQNG9XVVpt\ncmhGSTF0VW1GblNuVjdZSWF5OEVSUU10Mk9GTy9xMjVXak9rbVA4bTdcbkpT\nTFFVQVZsTi8rL21VVkVNUHlDYmJLNXFtaUlENFVJRTdveG9hemd6SWxVdm5F\nSUFNSGI1VzBsdHZCQkRkRmJcbmFZSkNHekZDbVh2ZnZ3WTFKVGFZWlowaEhR\nVjc4VElpUS9aRWxqcmhlbXhiT3hXREFxYXcwOVVhSU9hU0l1L0lcblE3Yktr\nWmtQclNGU1VEQmJHd09odUlVUklWbEdpdEhEaGVBVko3MGlQM3N5MDRDOUdD\nZEsrZzIyNENXajhUWWtcbkFxelFGbUxiUjgvQnZuNHBtcjNsRS9nZ1UyK2FP\nbjZ5UnpSdDJwOVEyV1l0aW5YVGNNRU1LNHdTbW5sTDJUaGdcbnlyWkNGT09P\nWkxnMHlacHpRSHJwbmlLODB2Mlg5cGNKNkhuTjRqWW4yVDNaUnUzL1FtV2Nk\ndVVyd3FDQ2J4Q3hcbkZWOUdKR0ZERnMzYUxnaUNpMDVIVjRMSVZiVCtMS0Vo\nMEZybktWV3lCeHV3R2doOW1KV3JSb1FMQ3phcFpobXVcbmhUcUNFL2NJQU5t\nOXozSmdGeHk4YXlNZTZ0dXdCSzZLaDZiQ3VmbWFFVjJxeTlDUU5CZnNUeUQ1\ndEcvQkpYdWNcbk53Qk45dENWaVlvK2RvV3VUcGRLVlFSaWZoUWJOdHEwT1cz\ncFdjNnZMelJFTVRUVzIvdUVXRzA2NHl0V2c2eUFcbjBoT1RXZXJraHBKbU1B\neXhMRXhSdVM1dkZvZDBVcUdwZTRPSE5EOUw5S3BIYmV4NmpzdHRSWS9mNmRS\nS2MxdjRcbnVIL3l1UWZ4bldJS2tWZVBJbElGRTZJSkFqUXRpL3BTaEVtalZN\nTzE2eUhKbUlxVzQ4ZEdJZCtONVMxczRUUzFcbnR6YXNTZ0VTSkc4ZlVEM2NI\nYm9KK0k2MU9Qakh3a3U1OHdteHh0cktob2htQlRYU1NVVUU4VVNpQUlDUXhJ\nZDhcblA0Zkt5eEtXZURyNU84dUQwL1BiME41QkMxWWlYVkVILzFxMExDRkc0\nVG94TWttekdYQVlzeGtIUXMwSU5HMUhcbjQ2cTJKb1VkUDNCZllCVlozd3Zw\namtrUm13Q3V4TklSL0xFTHcxZXk0bDRCc1FWN2hIU1gwcTV6SlVOVTBwWjVc\nblR4ZWFoREQxdWxwb2h3N3d5WmNUS1JVWWtDdU5vTnhJS251d284U3lsMVZ0\nVDdnbVlQazRpUCtOZEdTMTlveUhcbjNoOFZYMy9Udmd3ZFlIbDlJdUN5bnFt\neXJWNDlHS2VtTEhkTVNFMFNmdnhkbWIyUzZyeUJXZXJIZUVockR2N2pcbk10\nelNuMlFVQ0s4RUdMUEtPM08zSUk5RDUxUUFjQVpGRVF0UGY4K0JrdkloNXFu\nU2tmY0lkY21MK09XNGlLZDBcbnRwSHpCVVFjUVkwWkZVSXUrcGZOWWR5Nyt3\ndlhPOWd2STZyNlYxZjJHS3JDZitSWmFyOTRhc1owMkxRb1IybDBcblNIVmlJ\nRU4xYzNSdmJXVnlJRXRsZVNBOGMzVndjRzl5ZEVCbmFYUm9kV0l1WTI5dFBv\na0NPQVFUQVFJQUlnVUNcblRsTUtDd0liQXdZTENRZ0hBd0lHRlFnQ0NRb0xC\nQllDQXdFQ0hnRUNGNEFBQ2drUWk5OUNudktmblg1MEF4QUFcbnBEOVMwQUpZ\nbEtXR3pTU1FtV0dRWmIxcllqdmtGTEhhOFRpQmM3TFBSL21iUVE4WE05ZlJl\nbC9hNFpGYVRQa3JcbmVuaURuNVAvNmw5cEgvNmVwdTRRTGJKdHpmaDhHVm00\nWWY3MGJSWnB4QnpLQWNQY3I1bUVNdFMxRUN5YTR6MXRcbkJOUHl6RytzQisr\nZ2dPSXprWFlna3hPc1FJcUVTMDhlbUZaVmd2OUd6dzFwU2NqeFhMZko1Tzhx\nSUdmUmsvNFRcbnVQZmNZeU9lUVNBZXltNkhuUWlYeXp1Uk14RlBwZnV2c0N5\neVh4YVVlNzhLbU00d2ppZGRIZHJCcUJwazRLeUZcbk5PS2hkYkp1b04xTmlG\nK09EWnpaeTVTcFk4SkZrV2VaNERFbDY2c043eHBhOWg3UVBaSlllaXhzd3ky\nSlJjdjFcbkdJNklnWStDOXN2T1NNNG8xMmZmOSthWEl6MEI3YXZXUElpbVRZ\nVjI4eEdnM2R4aWdvaEl2cXdublpWb1F3eGhcbjQxK2RtbXFka3NWdGJ2a09u\ndUkyUVJkMnM1SDkyeGJtcjRBaVZMdFdrV3dtQnR4M0ZKbmJhSGY3QjJVMGVH\nR2ZcblUrZis3ZUllYzRaYUdta1o0S3A3NkY5dDFCMll1c1Jna0w5RE5LYnUz\nTzJ3NVRNL08zMVZwVmxGU0JQZFI0RFRcbithTklCbFg3b3pZMjlndzVYSi80\nem82Z1VaUWVVM0x1Sys5TXZtVTVYbGVUWU9WMDNhWWRrc1lqY1Uvcm1vM1Zc\nblhGY09DYXpQbi9Ia3gvOUt1WGF1RFZpTnNaRFk0MGpUYXFmL0Y0QjR5MGFX\nb3NaNjJQQklDbE05bXM3ckFBVHZcbkVidkV0TEIyb3hJV0RnbGFNaDVyZmps\nd2FNOURQcDZ3bC9uNXk5ekdveU9kQnhnRVRsTUtDd0VRQUp5bDdZdWdcbndt\nVnY3WndlK2NnRzBLM1NFT3pDNnAxcktJWDNUcnNLMUdONytIdjRvTjBUS2Vj\nMGVUUVYvRmFsU01aODBCUWVcbjBLaDJPRXVrVmpDeGx6NHBFRWd4L0F2R20y\ncWtzK05nYkFQV0F1NVI0QWV2WlZxbS9TS2JidjllUWRQcWNKejZcbjRWbTNG\ndzUxKzA0MnhkT2NlbjRrL254SXRwRmMvRVpSMVk0Z01JMHp0ZVpEbThSQnBZ\nYWd1R3FNQjAya3M3K3Rcbk1NYWFVRlF3Q1dnMUhxRCt0bENjanczSUdBQWc3\nNXJrTElrRVRoT3JUeHdXdS8wa0JadTA3dzNTc3EwWGl0VE5cbjVBOUxERzJ4\nRzE5YVViNWNWVnQrZFgvQ3FUT3ZWUVRnUnVYOFNuNXpuMnA4b1hVcDc2dlQ5\nYlBBOU1XTitJbmVcbnpqd2I2eExLdHpjNVZtMDNDL202UkNIMDZoZnlMRG9r\nY0ttVE1uVFFoWHEyckYzVGhQSHFyS00ra2JtRUYxSnFcbnZ2OWdoYklISTBi\ndFoyRDNMMDdTVW1tdkVEOTN5UnowWER4VStHekp5RklhUmVKM0JJVERaV0Rq\nK0FoU1FnRTJcbldtZEhRQXN4MGRabDFRckRGSHc2ZHdNSGFGUC9JeTJDS3Qy\nUU4wdGhrNXh2OThlUGdYUng0WGErR1RmdE9sRERcbnM4TGRIUmZaWTdNWFR1\nTGkzNGNXNDhZbldYVzhLcEs0Q2xsa0hRbmV6emhHb2hlMWh5U0YyRXpMOGZY\nQVhQN2lcbktJR2JESHN6WHJ6a21HVDQvWkFTL3k5MGpSdVZ1QklMbEFSbjFE\nR0ZZcm9kOHhmbndtdmhSSFRPcStmMXljUTdcbldSaHRjV0JkOHN0LzhsMWww\nZkdWSU9iWGpFMERXcEZRcFRhbEFCRUJBQUVBRC8wV3BRUGdYZHUyM0lYSVBs\nQVVcbll0WjljaDJyNURJVWtkNDRuaVlJU0RTb3NhTkdPZUdqT1F4NGdFVGtk\nZE1yQVZkZENNT1pvbFMrZ3VIT0h0SllcbjFWWDI1ZXBxZC8zOEE4NEpZMTEx\nSHB0WlkwYThNSGpHdmt1cFhaOXFobmFoYUNlZG5KNkNpdC9UQ2gwYXBEZmJc\nbnVCNUQ0Z2h4RTNtaStoaVk0emRvRmtJSCtzNUVuZUkxM2JYTVJVTWZqRHlY\nSm1rOTNQUEx0SEVWeDA2YWI1dnZcbkw2ZjBWUU1zOGJJdnAxVVUyNjRDRnVt\nbDRFbndja3RoZjVzcS9sbm9odHQ4aE9YN0VLbFY3RWVEWmNiRS8vSmtcbk1v\nTVk2M0crdVZxcDgrSzZ5OUNVcWw2RllPeGNqWmFtSEVzZUlVaFBiMk50aEpT\nOXVZYTJyaVNPV3VqUi9YSkdcbmc1TGpHcGw2Z2ZJQWYzdFhCVXVTOTg4YlJF\nQnRxbFZkR3g3Ym5sUUtHQ216bXpJd1RLMXJGMU10ZWxoL3ZXNENcbmhlUU1s\nRTJDejBXN3AzODBWWldHRytFdnMrM2MvWnQrODRsYlZSZEdVMkoyemhJN3NU\nOWRXUFVtME5BZkU3YTZcbjVkK0NiZTNOTDlPcldIYXFjOEM3VmpGakJEZHZF\nQ01UMEdRUkFCYUhoK1JXUFlOTlJoZEg1MWU5T1hjTzV2VlRcbkl4bS8wdEwx\nWFVkSVRZTTQrdUpmM1ZtaDA5UXQ2eGNWNlZXS0xxUk9aM2c5ZmdWeU5wVVlB\nWS9wWE03aVJZQ3lcblJDa0Y2SnMrSzRzUXRhOEhzMCtOQ3lvZm1jdzJINUVC\neCtMa3p4c3BHMzRNZ1ZJU3JjWlprL3VRcjdkSE5BdHJcbkJvMkZFMi9QWTZG\neko0Q05hS1VFMjI0KzV3Z0F3dlN6dUFwTFYvUVBMdE9UanEyUVkyb1JVSlJR\nR0wxVjBXcm5cblEyRndZTDByNXBUZmVSbkhGWUJXZ0ZaNm45eEFmMHBMNWRY\nNjFIZ3AyTU4yMk5DMUhwMEhib1gwYW8wS0U5ZnBcbjVBdzRMd0pibWI4MUxY\nVUNMb2YwbndrTEdHdGlKWS8rOHUzaU53SlBaRENlNnhsMlZvZThNYjVTZ3Jq\nUHIrOEtcbktEczUyN3VkZXd6UUhiTE1KaTV2OWExbDUxUDZaanZTcjdEVE9O\ncVR6SmUyWXkrTGtSYUZjU2FreEZIS3VGZkdcblNERVBpRHJHS2J3anp1eXhH\nczkyVkFBbUhYek9WQXRvVXFUZi9ZNklVOFJ3d2ttMEg1SzU3UFdPZ0pNWWJY\nVEJcblgxd2NzRVRNVFZlSTRxN3ZwYXkwdDBGQXVvQTJXWVhoV01Ia0pvUFZT\nT2psN2wwTFJ3Z0F6YktOSkNFSGc1Wmxcbkg5cFVpVmJOVHd2Vk0wNjFaRzJF\nc3lQSDByZ0NHWFdjdW9RZCtmQTE4UWVyaWo5ZUJDQzNQcldpZWE3TWs4aGpc\nbjlveXI2MzRIVDMrL05aR1dlTXE3bEQ0d2ZPTHptRFpDT0NmbHlwUlBBZGVq\nbSsxc2RreVkrS294OWpNTitlMGJcblV1T090cmZOWXpBbkswV05XZnI3L3Ba\nd0wyRDFtYTBGaVVuMkRPR0NMOEwzRkxnUm9QOVJ1dlAvMTNHUGpqVVFcblQ3\nVW9lakhFMDczSk5INW9uVFh2bjdDZkEzMU5jWW1GajkxV1VCV2ZCY2hNL042\nQXZha0xzd0cxTmpZRFo3NC9cbm0yREdaaittblZFQW1QRGJNUmJrNjNuYXU1\nT3ZXNDliWmNQQVphNUtBQ1FrQlNCOTNvQzlwcE9mTVJXNmpKUmdcbkhXd2Nw\nL2tNc3dnQWk3Y1JGUVZiajhGVk5kdU9CWi9ROG1jVjhIQzRocjBtb0d0eXdU\nQTlKUHBBWWFDWU1laWlcbk1XcW45KzQ4L0V2eTM4dmxyenQ1emFKV2VCVGNW\nbitZeEEzcHpYa1NUV2pBWHU3N1ZQcGZvdkU5dFlaQnBqcnJcbmFHKzFZeXVO\nb0dndlRrY05ScEdxVWQ2YjBxbFY4dVBFSXZCMTZaOWlYQXJESm9IRWxLQlRE\nK0JiajNjZXFCMGJcbnFEcWRyd1ZpREV4SjVTVkVXZDBBSGhDaW53MFo4NkQ1\nck5TaVFRc2lwWU8raGx6ZXZ4Wk1jYlgya1E3Z010ZlNcbmVxdWZHYmhWUlFC\na25iQlIwMXdUYk1MKzVxazJUeW9BSzNaWGR2MWVlSitwNVhCVUpGc0EyczBG\nQmFqWThTVWxcbmVvVnYyRWZXblR6akJYd2Y0OVN1NGN1V2ZSRFFCSVdIL1hn\neGlRSWZCQmdCQWdBSkJRSk9Vd29MQWhzTUFBb0pcbkVJdmZRcDd5bjUxKzMz\na1AvakgyNlZGMlBvdVBZLzBFL2orMmFOOEtZSmxHczRkNkp3WDR2QWNUVVNl\nMDdRSkVcbmxGRTlHMEp3R09nOXZIanF2TVF4VFdTUDN4RG9kMWpDWjVTS05T\nNnpOTmZaYmQ0eGV0Y3NkN0s3TzRXTFRCMUFcbmFhU01aTUFVZi94WUJMdmpu\nSUdFSjExM0tMNGpSQzB6Um44dG1mSHRFZkZTTUZkUk9BVkNySnBld3R4b2FN\nbVFcbmF0cFp0eTFtM1poUStzSnNzOHN4dUJZQ0NkMVdlVTlpbmh2N1BrRjN1\nNFFyVkVNVXhDL1JlNDU3QjUvbjZuL3pcbno1YkRFOC83VWwzT0oxZkxDK2or\nRjZNNDFMNUlYanFXWjdrREdmZzl2VTJKYjYwY2VZSGo0RFFTMHYxUWFZYmhc\nblF1bTZrK3hDUkYzaGFVekFRbkN0SWJZUno2N3lzZENQaXZuMEc5YUhHSU5G\nNUl0R1E4ZzEvaTZYYXRUcmd4K0ZcbkhDQXZ3MFovSXRDZjJNVmVHdVkxMFl2\nZ2VJYUZDWEF3eTV1MjhnVlEyMUFxdERQdW1jRnBsM0sraGo5czRoaWpcbmtP\ncFcwMU5tLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8v\nLy8vLy8vLy8vLy8vLy8vLy9cbi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8v\nLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy9cbi8vLy8v\nLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8v\nLy8vLy8vLy8vLy8vLy9cbi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8v\nLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vL2xRSFlcbkJFNnMyV0lC\nQkFDMG51bDhxcnkzMGtOK0IxZytndTBxQmNBNU5EandHbVkwN0l1R3U0ZHZI\nUElHT0FRV0h6VXZcbldpNy9BaU02UExkWEUxb21CSmhHWm1iVmE3cnlCZDYz\nR1F1MFNKQkxRQlMzcXFtRW9CZURJc3lrdnFkaEx2M2tcbngrVktZSytheUUz\ndGVkbG9NQ0RTNEZZSmtUTERBbHE2OTFQcnZxbkc3VFdXeXIySlhXbDdRUUFS\nQVFBQkFBUDlcbkVjOFRZQ2srTEovQ1FObTgzOWtDbW1DYnlKTE14R1o0bjdl\nWHRabFFRV3FUWUgxREd6ZnpnMW83TDdDZHhEOFBcbi9XUVpRT05nd2ticGY4\nU1NBbUt3SFZJTEp0b0Q5OEVPUEtRQ1Q2YW13RnFCNk5CWkU5Q2FLN0lIOFlM\nQWRnWFhcbm41enU5czVwUXprTDIreWl4YTg0YjVMUFNZeVBMbmNvWDBCamlE\nYnJydU1DQU1nejlKL0luK3N2SkNhaTVwSFBcblJOMjhESEYxaUppMURGT3Bh\nU0lVZ2g4dlJ2SWVETENTNHI1bkNTSjJCQ04rc016dTNhT1FnSjJ5ZTVBaEZD\nQ0ZcbkVyOENBT2IxenlFNjZXZUJDSG5UaWEvNks3RTNVSTBXb3NEWTVTMG5z\neWZHTThSQWNoNzJCV04yalV1TVd4M2JcbmhhZ3RKcVd6eXhsd1dqUnUvMk16\nZEhsSzhmOENBSk15c1h5NEIwY2ZGQ0wwanJSQWs5Z09Ga055a0prS3ViZHhc\nbjdHL1hVOU5QcDVwV2d1T2JPaTdTdUozU084QVR0UXAzVjd4d3Y1Y040OEJt\nSkE3L1R5MmM5clErUjJsMFNIVmlcbklDaGhaalpqWVdNNE1DMWxOR1V4TFRB\neE1tVXRaRGd5TWkweE1qTXhNemd3WlRVeVpUa3BJRHhzWldWQVoybDBcbmFI\nVmlMbU52YlQ2SXVBUVRBUUlBSWdVQ1RxelpZZ0liTHdZTENRZ0hBd0lHRlFn\nQ0NRb0xCQllDQXdFQ0hnRUNcbkY0QUFDZ2tRdmxoeUtFV1Fab25aYlFQK0t3\nbFhucUZtSWF4NFNsbVU4YUduTUVvb293bWxpU0JVeThTSHFkRU1cbmhWYUNG\nOW5MbWdDNGhTS2JwaExiR0h0UHdpWDdLcEVzMDZqTVdTb2lqUldncGJmdjY2\na3VENG9VQVZ5Q290MlNcbnplTUNKcjdPY1pJeXkwalVZYUYwRFhEbVRLMFRG\nN29mQ3BZc0xEWmVPU252TFcrR05CRHdqM0g0YVlSQlVVSTNcbnRHNmRBZGdF\nVHF6WllnRUVBTjRTb25IYXpxVmJzdFVHczJTNnFMQXllQUR5czNaeDJYSHcw\naVEySjErWFFSYXdcbkpKWjJSVFlxUE8yOTZKWVNkSWN5VVIzd2RSdGM2TmN6\nQkNZMWo5UklVS2NRc1NwVFlibndhNWM5cHRvNUVEN3lcbk5JVEZ4ZWd4VlVY\nTGh6SDJiczRYTGlvOG1VTlR4NUd3NVl3Z1lsSEJCSEk3VElKWmNXTkVmbWYx\nQUNEckFCRUJcbkFBRUFBLzRqdjdBeXo5eHdOaURGdGp4dXZMV25GNWpGM2t3\nUmh5WlA5MHA4MWRMa3luNkozblVsVzRpc3ZZUHRcbmFhTGxkYmNZaEhzV2JM\nME5XSm1LK3dWeCtURmIyRHNvSy9YM3NZZW5Yb2Fnd0diS25Gc3NFTnZjbFdm\nNVJSY2Jcbm11eUF6VXRYVnNPV01vaDZacXR5TVJsTmRwNnRDSWpIc0FiU2VQ\nVHg2U2o2akRwOTBRSUE3QVdLVkpyN0FJdk9cbnBtTmJIUWF6WjFSSWtjMnpr\nNFFucjVYbDFMSkUzbVJoWFU1aytjTld0QmVxV0ZCQzBiRUF4UCtkNkQ5ckFU\nN3FcbjdsdlJxRDVYUlFJQThON1VpdE1UUEliOGR2akZaV2VqSUpvZ1RuSnQ5\nL1V6MXJkQTJ1eUV6bDRUa29xc04xMndcbjJzQzVGVHdTdGsxeXgvTW9wc0Vn\nM0tiZjJhSExIdDdDYndIL1R1dXV4b2pmZFdERk5hdU5QTmFJS3F2a0plUmVc\nbjY2SGFLYVFrU2l2TWlsb2lYZjJmNTZGTnpNYTNWMVZNQlg0bnFSSmlib3Av\nV0xCSzNFa0ZhSmpkWjZwaGlRRTlcbkJCZ0JBZ0FKQlFKT3JObGlBaHN1QUtn\nSkVMNVljaWhGa0dhSm5TQUVHUUVDQUFZRkFrNnMyV0lBQ2drUWZBNUlcbjRy\nU0JnbXo4MUFQL1UvZVNKTFl1bFE1ZTRPMVZhTzQzVWIwQUZBTHUrMk52Vkdi\nem9vTVhJNWlFdU5IUXZZd3ZcbkRMSDBUbnRTdklWeFp4a0tPRm1LcmJ6Q2hU\nR0w0SjVCVFYvUjhhTjkwejJVRUZMT0hWM2xiMFRmMGhHdzlISE1cbjB2eW1I\neGdQR1JwdkFHLzBaL3NkK0F6Vm9vQjdGank0dkk0Zmo3cjd5NEhWUlU5dTVF\nY3UxTHZNeWdQL1p5TzdcbkNXbmd0TmltYUJYS2VsVldVYWNOUGxneUJUaGF2\nUnVlWE5mNmdEL2ZwM2NvSHhXdHRBcEM0ZlVOeFB3dE5xWjBcbklCa2JtdWdX\nV3B4OUorNGRTNVBkUStxNUszVHJoRHBaSmxrcWxodjU0RjJiR2lGb0FrQlMz\nc3ZaUzdqYW8vVnZcbjkxVkpNK1hKKzZuNy9aY1RNN2QvM3E1NGNtVXl6T1RX\nZmVxV3JrVT1cbj1sWERMXG4tLS0tLUVORCBQR1AgUFJJVkFURSBLRVkgQkxP\nQ0stLS0tLSIsInV1aWQiOiJhZjZjYWM4MC1lNGUxLTAxMmUtZDgyMi0xMjMx\nMzgwZTUyZTkifSwiZGVwZW5kYWJvdCI6eyJlbmFibGVkIjpmYWxzZX0sImRl\ncGVuZGVuY3lfZ3JhcGgiOnsiZW5hYmxlZCI6ZmFsc2V9LCJkZXBsb3ltZW50\nc19kYXNoYm9hcmRfZW5hYmxlZCI6ZmFsc2UsImVuZm9yY2VfZ2NtX2NsdXN0\nZXJfY29uZmlnX3ZhbGlkYXRpb24iOmZhbHNlLCJleHBpcmVfc2Vzc2lvbnMi\nOmZhbHNlLCJmZWF0dXJlX3RvZ2dsZXMiOnsiYWN0aW9ucyI6eyJlbmFibGVk\nIjpmYWxzZSwic2V0dXBfZmFpbHVyZXNfZGV0ZWN0ZWQiOmZhbHNlfSwiY2hh\ndG9wcyI6eyJlbmFibGVkIjpmYWxzZX0sIm1pZ3JhdGlvbnMiOnsiZW5hYmxl\nZCI6ZmFsc2V9LCJtb2JpbGUiOnsiZW5hYmxlZCI6dHJ1ZX0sInBhY2thZ2Vz\nIjp7ImNvbnRhaW5lcl9ibG9iX3JlZGlyZWN0aW9uX2VuYWJsZWQiOmZhbHNl\nLCJjb250YWluZXJfZW5hYmxlZCI6ImZhbHNlIiwiZG9ja2VyX2VuYWJsZWQi\nOiJ0cnVlIiwiZW5hYmxlZCI6ZmFsc2UsIm1hdmVuX2VuYWJsZWQiOiJ0cnVl\nIiwibnBtX2VuYWJsZWQiOiJ0cnVlIiwibnBtX3Vwc3RyZWFtaW5nX2VuYWJs\nZWQiOmZhbHNlLCJudWdldF9lbmFibGVkIjoidHJ1ZSIsInJ1YnlnZW1zX2Vu\nYWJsZWQiOiJ0cnVlIn19LCJmaXBzX21vZGUiOmZhbHNlLCJnaXRodWJfaG9z\ndG5hbWUiOiJhbGVqbmRyMC0wNWUwODQxYjIwNzY3MjcyNy5naGUtdGVzdC5j\nb20iLCJnaXRodWJfb2F1dGgiOm51bGwsImdpdGh1Yl9zc2wiOnsiYWNtZSI6\neyJhY2NlcHRfdG9zIjp0cnVlLCJjb250YWN0X2VtYWlsIjoiIiwiZW5hYmxl\nZCI6ZmFsc2UsInByb3ZpZGVyIjoibGV0c2VuY3J5cHQiLCJ2YWxpZGF0aW9u\nX3R5cGUiOiJodHRwLTAxIn0sImNlcnQiOiItLS0tLUJFR0lOIENFUlRJRklD\nQVRFLS0tLS1cbk1JSUZSRENDQkN5Z0F3SUJBZ0lTQStTblhBdG1JVWdrRzIz\nYkZubUtxTDlMTUEwR0NTcUdTSWIzRFFFQkN3VUFcbk1ESXhDekFKQmdOVkJB\nWVRBbFZUTVJZd0ZBWURWUVFLRXcxTVpYUW5jeUJGYm1OeWVYQjBNUXN3Q1FZ\nRFZRUURcbkV3SlNNekFlRncweU5EQTFNamN3T0RFMk1UUmFGdzB5TkRBNE1q\nVXdPREUyTVROYU1ESXhNREF1QmdOVkJBTVRcbkoyRnNaV3B1WkhJd0xUQTFa\nVEE0TkRGaU1qQTNOamN5TnpJM0xtZG9aUzEwWlhOMExtTnZiVENDQVNJd0RR\nWUpcbktvWklodmNOQVFFQkJRQURnZ0VQQURDQ0FRb0NnZ0VCQUxqZmM2dk5Z\nUHJGMXpGWWkvZVBuQ21sQytSTTNjVW1cbjc0MHo2aGM1UGdUOGtEejdOZmJJ\nWFA3ZDZuaHJtekJNbGJMZU4wODNFaGVBNEtlS2lESlR0YnZkU3ZBSXZLaGlc\nbm94cm9sVGgxNVZkbzU1Q2toc1ZVMjErR3dEdDZNUnlWaHROT2swTWNhcDVC\nbzZLcDRrc01Oak14dllkREF0bDFcbnl3QTh5TVdUcG56ZXRtSWdDYUFrOGdn\nOXphenZWellvd0hpdXFNQ0xzbGlCazBMZ0tmQWowM3AyU09FYm5pdjVcbm9z\nQ1B6SWMxVGNkbXFGTGVxUC9OQ2xjaS9PZjk4Ykl4TzF2dlFRbjkrOHRYK2hM\nR3BVQjdBUHUranl4ZFlUQnpcbjQ3SEtWczdocC92djF1L3BGdXhjQnA3ZFJz\nMnZFNjl5c0ZFSmt1aEdLcTVLNG01SER1dEsrU01DQXdFQUFhT0NcbkFsSXdn\nZ0pPTUE0R0ExVWREd0VCL3dRRUF3SUZvREFkQmdOVkhTVUVGakFVQmdnckJn\nRUZCUWNEQVFZSUt3WUJcbkJRVUhBd0l3REFZRFZSMFRBUUgvQkFJd0FEQWRC\nZ05WSFE0RUZnUVVQK2lRYkFORTh3cXhESG5PTSs2UDFQVUJcblFNVXdId1lE\nVlIwakJCZ3dGb0FVRkM2ekY3ZFlWc3V1VUFsQTVoK3ZuWXNVd3NZd1ZRWUlL\nd1lCQlFVSEFRRUVcblNUQkhNQ0VHQ0NzR0FRVUZCekFCaGhWb2RIUndPaTh2\nY2pNdWJ5NXNaVzVqY2k1dmNtY3dJZ1lJS3dZQkJRVUhcbk1BS0dGbWgwZEhB\nNkx5OXlNeTVwTG14bGJtTnlMbTl5Wnk4d1hRWURWUjBSQkZZd1ZJSXBLaTVo\nYkdWcWJtUnlcbk1DMHdOV1V3T0RReFlqSXdOelkzTWpjeU55NW5hR1V0ZEdW\nemRDNWpiMjJDSjJGc1pXcHVaSEl3TFRBMVpUQTRcbk5ERmlNakEzTmpjeU56\nSTNMbWRvWlMxMFpYTjBMbU52YlRBVEJnTlZIU0FFRERBS01BZ0dCbWVCREFF\nQ0FUQ0NcbkFRSUdDaXNHQVFRQjFua0NCQUlFZ2ZNRWdmQUE3Z0IxQUQ4WFMw\nL1hJa2RZbEIxbEhJUytEUkx0a0RkL0g0VnFcbjY4Ry9LSVhzK0dSdUFBQUJq\nN2xXQ3VnQUFBUURBRVl3UkFJZ2YrQlQ3VEI4bHJIODBkd2xSRUlqK1hhTnFK\nVGpcbjlrZGM1SjlWRk9rODFyZ0NJRFlmOE15UEZXWUl5QSs1T1M5NTZSYnFK\na2UzeEVKWmpkNXdkSkZuM3ViekFIVUFcbjMrRlc2Nm9GcjdXY0Q0WnhqYWpB\nTWs2dVZ0bHVwL1dsYWdIUndUdStVbHdBQUFHUHVWWUxvUUFBQkFNQVJqQkVc\nbkFpQWhqbitncGpQL0thRzVnMlVyRUpMR1QxV092UlkyWTZKcDdmdElYcnVR\nWVFJZ0xkVGVMbnplSm9pVHdnZzFcbmZscENWUDdoUUxka1I1TUJHODlJL0tp\nUkNLMHdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBSkx5VDk0UTJFN3pcbkJ3\nZEFIcVB6c1ZtaG5lK2pWSnpBcm1vR1l1Tk9JZ3FHZk84V0ZKT2lCNWs2c2lL\nZTM2blp6dU5aQTRtTzQwUUZcbnovUTFoQ3dZTWNkc2hqVitQdkNjUFdYdmVB\ndHhFZlJkOEdIQTlwL2NHVUtCU0ozT1U3UzFZRis1SFdWUWo2WmJcbm5XbWxK\nSFVjYy9OOW5CZmFBVUJTcmt5dkNsc2kvWkV2L1ZrOVJTc3Z5aUkrdzZrNjN4\nblk2alpzU3ZCS1d1TndcblNyZlJxUEJHTE9jYTFVcUx5d09IYTdKc1pKNmZV\nMDUwd2JROWtYUEs1TG1nSHdSM1VWR1NTcUtKVXJaNTAwbjBcbmRRNE5WNzR0\ncFRwM3FUZkd6NllIb2xOa09yTE1LeExvMUFaanlLRVY0SDB5Ukcrd2RDU25y\nVzJsNkxxdzdBZkRcblpZRXdFazM3cHJvPVxuLS0tLS1FTkQgQ0VSVElGSUNB\nVEUtLS0tLVxuLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tXG5NSUlGRmpD\nQ0F2NmdBd0lCQWdJUkFKRXJDRXJQREJpblUvYldMaVduWDFvd0RRWUpLb1pJ\naHZjTkFRRUxCUUF3XG5UekVMTUFrR0ExVUVCaE1DVlZNeEtUQW5CZ05WQkFv\nVElFbHVkR1Z5Ym1WMElGTmxZM1Z5YVhSNUlGSmxjMlZoXG5jbU5vSUVkeWIz\nVndNUlV3RXdZRFZRUURFd3hKVTFKSElGSnZiM1FnV0RFd0hoY05NakF3T1RB\nME1EQXdNREF3XG5XaGNOTWpVd09URTFNVFl3TURBd1dqQXlNUXN3Q1FZRFZR\nUUdFd0pWVXpFV01CUUdBMVVFQ2hNTlRHVjBKM01nXG5SVzVqY25sd2RERUxN\nQWtHQTFVRUF4TUNVak13Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3\nQXdnZ0VLXG5Bb0lCQVFDN0FoVW96UGFnbE5NUEV1eU5WWkxEK0lMeG1hWjZR\nb2luWFNhcXRTdTV4VXl4cjQ1citYWElvOWNQXG5SNVFVVlRWWGpKNm9vamta\nOVlJOFFxbE9idlU3d3k3YmpjQ3dYUE5aT09mdHoybndXZ3NidnNDVUpDV0gr\namR4XG5zeFBuSEt6aG0rL2I1RHRGVWtXV3FjRlR6alRJVXU2MXJ1MlAzbUJ3\nNHFWVXE3WnREcGVsUURScks5TzhadXRtXG5OSHo2YTR1UFZ5bVorREFYWGJw\neWIvdUJ4YTNTaGxnOUY4Zm5DYnZ4Sy9lRzNNSGFjVjNVUnVQTXJTWEJpTHhn\nXG5aM1Ztcy9FWTk2SmM1bFAvT29pMlI2WC9FeGpxbUFsM1A1MVQrYzhCNWZX\nbWNCY1VyMk9rLzVtems1M2NVNmNHXG4va2lGSGFGcHJpVjF1eFBNVWdQMTdW\nR2hpOXNWQWdNQkFBR2pnZ0VJTUlJQkJEQU9CZ05WSFE4QkFmOEVCQU1DXG5B\nWVl3SFFZRFZSMGxCQll3RkFZSUt3WUJCUVVIQXdJR0NDc0dBUVVGQndNQk1C\nSUdBMVVkRXdFQi93UUlNQVlCXG5BZjhDQVFBd0hRWURWUjBPQkJZRUZCUXVz\neGUzV0ZiTHJsQUpRT1lmcjUyTEZNTEdNQjhHQTFVZEl3UVlNQmFBXG5GSG0w\nV2VaN3R1WGtBWE9BQ0lqSUdsajI2WnR1TURJR0NDc0dBUVVGQndFQkJDWXdK\nREFpQmdnckJnRUZCUWN3XG5Bb1lXYUhSMGNEb3ZMM2d4TG1rdWJHVnVZM0l1\nYjNKbkx6QW5CZ05WSFI4RUlEQWVNQnlnR3FBWWhoWm9kSFJ3XG5PaTh2ZURF\ndVl5NXNaVzVqY2k1dmNtY3ZNQ0lHQTFVZElBUWJNQmt3Q0FZR1o0RU1BUUlC\nTUEwR0N5c0dBUVFCXG5ndDhUQVFFQk1BMEdDU3FHU0liM0RRRUJDd1VBQTRJ\nQ0FRQ0Z5azVIUHFQM2hVU0Z2TlZuZUxLWVk2MTFUUjZXXG5QVE5sY2xRdGdh\nRHF3KzM0SUw5ZnpMZHdBTGR1Ty9aZWxON2tJSittNzR1eUErZWl0Ulk4a2M2\nMDdUa0M1M3dsXG5pa2ZtWlc0L1J2VFo4TTZVSys1VXpoSzhqQ2RMdU1HWUw2\nS3Z6WEdSU2dpM3lMZ2pld1F0Q1BrSVZ6NkQyUVF6XG5Da2NoZUFtQ0o4TXF5\nSnU1emx6eVpNakF2bm5BVDQ1dFJBeGVrcnN1OTRzUTRlZ2RSQ25iV1NEdFk3\na2grQkltXG5sSk5Yb0IxbEJNRUtJcTRRRFVPWG9SZ2ZmdURnaGplMVdyRzlN\nTCtIYmlzcS95Rk9Hd1hEOVJpWDhGNnN3Nlc0XG5hdkF1dkRzenVlNUwzc3o4\nNUsrRUM0WS93RlZETnZabzRUWVhhbzZaMGYrbFFLYzB0OERRWXprMU9YVnU4\ncnAyXG55Sk1DNmFsTGJCZk9EQUxadllIN243ZG8xQVpsczRJOWQxUDRqbmtE\nclFveEIzVXFROWhWbDNMRUtRNzN4RjFPXG55SzVHaEREWDhvVmZHS0Y1dStk\nZWNJc0g0WWFUdzdtUDNHRnhKU3F2MyswbFVGSm9pNUxjNWRhMTQ5cDkwSWRz\nXG5oQ0V4cm9MMSs3bXJ5SWtYUGVGTTVUZ085cjBydlphQkZPdlYyejBncDM1\nWjArTDRXUGxidUVqTi9seFBGaW4rXG5IbFVqcjhnUnNJM3FmSk9RRnkvOXJL\nSUpSMFkvOE9td3QvOG9UV2d5MW1kZUhtbWprN2oxbllzdkM5SlNRNlp2XG5N\nbGRsVFRLQjN6aFRoVjErWFdZcDZyamQ1SlcxemJWV0VrTE54RTdHSlRoRVVH\nM3N6Z0JWR1A3cFNXVFVUc3FYXG5uTFJid0hPb3E3aEh3Zz09XG4tLS0tLUVO\nRCBDRVJUSUZJQ0FURS0tLS0tIiwiZW5hYmxlZCI6dHJ1ZSwia2V5IjoiLS0t\nLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLVxuTUlJRXBBSUJBQUtDQVFF\nQXVOOXpxODFnK3NYWE1WaUw5NCtjS2FVTDVFemR4U2J2alRQcUZ6aytCUHlR\nUFBzMVxuOXNoYy90M3FlR3ViTUV5VnN0NDNUemNTRjREZ3A0cUlNbE8xdTkx\nSzhBaThxR0tqR3VpVk9IWGxWMmpua0tTR1xueFZUYlg0YkFPM294SEpXRzAw\nNlRReHhxbmtHam9xbmlTd3cyTXpHOWgwTUMyWFhMQUR6SXhaT21mTjYyWWlB\nSlxub0NUeUNEM05yTzlYTmlqQWVLNm93SXV5V0lHVFF1QXA4Q1BUZW5aSTRS\ndWVLL21pd0kvTWh6Vk54MmFvVXQ2b1xuLzgwS1Z5TDg1LzN4c2pFN1crOUJD\nZjM3eTFmNkVzYWxRSHNBKzc2UExGMWhNSFBqc2NwV3p1R24rKy9XNytrV1xu\nN0Z3R250MUd6YThUcjNLd1VRbVM2RVlxcmtyaWJrY082MHI1SXdJREFRQUJB\nb0lCQUcrMXpsNkU5dEh4bEV2a1xuRm9lY0JwLy9kRVVhMFhNZFNPbEk4bTNn\nRUFMUlhwTUt0UndQREdxUlMrcENFMzlHOTdvaW5zZEdIcStIRjdrRlxuYzdE\nOWRqWXp6T0ZvVmg5bG91dFNtVUNKdFBCeG1tT0RsMUJNSzFiNHhOWHJ5eHRi\nbXlHNlBDLzBUdFNjRXpYcVxuYzZ3bmorUzFiTEg4SXcrbUp1bFkwWFRaK0dO\nQTVYenJXeXV2QzhMYTNDUi9CTytjOWVxY0tCTEk2eFJJZCtMRlxuL254eDhF\nTmlCYzdKWURrSU12NGVmT3JIemxrNExtVVpvMWdzMkNudG5GSDRYa2FlMEJ3\nOFpVZENYZ3krV1kwbFxua2ZLQ010T3hRNDZIdTRtK0dvdnZvV3B4K1VZb0lu\ncFhQR1JqNnFmdURmWjdrbUdWZWlKZmZBTklwekdlZXUzQ1xuUytrTjAza0Nn\nWUVBM1pwaE9MWm5CTHkvZEFYb3NJbmQ5aVFyVWV4bTViRWJva1BzK1k3TWhW\ncWVvbEt0TmZ6MFxuRzdHa0RmQU1uVE0weUNQR2FYeWwvQmhITWVZYnlBbEJL\naGZiSXA3ZEN1QVVNVjFHMSt5THpLMHRJdU9kV1pGUVxuZ0Y5TU10N2xNL0FN\nUitlSTRrMU1hVm9iNVZFeFQydWM0bkFONWVHMlFURU9SZHdsYkhUZGNuY0Nn\nWUVBMVpHUFxub3o5b1o4alpTdVh2OGV3R3NrK1dMY0QxREJOZFRjSjV1ZVBQ\nbXNqY1pQRnZBN3E4V1haVWdmYjlmKzFSTmlqbVxueXJ1TjBCanp5WjBkK2gw\nY1JGRE55M3M3NXdjU2lTSlFxWlhSeUVSR3FOMDdJRUxjTEdGZHlqSnVtdDhN\nY1VZTVxuZjZuWkpQQ09yK0NxL0pIUzJHWEVISFNXL25wRmpHYlB1YXlmRGJV\nQ2dZRUFvMVh6ek9wYzJsZ0l3WXJOYkxuaFxubVZnbGVmZkdEQXpUc25GZ2pM\nemRNSG1QclZORkNpTU5CaENVUEJXd0pub2tzRlAySGJCYlk0bTlpQ0QwWHll\nN1xuR1R5R0wybHF3V1pTVytSRm9FZGc3NWJCU3hMNzJwWEtBU1M4dEU0b0lI\nVVJpRG8zWVozWjhWa1NjSjY4dXE0MVxuNzR6cUlZT1JZMUcyRkhYa082R1R5\nNWNDZ1lBcUNOdFBrelJXY1Fhcm9qUW0xb0MrNmNFeVFpODQ4RHJHQ2tmeFxu\nR1hDTUU0cWxaNHVsSFVUakN0STVQa2JJdmduazhnbnl6eFZyWnUzY3Vjcmpw\nb1Vnd1JLd1FSSWFONThqVkppeFxudUNZeEY1Y2N0MlppeENZWHFoWk9yTHh1\nU1FabTZSV2VydXhwUTl1aHJFT2JNSXhpUVMxbk9GOWJ1TzhsWWpyeVxuWFpK\nMG5RS0JnUUNTNW5hK0hpOUtXSFFaY09CY1p2OFNIYjBXekhydHBTOG1td0RF\nVi83R0I2N2JsVC9zSUtsNFxuWkpyT1JHb25Ic1RUK2U5ekQ2U2lsbEdnL3R6\nanBFYWNUUEEreEFMTEUxUHJ2UnhKNUdmMExCVnkwOUMrVDdvcVxudnMyQUVS\nRVVIT0djUTgyclpTZ2JvbUhlVGoraGV3d29pV01Sb01OUWNlNTVHMmFpcjVj\ndkdnPT1cbi0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tIiwidGxzX21v\nZGUiOlsidGxzdjEyIiwidGxzdjEzIl19LCJnb3Zlcm5vciI6eyJsaW1pdF9u\nZXR3b3JrIjpudWxsLCJsaW1pdF91c2VyIjpudWxsLCJxdW90YXNfZW5hYmxl\nZCI6ZmFsc2V9LCJodHRwX25vcHJveHkiOm51bGwsImh0dHBfcHJveHkiOm51\nbGwsImlkZW50aWNvbnNfaG9zdCI6ImRvdGNvbSIsImxkYXAiOm51bGwsImxp\nY2Vuc2UiOnsiY2x1c3Rlcl9zdXBwb3J0Ijp0cnVlLCJldmFsdWF0aW9uIjpm\nYWxzZSwiZXhwaXJlX2F0IjoiMjAyNS0wMS0wMVQyMzo1OTo1OS0wODowMCIs\nInBlcnBldHVhbCI6ZmFsc2UsInNlYXRzIjowLCJzc2hfYWxsb3dlZCI6dHJ1\nZSwic3VwcG9ydF9rZXkiOm51bGwsInVubGltaXRlZF9zZWF0aW5nIjp0cnVl\nfSwibG9hZF9iYWxhbmNlciI6bnVsbCwibWFuYWdlX2F1dGgiOnsibG9naW5f\nYXR0ZW1wdF9saW1pdCI6MTAsImxvZ2luX2F0dGVtcHRfbG9ja291dF9taW51\ndGVzIjoxMH0sIm1hcHBpbmciOnsiYXp1cmVfYXBwX2NsaWVudF9pZCI6bnVs\nbCwiYXp1cmVfYXBwX2NsaWVudF9zZWNyZXQiOm51bGwsImF6dXJlX21hcF9j\nbGllbnRfaWQiOm51bGwsImF6dXJlX3RlbmFudF9pZCI6bnVsbCwiYmFzZW1h\ncCI6bnVsbCwiY3NyZl9zZWNyZXQiOm51bGwsImVuYWJsZWQiOmZhbHNlfSwi\nbXlzcWwiOnsiYmFja3VwIjp7ImJpbmFyeSI6dHJ1ZX19LCJudHAiOm51bGws\nIm51bV9wYXJhbGxlbF9kYXRhYmFzZV9taWdyYXRpb25fd29ya2VyIjo0LCJw\nYWdlcyI6eyJidWlsZF90aW1lb3V0X21pbnV0ZXMiOjExLCJlbmFibGVkIjp0\ncnVlLCJoZWFkZXJfb3ZlcnJpZGUiOiIiLCJzeW5jX3RpbWVvdXRfbWludXRl\ncyI6MTB9LCJwcml2YXRlX2luc3RhbmNlIjp7ImF6dXJlX2Nsb3VkX2Vudmly\nb25tZW50IjoiIiwiYmlsbGluZyI6eyJmcmVlX3RyaWFsX2VuYWJsZWQiOmZh\nbHNlLCJsaWNlbnNldXNhZ2UiOnsibWV0ZXJfaWQiOiIifSwicGF2MiI6eyJr\nZXlfdmF1bHRfaWRlbnRpdHlfY2xpZW50X2lkIjoiIiwia2V5X3ZhdWx0X25h\nbWUiOiIiLCJxdWV1ZV9zdG9yYWdlX2FjY291bnRfbmFtZSI6IiIsInF1ZXVl\nX3N0b3JhZ2Vfc2FzX3Rva2VuX3NlY3JldF9uYW1lIjoiIiwidGFibGVfc3Rv\ncmFnZV9hY2NvdW50X25hbWUiOiIiLCJ0YWJsZV9zdG9yYWdlX3Nhc190b2tl\nbl9zZWNyZXRfbmFtZSI6IiJ9LCJyZXNvdXJjZV9ncm91cCI6IiIsInJlc291\ncmNlX25hbWUiOiIiLCJyZXNvdXJjZV9yZWdpb24iOiIiLCJzdWJzY3JpcHRp\nb25faWQiOiIifSwiZW5hYmxlZCI6ZmFsc2UsImVuY3J5cHRpb24iOnsiYmFj\na3VwIjp7ImRpc2tfZW5jcnlwdGlvbl9zZXQiOiIiLCJrZXkiOiIiLCJrZXlf\ndmF1bHQiOiIifSwicHJpbWFyeSI6eyJkaXNrX2VuY3J5cHRpb25fc2V0Ijoi\nIiwia2V5IjoiIiwia2V5X3ZhdWx0IjoiIn0sInJlcGxpY2EiOnsiZGlza19l\nbmNyeXB0aW9uX3NldCI6IiIsImtleSI6IiIsImtleV92YXVsdCI6IiJ9LCJy\nZXNvdXJjZV9ncm91cCI6IiIsInN1YnNjcmlwdGlvbl9pZCI6IiJ9LCJpZHBf\nY29uZmlndXJhdGlvbl9yZXF1aXJlZCI6ZmFsc2UsIm1lbyI6eyJhcHBfaWQi\nOiIiLCJjbGllbnRfc2VjcmV0IjoiIiwidGVuYW50X2lkIjoiIiwidXJsIjoi\nIn19LCJwcml2YXRlX21vZGUiOnRydWUsInB1YmxpY19wYWdlcyI6ZmFsc2Us\nInNhbWwiOm51bGwsInNlY3JldF9zY2FubmluZyI6eyJlbmFibGVkIjp0cnVl\nfSwic2lnbnVwX2VuYWJsZWQiOmZhbHNlLCJzbXRwIjp7ImFkZHJlc3MiOm51\nbGwsImF1dGhlbnRpY2F0aW9uIjpudWxsLCJkaXNjYXJkX3RvX25vcmVwbHlf\nYWRkcmVzcyI6ZmFsc2UsImRvbWFpbiI6bnVsbCwiZW5hYmxlZCI6ZmFsc2Us\nImVuZm9yY2VfdGxzX2F1dGgiOmZhbHNlLCJub3JlcGx5X2FkZHJlc3MiOm51\nbGwsInBhc3N3b3JkIjpudWxsLCJwb3J0IjowLCJzdXBwb3J0X2FkZHJlc3Mi\nOm51bGwsInN1cHBvcnRfYWRkcmVzc190eXBlIjpudWxsLCJ1c2VyX25hbWUi\nOm51bGwsInVzZXJuYW1lIjpudWxsfSwic25tcCI6bnVsbCwic3ViZG9tYWlu\nX2lzb2xhdGlvbiI6dHJ1ZSwic3lzbG9nIjp7ImNlcnQiOm51bGwsImVuYWJs\nZWQiOmZhbHNlLCJwcm90b2NvbF9uYW1lIjoidWRwIiwic2VydmVyIjpudWxs\nLCJ0bHNfZW5hYmxlZCI6ZmFsc2V9LCJ0aW1lem9uZSI6bnVsbCwidG9nZ2xl\nX2djbV9jbHVzdGVyX2NvbmZpZ192YWxpZGF0aW9uIjp0cnVlLCJ1c2VfcGFy\nYWxsZWxfZGF0YWJhc2VfbWlncmF0aW9ucyI6ZmFsc2V9Cg==\n" + } + }, + "recorded_at": "Tue, 28 May 2024 10:41:27 GMT" + } + ], + "recorded_with": "VCR 6.2.0" +} \ No newline at end of file diff --git a/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_start_configuration/start_a_ghe-config-apply.json b/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_start_configuration/start_a_ghe-config-apply.json new file mode 100644 index 000000000..3bb02df52 --- /dev/null +++ b/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_start_configuration/start_a_ghe-config-apply.json @@ -0,0 +1,72 @@ +{ + "http_interactions": [ + { + "request": { + "method": "post", + "uri": "<>/manage/v1/config/apply", + "body": { + "encoding": "UTF-8", + "base64_string": "" + }, + "headers": { + "User-Agent": [ + "Octokit Ruby Gem 8.1.0" + ], + "Authorization": [ + "Basic YXBpX2tleTpRMjBVcm45aWs=" + ], + "Content-Length": [ + "0" + ], + "Accept-Encoding": [ + "gzip;q=1.0,deflate;q=0.6,identity;q=0.3" + ], + "Accept": [ + "*/*" + ] + } + }, + "response": { + "status": { + "code": 200, + "message": "OK" + }, + "headers": { + "Content-Security-Policy": [ + "default-src 'none';" + ], + "Content-Type": [ + "application/json; charset=utf-8" + ], + "Server": [ + "GHES Manage" + ], + "Strict-Transport-Security": [ + "max-age=63072000; includeSubDomains; preload" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "DENY" + ], + "X-Xss-Protection": [ + "0" + ], + "Date": [ + "Tue, 28 May 2024 10:25:26 GMT" + ], + "Content-Length": [ + "22" + ] + }, + "body": { + "encoding": "UTF-8", + "base64_string": "eyJydW5faWQiOiI5ODI0ZjE2ZSJ9Cg==\n" + } + }, + "recorded_at": "Tue, 28 May 2024 10:25:26 GMT" + } + ], + "recorded_with": "VCR 6.2.0" +} \ No newline at end of file diff --git a/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_upload_license/upload_a_new_license.json b/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_upload_license/upload_a_new_license.json new file mode 100644 index 000000000..d5a6231a2 --- /dev/null +++ b/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_upload_license/upload_a_new_license.json @@ -0,0 +1,75 @@ +{ + "http_interactions": [ + { + "request": { + "method": "put", + "uri": "<>/manage/v1/config/license", + "body": { + "encoding": "ASCII-8BIT", + "base64_string": "anqDHd6gSAjXRl5IUvRNla+HL\nwkjkmQMlgLD1iUomBHeBrw/LsuW+DrfUqvTaBFdAYxN5e1grmlHaBREkVADd\nqD/Tp1x8Wwte2oFVTRr3Q2AMwe5JyFsp6st0Vx7Vn8SHcxustqiH1fciJLt8\nQTmMr6yYHsZ+2YPySFDjirAbSH9xSX+zKG25VqDmMWwsjBIjaQMGfbaLDygO\nDpRvo63BnoPq2B/uxLHAE3gEUZWP8ukN9cuBPB8YxmWGpsrxeQrrfPZl4cG9\nQPBhSW+0NMmo5H3BQl/z8WZtje8uBwShb6Sc2RyqMyH2GDin3XTW78JzWl9i\nuyxOvG3FHwRnA2txkuM+54ikgwWO6vKKJFoan1X8_LOLNOTREAL_/eZ3FOUm1RCXbDrK7DwY\nqftO+hhL0kFZIz+O/Dg/a/OpeCP3UPcEaNmpkZbfXqpMsIxSGi96pisMJl6M\nRNJ6ZyiFf5CqpliiwCn9I3w9NWIXJhlLzimVwzX705s6a9ML5\n72gA8iFY3THXfNt5l7WdmssXegborR+ITb8cwXDdAAFXIZBurX4uQUWcN+tB\n9W07iqmpR7UzmPPQhcNZX/gmDjnkfaXx9neyydM6rY1yWhzEZ14WJwJLIne0uqU90SeqKDSPwzaTMbEo2ItVUgDbbEqNf/tXU2ZKnnU68Aywt5bfjLOM8sV6\ndmZHUCx6ygqMpRnlJwnsW/ikq00hJsKHS0TSJq4EnDiZaCyZYwjR7eHn2uGP\n/ufqoXKDWIY6Wxr4pyLcauDFUBnq75lEn7nA9knoDHmgrBFCL9bQcM+/Wh+8\nZ7I1NG5XUubvWCH8ywLhm6a5ftPKPsQh5mDurB55+gUxatRqgXS9XnfxSnac\nwlP02RpRlxPKfbMZqVsO2KW2TYUGXTpFCyZYLCau1Uw/+qJ/8z1ugURLjzJI3j2x4I3v6Mc952\n0TcebG/ZvuTaKft6dP+ZW++86Oynnn3T6j8BDQotLS0tLS0tLS0tLS0tUnVi\neU11bHRpcGFydFBvc3QNCkNvbnRlbnQtRGlzcG9zaXRpb246IGZvcm0tZGF0\nYTsgbmFtZT0icGFzc3dvcmQiDQoNC\n" + }, + "headers": { + "User-Agent": [ + "Octokit Ruby Gem 8.1.0" + ], + "Content-Type": [ + "multipart/form-data; boundary=-----------RubyMultipartPost-e8412453628eb4b99f71583f2234ae4f" + ], + "Authorization": [ + "Basic YXBpX2tleTpRMjBVcm45aWs=" + ], + "Content-Length": [ + "17459" + ], + "Accept-Encoding": [ + "gzip;q=1.0,deflate;q=0.6,identity;q=0.3" + ], + "Accept": [ + "*/*" + ] + } + }, + "response": { + "status": { + "code": 201, + "message": "Created" + }, + "headers": { + "Content-Security-Policy": [ + "default-src 'none';" + ], + "Content-Type": [ + "application/json; charset=utf-8" + ], + "Server": [ + "GHES Manage" + ], + "Strict-Transport-Security": [ + "max-age=63072000; includeSubDomains; preload" + ], + "X-Content-Type-Options": [ + "nosniff" + ], + "X-Frame-Options": [ + "DENY" + ], + "X-Xss-Protection": [ + "0" + ], + "Date": [ + "Tue, 28 May 2024 10:16:58 GMT" + ], + "Content-Length": [ + "3" + ] + }, + "body": { + "encoding": "UTF-8", + "base64_string": "e30K\n" + } + }, + "recorded_at": "Tue, 28 May 2024 10:16:58 GMT" + } + ], + "recorded_with": "VCR 6.2.0" +} \ No newline at end of file diff --git a/spec/octokit/ghes_manage_client/ghes_manage_spec.rb b/spec/octokit/ghes_manage_client/ghes_manage_spec.rb index 3d38baf0e..fafb6a5e2 100644 --- a/spec/octokit/ghes_manage_client/ghes_manage_spec.rb +++ b/spec/octokit/ghes_manage_client/ghes_manage_spec.rb @@ -4,12 +4,15 @@ before do Octokit.reset! @manage_ghes = manage_ghes_client + @license = 'spec/fixtures/github-enterprise.ghl' end describe '.maintenance_mode', :vcr do it 'get maintenance mode' do @manage_ghes.maintenance_mode expect(@manage_ghes.last_response.status).to eq(200) + expect(@manage_ghes.last_response.body).to be_kind_of Array + expect(@manage_ghes.last_response.body.first['status']).to be_kind_of String assert_requested :get, github_manage_ghes_url('/manage/v1/maintenance') end end # .maintenance_mode @@ -18,14 +21,93 @@ it 'enable maintenance mode' do @manage_ghes.set_maintenance_mode(true) expect(@manage_ghes.last_response.status).to eq(200) - expect(@manage_ghes.last_response.body[0]['message']).to eq('maintenance mode enabled') + expect(@manage_ghes.last_response.body.first['message']).to eq('maintenance mode enabled') assert_requested :post, github_manage_ghes_url('/manage/v1/maintenance') end it 'disable maintenance mode' do @manage_ghes.set_maintenance_mode(false) expect(@manage_ghes.last_response.status).to eq(200) - expect(@manage_ghes.last_response.body[0]['message']).to eq('maintenance mode disabled') + expect(@manage_ghes.last_response.body.first['message']).to eq('maintenance mode disabled') assert_requested :post, github_manage_ghes_url('/manage/v1/maintenance') end end # .set_maintenance_mode + + describe '.upload_license', :vcr do + it 'upload a new license' do + @manage_ghes.upload_license(@license) + expect(@manage_ghes.last_response.status).to eq(201) + assert_requested :put, github_manage_ghes_url('/manage/v1/config/license') + end + end # .upload_license + + describe '.start_configuration', :vcr do + it 'start a ghe-config-apply' do + @manage_ghes.start_configuration + expect(@manage_ghes.last_response.status).to eq(200) + expect(@manage_ghes.last_response.body['run_id']).to be_kind_of String + assert_requested :post, github_manage_ghes_url('/manage/v1/config/apply') + end + end # .start_configuration + + describe '.config_status', :vcr do + it 'get ghe-config-apply status' do + @manage_ghes.config_status + expect(@manage_ghes.last_response.status).to eq(200) + expect(@manage_ghes.last_response.body['run_id']).to be_kind_of String + expect(@manage_ghes.last_response.body['nodes']).to be_kind_of Array + assert_requested :get, github_manage_ghes_url('/manage/v1/config/apply') + end + end # .config_status + + describe '.settings', :vcr do + it 'get settings' do + @manage_ghes.settings + expect(@manage_ghes.last_response.status).to eq(200) + expect(@manage_ghes.last_response.body).to be_kind_of Hash + expect(@manage_ghes.last_response.body['abuse_rate_limiting']['requests_per_minute']).to be_kind_of Integer + assert_requested :get, github_manage_ghes_url('/manage/v1/config/settings') + end + end # .settings + + describe '.edit_settings', :vcr do + it 'set settings' do + @manage_ghes.edit_settings({ 'abuse_rate_limiting' => { 'requests_per_minute' => 901 } }) + expect(@manage_ghes.last_response.status).to eq(204) + assert_requested :put, github_manage_ghes_url('/manage/v1/config/settings') + end + end # .edit_settings + + describe '.authorized_keys', :vcr do + it 'get authorized keys' do + @manage_ghes.authorized_keys + expect(@manage_ghes.last_response.status).to eq(200) + expect(@manage_ghes.last_response.body).to be_kind_of Array + expect(@manage_ghes.last_response.body.first['key']).to be_kind_of String + assert_requested :get, github_manage_ghes_url('/manage/v1/access/ssh') + end + end # .authorized_keys + + describe '.add_authorized_key', :vcr do + it 'adds a new authorized SSH keys (via a file path)' do + key = 'spec/fixtures/fake_key.pub' + @manage_ghes.add_authorized_key(key) + + expect(@manage_ghes.last_response.status).to eq(200) + expect(@manage_ghes.last_response.body.first['message']).to eq('SSH key added successfully') + + assert_requested :post, github_manage_ghes_url('/manage/v1/access/ssh') + end + end # .add_authorized_key + + describe '.remove_authorized_key', :vcr do + it 'delete an authorized SSH key (via a file path)' do + key = 'spec/fixtures/fake_key.pub' + @manage_ghes.remove_authorized_key(key) + + expect(@manage_ghes.last_response.status).to eq(200) + expect(@manage_ghes.last_response.body.first['message']).to eq('SSH key removed successfully') + + assert_requested :delete, github_manage_ghes_url('/manage/v1/access/ssh') + end + end # .remove_authorized_key end From 849b28cc54ebef3355b006a1127149bb595c6d0a Mon Sep 17 00:00:00 2001 From: alejndr0 Date: Thu, 30 May 2024 12:14:37 +0200 Subject: [PATCH 11/19] rubocop fixes --- lib/octokit/manage_ghes_client.rb | 6 +++--- spec/spec_helper.rb | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/octokit/manage_ghes_client.rb b/lib/octokit/manage_ghes_client.rb index 8570a93ad..f8ecaf6f1 100644 --- a/lib/octokit/manage_ghes_client.rb +++ b/lib/octokit/manage_ghes_client.rb @@ -49,9 +49,9 @@ def manage_ghes_endpoint=(value) # # @param value [String] Manage GHES API username def manage_ghes_username=(value) - reset_agent - @manage_ghes_username = value - end + reset_agent + @manage_ghes_username = value + end # Set Manage GHES API password # diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 477f62759..3b1dc992a 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -32,7 +32,7 @@ end require 'vcr' -VCR.configure do |c| +VCR.configure do |c| # rubocop:disable Metrics/BlockLength c.configure_rspec_metadata! c.filter_sensitive_data('') do test_github_login From f586f54b6fa09af58dfe2ff4a42faed118af30c5 Mon Sep 17 00:00:00 2001 From: alejndr0 Date: Thu, 30 May 2024 15:55:07 +0200 Subject: [PATCH 12/19] Fix basic auth for older version --- lib/octokit/manage_ghes_client/manage_ghes.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/octokit/manage_ghes_client/manage_ghes.rb b/lib/octokit/manage_ghes_client/manage_ghes.rb index 4a78437c9..d5f0c9476 100644 --- a/lib/octokit/manage_ghes_client/manage_ghes.rb +++ b/lib/octokit/manage_ghes_client/manage_ghes.rb @@ -159,7 +159,7 @@ def authenticated_client elsif basic_authenticated? username = @manage_ghes_username end - c.request :authorization, :basic, username, @manage_ghes_password + c.request(*FARADAY_BASIC_AUTH_KEYS, username, @manage_ghes_password) # Disabling SSL is essential for certain self-hosted Enterprise instances c.ssl[:verify] = false if connection_options[:ssl] && !connection_options[:ssl][:verify] From 7bc6dd50d9d82cd1ce1e025b8aaf34f9823846a2 Mon Sep 17 00:00:00 2001 From: alejndr0 Date: Mon, 3 Jun 2024 13:16:46 +0200 Subject: [PATCH 13/19] Align ghesmanage client with management console client --- lib/octokit/default.rb | 5 +++ lib/octokit/manage_ghes_client/manage_ghes.rb | 18 ++++----- .../_upload_license/upload_a_new_license.json | 39 ++++++------------- .../ghes_manage_client/ghes_manage_spec.rb | 4 +- 4 files changed, 28 insertions(+), 38 deletions(-) diff --git a/lib/octokit/default.rb b/lib/octokit/default.rb index ca2e2fb73..47bdf3a6c 100644 --- a/lib/octokit/default.rb +++ b/lib/octokit/default.rb @@ -12,6 +12,11 @@ rescue LoadError Octokit::Warnable.octokit_warn 'To use retry middleware with Faraday v2.0+, install `faraday-retry` gem' end + begin + require 'faraday/multipart' + rescue LoadError + Octokit::Warnable.octokit_warn 'To use retry middleware with Faraday v2.0+, install `faraday-multipart` gem' + end end module Octokit diff --git a/lib/octokit/manage_ghes_client/manage_ghes.rb b/lib/octokit/manage_ghes_client/manage_ghes.rb index d5f0c9476..806614a8e 100644 --- a/lib/octokit/manage_ghes_client/manage_ghes.rb +++ b/lib/octokit/manage_ghes_client/manage_ghes.rb @@ -9,7 +9,7 @@ class ManageGHESClient module ManageAPI # Get information about the maintenance status of the GHES instance # - # @return [Sawyer::Resource] The maintenance mode status + # @return [nil] def maintenance_mode conn = authenticated_client @@ -33,19 +33,19 @@ def set_maintenance_mode(enabled, options = {}) # # @param license [String] The path to your .ghl license file. # - # @see https://docs.github.com/en/enterprise-server@3.4/rest/enterprise-admin/management-console#create-a-github-license - # @return nil + # @return [nil] def upload_license(license) conn = authenticated_client conn.request :multipart params = {} params[:license] = Faraday::FilePart.new(license, 'binary') - @last_response = conn.put('/manage/v1/config/license', params, { 'Content-Type' => 'multipart/form-data' }) + params[:password] = @manage_ghes_password + @last_response = conn.post('/manage/v1/config/init', params, { 'Content-Type' => 'multipart/form-data' }) end # Start a configuration process. # - # @return nil + # @return [nil] def start_configuration conn = authenticated_client @last_response = conn.post('/manage/v1/config/apply') @@ -53,7 +53,7 @@ def start_configuration # Get information about the Enterprise installation # - # @return [Sawyer::Resource] The installation information + # @return [nil] def config_status conn = authenticated_client @last_response = conn.get('/manage/v1/config/apply') @@ -62,7 +62,7 @@ def config_status # Get information about the Enterprise installation # - # @return [Sawyer::Resource] The settings + # @return [nil] def settings conn = authenticated_client @last_response = conn.get('/manage/v1/config/settings') @@ -88,7 +88,7 @@ def authorized_keys # Add an authorized SSH keys on the Enterprise install # # @param key Either the file path to a key, a File handler to the key, or the contents of the key itself - # @return [Sawyer::Resource] An array of authorized SSH keys + # @return [nil] def add_authorized_key(key) conn = authenticated_client case key @@ -113,7 +113,7 @@ def add_authorized_key(key) # Removes an authorized SSH keys from the Enterprise install # # @param key Either the file path to a key, a File handler to the key, or the contents of the key itself - # @return [Sawyer::Resource] An array of authorized SSH keys + # @return [nil] def remove_authorized_key(key) conn = authenticated_client case key diff --git a/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_upload_license/upload_a_new_license.json b/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_upload_license/upload_a_new_license.json index d5a6231a2..4e6df5abf 100644 --- a/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_upload_license/upload_a_new_license.json +++ b/spec/cassettes/Octokit_ManageGHESClient_ManageAPI/_upload_license/upload_a_new_license.json @@ -2,24 +2,24 @@ "http_interactions": [ { "request": { - "method": "put", - "uri": "<>/manage/v1/config/license", + "method": "post", + "uri": "<>/manage/v1/config/init", "body": { "encoding": "ASCII-8BIT", - "base64_string": "anqDHd6gSAjXRl5IUvRNla+HL\nwkjkmQMlgLD1iUomBHeBrw/LsuW+DrfUqvTaBFdAYxN5e1grmlHaBREkVADd\nqD/Tp1x8Wwte2oFVTRr3Q2AMwe5JyFsp6st0Vx7Vn8SHcxustqiH1fciJLt8\nQTmMr6yYHsZ+2YPySFDjirAbSH9xSX+zKG25VqDmMWwsjBIjaQMGfbaLDygO\nDpRvo63BnoPq2B/uxLHAE3gEUZWP8ukN9cuBPB8YxmWGpsrxeQrrfPZl4cG9\nQPBhSW+0NMmo5H3BQl/z8WZtje8uBwShb6Sc2RyqMyH2GDin3XTW78JzWl9i\nuyxOvG3FHwRnA2txkuM+54ikgwWO6vKKJFoan1X8_LOLNOTREAL_/eZ3FOUm1RCXbDrK7DwY\nqftO+hhL0kFZIz+O/Dg/a/OpeCP3UPcEaNmpkZbfXqpMsIxSGi96pisMJl6M\nRNJ6ZyiFf5CqpliiwCn9I3w9NWIXJhlLzimVwzX705s6a9ML5\n72gA8iFY3THXfNt5l7WdmssXegborR+ITb8cwXDdAAFXIZBurX4uQUWcN+tB\n9W07iqmpR7UzmPPQhcNZX/gmDjnkfaXx9neyydM6rY1yWhzEZ14WJwJLIne0uqU90SeqKDSPwzaTMbEo2ItVUgDbbEqNf/tXU2ZKnnU68Aywt5bfjLOM8sV6\ndmZHUCx6ygqMpRnlJwnsW/ikq00hJsKHS0TSJq4EnDiZaCyZYwjR7eHn2uGP\n/ufqoXKDWIY6Wxr4pyLcauDFUBnq75lEn7nA9knoDHmgrBFCL9bQcM+/Wh+8\nZ7I1NG5XUubvWCH8ywLhm6a5ftPKPsQh5mDurB55+gUxatRqgXS9XnfxSnac\nwlP02RpRlxPKfbMZqVsO2KW2TYUGXTpFCyZYLCau1Uw/+qJ/8z1ugURLjzJI3j2x4I3v6Mc952\n0TcebG/ZvuTaKft6dP+ZW++86Oynnn3T6j8BDQotLS0tLS0tLS0tLS0tUnVi\neU11bHRpcGFydFBvc3QNCkNvbnRlbnQtRGlzcG9zaXRpb246IGZvcm0tZGF0\nYTsgbmFtZT0icGFzc3dvcmQiDQoNC\n" + "base64_string": "anqDHd6gSAjXRl5IUvRNla+HL\nwkjkmQMlgLD1iUomBHeBrw/LsuW+DrfUqvTaBFdAYxN5e1grmlHaBREkVADd\nqD/Tp1x8Wwte2oFVTRr3Q2AMwe5JyFsp6st0Vx7Vn8SHcxustqiH1fciJLt8\nQTmMr6yYHsZ+2YPySFDjirAbSH9xSX+zKG25VqDmMWwsjBIjaQMGfbaLDygO\nDpRvo63BnoPq2B/uxLHAE3gEUZWP8ukN9cuBPB8YxmWGpsrxeQrrfPZl4cG9\nQPBhSW+0NMmo5H3BQl/z8WZtje8uBwShb6Sc2RyqMyH2GDin3XTW78JzWl9i\nuyxOvG3FHwRnA2txkuM+54ikgwWO6vKKJFoan1X8_LOLNOTREAL_/eZ3FOUm1RCXbDrK7DwY\nqftO+hhL0kFZIz+O/Dg/a/OpeCP3UPcEaNmpkZbfXqpMsIxSGi96pisMJl6M\nRNJ6ZyiFf5CqpliiwCn9I3w9NWIXJhlLzimVwzX705s6a9ML5\n72gA8iFY3THXfNt5l7WdmssXegborR+ITb8cwXDdAAFXIZBurX4uQUWcN+tB\n9W07iqmpR7UzmPPQhcNZX/gmDjnkfaXx9neyydM6rY1yWhzEZ14WJwJLIne0uqU90SeqKDSPwzaTMbEo2ItVUgDbbEqNf/tXU2ZKnnU68Aywt5bfjLOM8sV6\ndmZHUCx6ygqMpRnlJwnsW/ikq00hJsKHS0TSJq4EnDiZaCyZYwjR7eHn2uGP\n/ufqoXKDWIY6Wxr4pyLcauDFUBnq75lEn7nA9knoDHmgrBFCL9bQcM+/Wh+8\nZ7I1NG5XUubvWCH8ywLhm6a5ftPKPsQh5mDurB55+gUxatRqgXS9XnfxSnac\nwlP02RpRlxPKfbMZqVsO2KW2TYUGXTpFCyZYLCau1Uw/+qJ/8z1ugURLjzJI3j2x4I3v6Mc952\n0TcebG/ZvuTaKft6dP+ZW++86Oynnn3T6j8BDQotLS0tLS0tLS0tLS0tUnVi\neU11bHRpcGFydFBvc3QNCkNvbnRlbnQtRGlzcG9zaXRpb246IGZvcm0tZGF0\nYTsgbmFtZT0icGFzc3dvcmQiDQoNC\n\n" }, "headers": { "User-Agent": [ "Octokit Ruby Gem 8.1.0" ], "Content-Type": [ - "multipart/form-data; boundary=-----------RubyMultipartPost-e8412453628eb4b99f71583f2234ae4f" + "multipart/form-data; boundary=-----------RubyMultipartPost-2cfc1d28d56dda99e4bebdcded8c4f41" ], "Authorization": [ "Basic YXBpX2tleTpRMjBVcm45aWs=" ], "Content-Length": [ - "17459" + "17583" ], "Accept-Encoding": [ "gzip;q=1.0,deflate;q=0.6,identity;q=0.3" @@ -31,36 +31,21 @@ }, "response": { "status": { - "code": 201, - "message": "Created" + "code": 202, + "message": "Accepted" }, "headers": { - "Content-Security-Policy": [ - "default-src 'none';" - ], "Content-Type": [ "application/json; charset=utf-8" ], - "Server": [ - "GHES Manage" - ], - "Strict-Transport-Security": [ - "max-age=63072000; includeSubDomains; preload" - ], - "X-Content-Type-Options": [ - "nosniff" - ], - "X-Frame-Options": [ - "DENY" - ], - "X-Xss-Protection": [ - "0" - ], "Date": [ - "Tue, 28 May 2024 10:16:58 GMT" + "Mon, 03 Jun 2024 11:12:05 GMT" ], "Content-Length": [ "3" + ], + "X-Frame-Options": [ + "DENY" ] }, "body": { @@ -68,7 +53,7 @@ "base64_string": "e30K\n" } }, - "recorded_at": "Tue, 28 May 2024 10:16:58 GMT" + "recorded_at": "Mon, 03 Jun 2024 11:12:05 GMT" } ], "recorded_with": "VCR 6.2.0" diff --git a/spec/octokit/ghes_manage_client/ghes_manage_spec.rb b/spec/octokit/ghes_manage_client/ghes_manage_spec.rb index fafb6a5e2..4cbf3fac0 100644 --- a/spec/octokit/ghes_manage_client/ghes_manage_spec.rb +++ b/spec/octokit/ghes_manage_client/ghes_manage_spec.rb @@ -35,8 +35,8 @@ describe '.upload_license', :vcr do it 'upload a new license' do @manage_ghes.upload_license(@license) - expect(@manage_ghes.last_response.status).to eq(201) - assert_requested :put, github_manage_ghes_url('/manage/v1/config/license') + expect(@manage_ghes.last_response.status).to eq(202) + assert_requested :post, github_manage_ghes_url('/manage/v1/config/init') end end # .upload_license From fc842485ecab9b269e9cad42302e02599692df02 Mon Sep 17 00:00:00 2001 From: alejndr0 Date: Mon, 3 Jun 2024 16:07:22 +0200 Subject: [PATCH 14/19] add deprecation warnings --- .../management_console.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/octokit/enterprise_management_console_client/management_console.rb b/lib/octokit/enterprise_management_console_client/management_console.rb index f267ee58c..6ff70926d 100644 --- a/lib/octokit/enterprise_management_console_client/management_console.rb +++ b/lib/octokit/enterprise_management_console_client/management_console.rb @@ -14,6 +14,7 @@ module ManagementConsole # @see https://docs.github.com/en/enterprise-server@3.4/rest/enterprise-admin/management-console#create-a-github-license # @return nil def upload_license(license, settings = nil) + octokit_warn('The Management Console API will be deprecated in GitHub Enterprise Server 3.14.0, please use the ManageGHES client instead.') conn = faraday_configuration params = {} @@ -28,6 +29,7 @@ def upload_license(license, settings = nil) # # @return nil def start_configuration + octokit_warn('The Management Console API will be deprecated in GitHub Enterprise Server 3.14.0, please use the ManageGHES client instead.') post '/setup/api/configure', password_hash end @@ -37,6 +39,7 @@ def start_configuration # # @return nil def upgrade(license) + octokit_warn('The Management Console API will be deprecated in GitHub Enterprise Server 3.14.0, please use the ManageGHES client instead.') conn = faraday_configuration params = {} @@ -49,6 +52,7 @@ def upgrade(license) # # @return [Sawyer::Resource] The installation information def config_status + octokit_warn('The Management Console API will be deprecated in GitHub Enterprise Server 3.14.0, please use the ManageGHES client instead.') get '/setup/api/configcheck', password_hash end alias config_check config_status @@ -57,6 +61,7 @@ def config_status # # @return [Sawyer::Resource] The settings def settings + octokit_warn('The Management Console API will be deprecated in GitHub Enterprise Server 3.14.0, please use the ManageGHES client instead.') get '/setup/api/settings', password_hash end alias get_settings settings @@ -67,6 +72,7 @@ def settings # # @return [nil] def edit_settings(settings) + octokit_warn('The Management Console API will be deprecated in GitHub Enterprise Server 3.14.0, please use the ManageGHES client instead.') queries = password_hash queries[:query][:settings] = settings.to_json.to_s put '/setup/api/settings', queries @@ -76,6 +82,7 @@ def edit_settings(settings) # # @return [Sawyer::Resource] The maintenance status def maintenance_status + octokit_warn('The Management Console API will be deprecated in GitHub Enterprise Server 3.14.0, please use the ManageGHES client instead.') get '/setup/api/maintenance', password_hash end alias get_maintenance_status maintenance_status @@ -85,6 +92,7 @@ def maintenance_status # @param maintenance [Hash] A hash configuration of the maintenance settings # @return [nil] def set_maintenance_status(maintenance) + octokit_warn('The Management Console API will be deprecated in GitHub Enterprise Server 3.14.0, please use the ManageGHES client instead.') queries = password_hash queries[:query][:maintenance] = maintenance.to_json.to_s post '/setup/api/maintenance', queries @@ -95,6 +103,7 @@ def set_maintenance_status(maintenance) # # @return [Sawyer::Resource] An array of authorized SSH keys def authorized_keys + octokit_warn('The Management Console API will be deprecated in GitHub Enterprise Server 3.14.0, please use the ManageGHES client instead.') get '/setup/api/settings/authorized-keys', password_hash end alias get_authorized_keys authorized_keys @@ -104,6 +113,7 @@ def authorized_keys # @param key Either the file path to a key, a File handler to the key, or the contents of the key itself # @return [Sawyer::Resource] An array of authorized SSH keys def add_authorized_key(key) + octokit_warn('The Management Console API will be deprecated in GitHub Enterprise Server 3.14.0, please use the ManageGHES client instead.') queries = password_hash case key when String @@ -128,6 +138,7 @@ def add_authorized_key(key) # @param key Either the file path to a key, a File handler to the key, or the contents of the key itself # @return [Sawyer::Resource] An array of authorized SSH keys def remove_authorized_key(key) + octokit_warn('The Management Console API will be deprecated in GitHub Enterprise Server 3.14.0, please use the ManageGHES client instead.') queries = password_hash case key when String From 57761db48e8e03d089866aebce386ff207b265f4 Mon Sep 17 00:00:00 2001 From: alejndr0 Date: Wed, 5 Jun 2024 08:21:00 +0200 Subject: [PATCH 15/19] Update lib/octokit/default.rb Co-authored-by: Nick Floyd <139819+nickfloyd@users.noreply.github.com> --- lib/octokit/default.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/octokit/default.rb b/lib/octokit/default.rb index 47bdf3a6c..35eba066a 100644 --- a/lib/octokit/default.rb +++ b/lib/octokit/default.rb @@ -15,7 +15,7 @@ begin require 'faraday/multipart' rescue LoadError - Octokit::Warnable.octokit_warn 'To use retry middleware with Faraday v2.0+, install `faraday-multipart` gem' + Octokit::Warnable.octokit_warn 'To use multipart middleware with Faraday v2.0+, install `faraday-multipart` gem; note: this is used by the ManageGHES client for uploading licenses' end end From 894794eb3b5b8b5222f2303e04a3f2d2fc78f5df Mon Sep 17 00:00:00 2001 From: alejndr0 Date: Fri, 7 Jun 2024 11:12:25 +0200 Subject: [PATCH 16/19] create error 410 --- lib/octokit/error.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/octokit/error.rb b/lib/octokit/error.rb index f607bf02c..4ef40f75c 100644 --- a/lib/octokit/error.rb +++ b/lib/octokit/error.rb @@ -23,6 +23,7 @@ def self.from_response(response) when 405 then Octokit::MethodNotAllowed when 406 then Octokit::NotAcceptable when 409 then Octokit::Conflict + when 410 then Octokit::Deprecated when 415 then Octokit::UnsupportedMediaType when 422 then error_for_422(body) when 451 then Octokit::UnavailableForLegalReasons @@ -110,6 +111,10 @@ def self.error_for_404(body) end end + def self.error_for_410(body) + Octokit::Gone + end + # Return most appropriate error for 422 HTTP status code # @private # rubocop:disable Naming/VariableNumber @@ -317,6 +322,9 @@ class NotAcceptable < ClientError; end # Raised when GitHub returns a 409 HTTP status code class Conflict < ClientError; end + # Raised when GHES Manage return a 410 HTTP status code + class Deprecated < ClientError; end + # Raised when GitHub returns a 414 HTTP status code class UnsupportedMediaType < ClientError; end From 2a79e2c1d98408c0535fba0fd23abd9a28fd9831 Mon Sep 17 00:00:00 2001 From: alejndr0 Date: Mon, 10 Jun 2024 15:42:24 +0200 Subject: [PATCH 17/19] remove unused method --- lib/octokit/error.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/octokit/error.rb b/lib/octokit/error.rb index 4ef40f75c..ec94c3ebd 100644 --- a/lib/octokit/error.rb +++ b/lib/octokit/error.rb @@ -111,10 +111,6 @@ def self.error_for_404(body) end end - def self.error_for_410(body) - Octokit::Gone - end - # Return most appropriate error for 422 HTTP status code # @private # rubocop:disable Naming/VariableNumber From 9ed27c68c3cb59fcc400fea5ec773df2c0b65b59 Mon Sep 17 00:00:00 2001 From: alejndr0 Date: Mon, 10 Jun 2024 15:56:40 +0200 Subject: [PATCH 18/19] disable Metrics/CyclomaticComplexity check --- lib/octokit/error.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/octokit/error.rb b/lib/octokit/error.rb index ec94c3ebd..2430d472d 100644 --- a/lib/octokit/error.rb +++ b/lib/octokit/error.rb @@ -10,6 +10,7 @@ class Error < StandardError # # @param [Hash] response HTTP response # @return [Octokit::Error] + # rubocop:disable Metrics/CyclomaticComplexity def self.from_response(response) status = response[:status].to_i body = response[:body].to_s From e11782bdd3b40f56d2582600659240a3d7e8a5c5 Mon Sep 17 00:00:00 2001 From: alejndr0 Date: Mon, 10 Jun 2024 16:10:21 +0200 Subject: [PATCH 19/19] enable check --- lib/octokit/error.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/octokit/error.rb b/lib/octokit/error.rb index 2430d472d..114ba37f4 100644 --- a/lib/octokit/error.rb +++ b/lib/octokit/error.rb @@ -38,6 +38,7 @@ def self.from_response(response) klass.new(response) end end + # rubocop:enable Metrics/CyclomaticComplexity def build_error_context if RATE_LIMITED_ERRORS.include?(self.class)