From 575584bce0172b4c16ede27c304892fa4879bda9 Mon Sep 17 00:00:00 2001 From: oleghasjanov Date: Fri, 6 Feb 2026 13:14:04 +0200 Subject: [PATCH 1/6] added mock data for aws staging --- db/seeds_mock.rb | 201 +++++++++++++++++++++++++++++++++++++++++ db/structure.sql | 23 +++-- lib/tasks/db_mock.rake | 8 ++ 3 files changed, 225 insertions(+), 7 deletions(-) create mode 100644 db/seeds_mock.rb create mode 100644 lib/tasks/db_mock.rake diff --git a/db/seeds_mock.rb b/db/seeds_mock.rb new file mode 100644 index 0000000000..32909bbf5d --- /dev/null +++ b/db/seeds_mock.rb @@ -0,0 +1,201 @@ +# frozen_string_literal: true + +# Valid Estonian ID code generator (simplistic) +def generate_ident(sex: 'm', birth_date: '900101') + # Sex: 1/3/5 for male (1800, 1900, 2000), 2/4/6 for female + century_sex = sex == 'm' ? '3' : '4' + + # Basic body + body = "#{century_sex}#{birth_date}001" + + # Checksum calculation + weights1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 1] + weights2 = [3, 4, 5, 6, 7, 8, 9, 1, 2, 3] + + chars = body.chars.map(&:to_i) + sum = chars.each_with_index.sum { |c, i| c * weights1[i] } + mod = sum % 11 + + if mod == 10 + sum = chars.each_with_index.sum { |c, i| c * weights2[i] } + mod = sum % 11 + mod = 0 if mod == 10 + end + + "#{body}#{mod}" +end + +def generate_phone + "+372.5#{rand(10_000_000..99_999_999)}" +end + +def generate_email(first, last) + safe_first = first.downcase.gsub(/[^a-z0-9]/, '') + safe_last = last.downcase.gsub(/[^a-z0-9]/, '') + "#{safe_first}.#{safe_last}+mock@example.com" +end + +def generate_random_string(length = 8) + ('a'..'z').to_a.sample(length).join +end + +puts "Starting Mock Data Generation..." + +ActiveRecord::Base.transaction do + # Cleaning up old mock data if necessary (comment out if you want to keep old data) + # puts "Cleaning up old mock data..." + # Domain.destroy_all + # Contact.destroy_all + # Registrar.where("code LIKE 'MOCK%'").destroy_all + # ... + + # 1. Ensure Zone exists + zone_origin = 'ee' + zone = DNS::Zone.find_or_create_by!(origin: zone_origin) do |z| + z.ttl = 86400 + z.refresh = 3600 + z.retry = 900 + z.expire = 604800 + z.minimum_ttl = 3600 + z.email = 'hostmaster.ee' + z.master_nameserver = 'ns1.tld.ee' + end + puts "Zone ensured: #{zone.origin}" + + # 2. Ensure Prices exist + ['create', 'renew'].each do |op| + Billing::Price.durations.each do |dur_name, dur_val| + Billing::Price.find_or_create_by!( + zone: zone, + operation_category: op, + duration: dur_val + ) do |p| + p.price = Money.new(1000, 'EUR') # 10.00 EUR + p.valid_from = Time.zone.now.beginning_of_year + end + end + end + puts "Prices ensured for #{zone.origin}" + + # 3. Create Multiple Registrars + 3.times do |reg_i| + reg_code = "MOCKREG#{reg_i+1}" + puts "Processing Registrar: #{reg_code}..." + + registrar = Registrar.find_or_create_by!(code: reg_code) do |r| + r.name = "Mock Registrar #{reg_i+1} Ltd" + r.reg_no = "1234#{reg_i+1}000" + r.email = "support@mock#{reg_i+1}.test" + r.phone = "+372.5555#{reg_i+1}00" + r.address_street = "Mock St #{reg_i+1}" + r.address_city = "Tallinn" + r.address_zip = "10111" + r.address_country_code = "EE" + r.accounting_customer_code = "MOCK#{reg_i+1}" + r.language = "en" + r.reference_no = Billing::ReferenceNo.generate(owner: r) rescue "123456#{reg_i+1}" + end + + # Ensure account + registrar.accounts.find_or_create_by!(account_type: Account::CASH, currency: 'EUR') + puts " Registrar ensured: #{registrar.name}" + + # 4. Create API User for Registrar + api_username = "api_#{reg_code.downcase}" + api_user = ApiUser.find_or_create_by!(username: api_username) do |u| + u.plain_text_password = "password123" + u.registrar = registrar + u.roles = ['epp', 'billing'] + u.active = true + u.identity_code = generate_ident(sex: 'm', birth_date: "8#{reg_i}0101") + end + puts " API User ensured: #{api_user.username}" + + # 5. Create Contacts (Registrants) for THIS Registrar + contacts = [] + + # create some ORG contacts + 5.times do |i| + code = "#{reg_code}:ORG:#{i+1}" + name = "Mock Company #{reg_i+1}-#{i+1} OÜ" + + contact = Registrant.find_or_create_by!(code: code) do |c| + c.name = name + c.email = generate_email("info", "company#{reg_i+1}.#{i+1}") + c.phone = generate_phone + c.registrar = registrar + c.country_code = 'EE' + c.city = 'Tallinn' + c.street = "Business St #{i+1}" + c.zip = '10111' + c.ident_country_code = 'EE' + c.ident_type = 'org' + c.ident = rand(10000000..99999999).to_s + end + contacts << contact + end + + # create some PRIV contacts + 5.times do |i| + code = "#{reg_code}:PRIV:#{i+1}" + first_name = "Mockperson#{reg_i+1}" + last_name = "Lastname#{i+1}" + ident = generate_ident(sex: i.even? ? 'm' : 'f', birth_date: "9#{i}0101") + + contact = Registrant.find_or_create_by!(code: code) do |c| + c.name = "#{first_name} #{last_name}" + c.email = generate_email(first_name, last_name) + c.phone = generate_phone + c.registrar = registrar + c.country_code = 'EE' + c.city = 'Tartu' + c.street = "Private St #{i+1}" + c.zip = '51001' + c.ident_country_code = 'EE' + c.ident_type = 'priv' + c.ident = ident + end + contacts << contact + end + puts " Contacts created/found: #{contacts.count}" + + # 6. Create Domains for THIS Registrar and its Contacts + 10.times do |i| + domain_name = "mock#{reg_i+1}-#{i+1}.#{zone_origin}" + registrant = contacts.sample + + # Create Domain + domain = Domain.find_or_create_by!(name: domain_name) do |d| + d.registrar = registrar + d.registrant = registrant + d.period = 1 + d.period_unit = 'y' + d.valid_to = 1.year.from_now + + # Add Admin Contacts (required) + d.admin_contacts << registrant + + # Add Tech Contacts (required usually) + d.tech_contacts << registrant + + # Add Nameservers (min 2 required) + 2.times do |j| + ns_hostname = "ns#{j+1}.#{domain_name}" + d.nameservers.build( + hostname: ns_hostname, + ipv4: ["192.0.2.#{i*10+j}"], + ipv6: ["2001:db8::#{i*10+j}"] + ) + end + end + + if domain.persisted? + puts " Ensured domain: #{domain.name}" + else + puts " Failed to ensure domain #{domain_name}: #{domain.errors.full_messages.join(', ')}" + end + end + end +end + +puts "Mock Data Generation Completed!" diff --git a/db/structure.sql b/db/structure.sql index 9e5cb7ad47..ce3fd8678d 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -1,3 +1,8 @@ +\restrict OgpBVS4LcDZVV6fZTwmnzAAWL70pwHISsUhjW2gqrf2CNdzHNtVCcfzYehS3JFu + +-- Dumped from database version 13.4 (Debian 13.4-4.pgdg110+1) +-- Dumped by pg_dump version 13.22 (Debian 13.22-0+deb11u1) + SET statement_timeout = 0; SET lock_timeout = 0; SET idle_in_transaction_session_timeout = 0; @@ -2642,7 +2647,8 @@ CREATE TABLE public.registrars ( settings jsonb DEFAULT '{}'::jsonb NOT NULL, legaldoc_optout boolean DEFAULT false NOT NULL, legaldoc_optout_comment text, - email_history character varying + email_history character varying, + accept_pdf_invoices boolean DEFAULT true ); @@ -5280,6 +5286,8 @@ ALTER TABLE ONLY public.users -- PostgreSQL database dump complete -- +\unrestrict OgpBVS4LcDZVV6fZTwmnzAAWL70pwHISsUhjW2gqrf2CNdzHNtVCcfzYehS3JFu + SET search_path TO "$user", public; INSERT INTO "schema_migrations" (version) VALUES @@ -5768,10 +5776,13 @@ INSERT INTO "schema_migrations" (version) VALUES ('20230707084741'), ('20230710120154'), ('20230711083811'), +('20240722085530'), +('20240723110208'), ('20240816091049'), ('20240816092636'), ('20240924103554'), ('20241015071505'), +('20241022121525'), ('20241030095636'), ('20241104104620'), ('20241112093540'), @@ -5780,13 +5791,11 @@ INSERT INTO "schema_migrations" (version) VALUES ('20241206085817'), ('20250204094550'), ('20250219102811'), -('20250313122119'), -('20250319104749'), ('20250310133151'), +('20250313122119'), ('20250314133357'), -('20240722085530'), -('20240723110208'), -('20241022121525'), -('20250627084536'); +('20250319104749'), +('20250627084536'), +('20251230104312'); diff --git a/lib/tasks/db_mock.rake b/lib/tasks/db_mock.rake new file mode 100644 index 0000000000..33b1a73e6e --- /dev/null +++ b/lib/tasks/db_mock.rake @@ -0,0 +1,8 @@ +namespace :db do + namespace :seed do + desc "Load the mock data from db/seeds_mock.rb" + task mock: :environment do + load(Rails.root.join('db', 'seeds_mock.rb')) + end + end +end From fe61d877c868ce81a06a937282c8d4672d453dea Mon Sep 17 00:00:00 2001 From: oleghasjanov Date: Fri, 6 Feb 2026 14:27:58 +0200 Subject: [PATCH 2/6] fixed dockerfile staging --- Dockerfile.staging | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Dockerfile.staging b/Dockerfile.staging index 1b78aaf093..ba7ed131e2 100644 --- a/Dockerfile.staging +++ b/Dockerfile.staging @@ -57,11 +57,13 @@ RUN gem install bundler && \ # Copy application code COPY . . -# Precompile assets in build stage (Node.js 14 is available here) -# Use dummy SECRET_KEY_BASE for asset precompilation only -ARG SECRET_KEY_BASE=dummy_key_for_assets_precompilation -ENV SECRET_KEY_BASE=${SECRET_KEY_BASE} -RUN RAILS_ENV=staging bundle exec rails assets:precompile && \ +# Copy sample config for asset precompilation (real values come from env at runtime) +RUN cp config/application.yml.sample config/application.yml && \ + cp config/database.yml.sample config/database.yml + +# Precompile assets +RUN RAILS_ENV=staging SECRET_KEY_BASE=dummy_for_assets \ + bundle exec rails assets:precompile && \ echo "Assets precompiled successfully for staging" && \ ls -la public/assets/ | head -20 @@ -124,4 +126,4 @@ USER 1000:1000 EXPOSE 3000 # Start the application -CMD ["bundle", "exec", "rails", "server", "-b", "0.0.0.0"] +CMD ["bundle", "exec", "rails", "server", "-b", "0.0.0.0"] \ No newline at end of file From 90a7a2c2bca897ed5e0956b882336b8eeb11a029 Mon Sep 17 00:00:00 2001 From: oleghasjanov Date: Fri, 6 Feb 2026 14:45:36 +0200 Subject: [PATCH 3/6] added copy command for copy application.yml.sample to application.yml --- Dockerfile.staging | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Dockerfile.staging b/Dockerfile.staging index ba7ed131e2..45ca3af535 100644 --- a/Dockerfile.staging +++ b/Dockerfile.staging @@ -122,6 +122,8 @@ USER 1000:1000 # Entrypoint prepares the database. # ENTRYPOINT ["/opt/webapps/app/bin/docker-entrypoint"] +COPY config/application.yml.sample config/application.yml + # Expose port EXPOSE 3000 From b9d80d2ffda1cd2b4a2bd56693af35af27e5ffac Mon Sep 17 00:00:00 2001 From: oleghasjanov Date: Fri, 6 Feb 2026 15:05:33 +0200 Subject: [PATCH 4/6] added mails placeholders to dockerfile staging --- Dockerfile.staging | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Dockerfile.staging b/Dockerfile.staging index 45ca3af535..07e0f07838 100644 --- a/Dockerfile.staging +++ b/Dockerfile.staging @@ -63,6 +63,8 @@ RUN cp config/application.yml.sample config/application.yml && \ # Precompile assets RUN RAILS_ENV=staging SECRET_KEY_BASE=dummy_for_assets \ + ACTION_MAILER_DEFAULT_HOST=dummy.host \ + ACTION_MAILER_DEFAULT_FROM=dummy@example.com \ bundle exec rails assets:precompile && \ echo "Assets precompiled successfully for staging" && \ ls -la public/assets/ | head -20 From 3c372d78277d9ed357adff746dfc67b36f403b12 Mon Sep 17 00:00:00 2001 From: oleghasjanov Date: Fri, 6 Feb 2026 16:17:02 +0200 Subject: [PATCH 5/6] fixed application.yml sample and database.yml.sample --- config/application.yml.sample | 14 ++++++++++++-- config/database.yml.sample | 9 +++++++-- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/config/application.yml.sample b/config/application.yml.sample index c8e8ecbd01..6abbbcbdfb 100644 --- a/config/application.yml.sample +++ b/config/application.yml.sample @@ -160,9 +160,9 @@ release_domains_to_auction: 'true' auction_api_allowed_ips: '' # 192.0.2.0, 192.0.2.1 action_mailer_default_protocol: # default: http -action_mailer_default_host: +action_mailer_default_host: 'registry.staging' action_mailer_default_port: # default: no port (80) -action_mailer_default_from: # no-reply@example.com +action_mailer_default_from: 'no-reply@registry.staging' action_mailer_force_delete_from: # `From` header for `DomainDeleteMailer#forced` email lhv_p12_keystore: @@ -273,3 +273,13 @@ ident_service_client_secret: 321 business_registry_allowed_origins: "http://registry.test,https://registry.test" business_registry_allowed_ips: "127.0.0.1,0.0.0.0,192.168.65.1" business_registry_api_tokens: "token1,token2" + +staging: + action_mailer_default_host: 'registry.staging.test' + action_mailer_default_from: 'no-reply@registry.staging.test' + action_mailer_force_delete_from: 'legal@registry.staging.test' + +staging: + action_mailer_default_host: 'registry.staging.test' + action_mailer_default_from: 'no-reply@registry.staging.test' + action_mailer_force_delete_from: 'legal@registry.staging.test' diff --git a/config/database.yml.sample b/config/database.yml.sample index 54c01fa6b6..621c0ac965 100644 --- a/config/database.yml.sample +++ b/config/database.yml.sample @@ -16,8 +16,13 @@ default: &default # staging: - <<: *default - database: registry_staging + primary: + <<: *default + database: registry_staging + primary_replica: + <<: *default + database: registry_staging + replica: true demo: <<: *default From 7d70717a3972cdfb0adc12a14bbd25860a67343b Mon Sep 17 00:00:00 2001 From: oleghasjanov Date: Tue, 10 Feb 2026 14:02:31 +0200 Subject: [PATCH 6/6] added master branch in pipeline --- .github/workflows/deploy-pr-staging.yml | 33 ++++++++++++++++++++----- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/.github/workflows/deploy-pr-staging.yml b/.github/workflows/deploy-pr-staging.yml index c812d5b437..46174f9e46 100644 --- a/.github/workflows/deploy-pr-staging.yml +++ b/.github/workflows/deploy-pr-staging.yml @@ -1,11 +1,19 @@ -name: 01 PR Deploy to Staging (Kubernetes) +name: 01 Deploy to Staging (Kubernetes) on: workflow_dispatch: inputs: - pr_number: - description: 'Number of PR to deploy (only digits, e.g., 2889)' + deploy_target: + description: 'What to deploy' required: true + type: choice + options: + - pr + - master + default: pr + pr_number: + description: 'Number of PR to deploy (only digits, e.g., 2889). Required only for PR deploy.' + required: false type: string permissions: @@ -25,10 +33,17 @@ jobs: # environment: staging steps: + - name: āœ… Validate inputs + run: | + if [[ "${{ inputs.deploy_target }}" == "pr" && -z "${{ inputs.pr_number }}" ]]; then + echo "::error::PR number is required when deploy target is 'pr'" + exit 1 + fi + - name: ā¬‡ļø Checkout application code uses: actions/checkout@v4 with: - ref: refs/pull/${{ github.event.inputs.pr_number }}/merge + ref: ${{ inputs.deploy_target == 'master' && 'master' || format('refs/pull/{0}/merge', inputs.pr_number) }} - name: šŸ”‘ Configure AWS Credentials (for ECR and EKS) uses: aws-actions/configure-aws-credentials@v4 @@ -39,7 +54,13 @@ jobs: - name: šŸ› ļø Build and Tag Docker image id: docker_build run: | - TAG="pr-${{ github.event.inputs.pr_number }}" + if [[ "${{ inputs.deploy_target }}" == "master" ]]; then + SHORT_SHA=$(git rev-parse --short HEAD) + TAG="master-${SHORT_SHA}" + else + TAG="pr-${{ inputs.pr_number }}" + fi + echo "IMAGE_TAG=$TAG" >> $GITHUB_OUTPUT docker build --no-cache --platform linux/amd64 -f Dockerfile.staging \ @@ -77,6 +98,6 @@ jobs: "app_name": "${{ env.APP_NAME }}", "image_tag": "${{ steps.docker_build.outputs.IMAGE_TAG }}", "namespace": "${{ env.APP_NAME }}", - "pr_number": "${{ inputs.pr_number }}" + "pr_number": "${{ inputs.deploy_target == 'master' && '0' || inputs.pr_number }}" }