From b61f988fd5faaf9a7b88d6c6cae1bc02783e2927 Mon Sep 17 00:00:00 2001 From: Ben McIlwain Date: Thu, 27 Aug 2026 20:55:53 -0400 Subject: [PATCH] Add XAP registrar flag and drop DB defaults Expose the --expiry_access_period_enabled CLI flag on registrar mutation commands and drop temporary database-level default constraints for XAP. Specifically: - Expose the --expiry_access_period_enabled parameter in CreateOrUpdateRegistrarCommand and pass it to Registrar.Builder.setExpiryAccessPeriodEnabled. - Add expiryAccessPeriodTransitions with default DISABLED to example.yaml. - Add unit tests for --expiry_access_period_enabled in CreateRegistrarCommandTest and UpdateRegistrarCommandTest. - Add Flyway migrations V229 and V230 to drop the temporary database-level DEFAULT constraints on Tld.expiry_access_period_transitions and Registrar.expiry_access_period_enabled per db/README.md. - Regenerate flyway.txt, nomulus.golden.sql, and ER diagrams. TAG=agy BUG=http://b/437398822 --- .../registry/config/files/tld/example.yaml | 2 + .../tools/CreateOrUpdateRegistrarCommand.java | 9 ++++ .../tools/CreateRegistrarCommandTest.java | 45 +++++++++++++++++++ .../tools/UpdateRegistrarCommandTest.java | 17 +++++++ .../sql/er_diagram/brief_er_diagram.html | 6 +-- .../sql/er_diagram/full_er_diagram.html | 16 ++----- db/src/main/resources/sql/flyway.txt | 2 + ...V229__tld_drop_xap_transitions_default.sql | 16 +++++++ ...30__registrar_drop_xap_enabled_default.sql | 16 +++++++ .../resources/sql/schema/nomulus.golden.sql | 8 ++-- 10 files changed, 117 insertions(+), 20 deletions(-) create mode 100644 db/src/main/resources/sql/flyway/V229__tld_drop_xap_transitions_default.sql create mode 100644 db/src/main/resources/sql/flyway/V230__registrar_drop_xap_enabled_default.sql diff --git a/core/src/main/java/google/registry/config/files/tld/example.yaml b/core/src/main/java/google/registry/config/files/tld/example.yaml index d51da68f316..52832ee9fcc 100644 --- a/core/src/main/java/google/registry/config/files/tld/example.yaml +++ b/core/src/main/java/google/registry/config/files/tld/example.yaml @@ -27,6 +27,8 @@ eapFeeSchedule: currency: "USD" amount: 0.00 escrowEnabled: false +expiryAccessPeriodTransitions: + "1970-01-01T00:00:00.000Z": "DISABLED" idnTables: [] invoicingEnabled: false lordnUsername: null diff --git a/core/src/main/java/google/registry/tools/CreateOrUpdateRegistrarCommand.java b/core/src/main/java/google/registry/tools/CreateOrUpdateRegistrarCommand.java index f9f90a98de1..9ff5f6f97b6 100644 --- a/core/src/main/java/google/registry/tools/CreateOrUpdateRegistrarCommand.java +++ b/core/src/main/java/google/registry/tools/CreateOrUpdateRegistrarCommand.java @@ -234,6 +234,13 @@ abstract class CreateOrUpdateRegistrarCommand extends MutatingCommand { arity = 1) private Boolean registryLockAllowed; + @Nullable + @Parameter( + names = "--expiry_access_period_enabled", + description = "Whether this registrar is enabled for the Expiry Access Period", + arity = 1) + private Boolean expiryAccessPeriodEnabled; + @Nullable @Parameter( names = "--drive_folder_id", @@ -384,6 +391,8 @@ protected final void init() throws Exception { Optional.ofNullable(blockPremiumNames).ifPresent(builder::setBlockPremiumNames); Optional.ofNullable(contactsRequireSyncing).ifPresent(builder::setContactsRequireSyncing); Optional.ofNullable(registryLockAllowed).ifPresent(builder::setRegistryLockAllowed); + Optional.ofNullable(expiryAccessPeriodEnabled) + .ifPresent(builder::setExpiryAccessPeriodEnabled); Optional.ofNullable(phonePasscode).ifPresent(builder::setPhonePasscode); Optional.ofNullable(icannReferralEmail).ifPresent(builder::setIcannReferralEmail); Optional.ofNullable(whoisServer).ifPresent(builder::setWhoisServer); diff --git a/core/src/test/java/google/registry/tools/CreateRegistrarCommandTest.java b/core/src/test/java/google/registry/tools/CreateRegistrarCommandTest.java index c94b7b002db..ec6516ba83e 100644 --- a/core/src/test/java/google/registry/tools/CreateRegistrarCommandTest.java +++ b/core/src/test/java/google/registry/tools/CreateRegistrarCommandTest.java @@ -104,6 +104,7 @@ void testSuccess() throws Exception { assertThat(registrar.getLastUpdateTime()).isEqualTo(registrar.getCreationTime()); assertThat(registrar.getBlockPremiumNames()).isFalse(); assertThat(registrar.isRegistryLockAllowed()).isFalse(); + assertThat(registrar.getExpiryAccessPeriodEnabled()).isFalse(); assertThat(registrar.getPoNumber()).isEmpty(); assertThat(registrar.getIcannReferralEmail()).isEqualTo("foo@bar.test"); @@ -890,6 +891,50 @@ void testSuccess_registryLockDisallowed() throws Exception { assertThat(registrar.get().isRegistryLockAllowed()).isFalse(); } + @Test + void testSuccess_expiryAccessPeriodEnabled() throws Exception { + runCommandForced( + "--name=blobio", + "--password=some_password", + "--registrar_type=REAL", + "--iana_id=8", + "--expiry_access_period_enabled=true", + "--passcode=01234", + "--icann_referral_email=foo@bar.test", + "--street=\"123 Fake St\"", + "--city Fakington", + "--state MA", + "--zip 00351", + "--cc US", + "clientz"); + + Optional registrar = Registrar.loadByRegistrarId("clientz"); + assertThat(registrar).isPresent(); + assertThat(registrar.get().getExpiryAccessPeriodEnabled()).isTrue(); + } + + @Test + void testSuccess_expiryAccessPeriodDisabled() throws Exception { + runCommandForced( + "--name=blobio", + "--password=some_password", + "--registrar_type=REAL", + "--iana_id=8", + "--expiry_access_period_enabled=false", + "--passcode=01234", + "--icann_referral_email=foo@bar.test", + "--street=\"123 Fake St\"", + "--city Fakington", + "--state MA", + "--zip 00351", + "--cc US", + "clientz"); + + Optional registrar = Registrar.loadByRegistrarId("clientz"); + assertThat(registrar).isPresent(); + assertThat(registrar.get().getExpiryAccessPeriodEnabled()).isFalse(); + } + @Test void testFailure_badPhoneNumber() { ParameterException thrown = diff --git a/core/src/test/java/google/registry/tools/UpdateRegistrarCommandTest.java b/core/src/test/java/google/registry/tools/UpdateRegistrarCommandTest.java index 213cd874c00..5e3d8807f5e 100644 --- a/core/src/test/java/google/registry/tools/UpdateRegistrarCommandTest.java +++ b/core/src/test/java/google/registry/tools/UpdateRegistrarCommandTest.java @@ -563,6 +563,21 @@ void testSuccess_disallowRegistryLock() throws Exception { assertThat(loadRegistrar("NewRegistrar").isRegistryLockAllowed()).isFalse(); } + @Test + void testSuccess_expiryAccessPeriodEnabled() throws Exception { + assertThat(loadRegistrar("NewRegistrar").getExpiryAccessPeriodEnabled()).isFalse(); + runCommandForced("--expiry_access_period_enabled=true", "NewRegistrar"); + assertThat(loadRegistrar("NewRegistrar").getExpiryAccessPeriodEnabled()).isTrue(); + } + + @Test + void testSuccess_resetExpiryAccessPeriodEnabled() throws Exception { + persistResource( + loadRegistrar("NewRegistrar").asBuilder().setExpiryAccessPeriodEnabled(true).build()); + runCommandForced("--expiry_access_period_enabled=false", "NewRegistrar"); + assertThat(loadRegistrar("NewRegistrar").getExpiryAccessPeriodEnabled()).isFalse(); + } + @Test void testSuccess_unspecifiedBooleansArentChanged() throws Exception { persistResource( @@ -570,6 +585,7 @@ void testSuccess_unspecifiedBooleansArentChanged() throws Exception { .asBuilder() .setBlockPremiumNames(true) .setContactsRequireSyncing(true) + .setExpiryAccessPeriodEnabled(true) .build()); // Make some unrelated change where we don't specify the flags for the booleans. runCommandForced("NewRegistrar"); @@ -577,6 +593,7 @@ void testSuccess_unspecifiedBooleansArentChanged() throws Exception { Registrar reloadedRegistrar = loadRegistrar("NewRegistrar"); assertThat(reloadedRegistrar.getBlockPremiumNames()).isTrue(); assertThat(reloadedRegistrar.getContactsRequireSyncing()).isTrue(); + assertThat(reloadedRegistrar.getExpiryAccessPeriodEnabled()).isTrue(); } @Test diff --git a/db/src/main/resources/sql/er_diagram/brief_er_diagram.html b/db/src/main/resources/sql/er_diagram/brief_er_diagram.html index 14990bd7ad0..8b92a34f4ef 100644 --- a/db/src/main/resources/sql/er_diagram/brief_er_diagram.html +++ b/db/src/main/resources/sql/er_diagram/brief_er_diagram.html @@ -261,11 +261,11 @@

System Information

generated on - 2026-08-12 15:34:00 + 2026-08-27 21:08:38 last flyway file - V228__hosthistory_repo_id_mod_time_idx.sql + V230__registrar_drop_xap_enabled_default.sql @@ -273,7 +273,7 @@

System Information

 

- SchemaCrawler_Diagram generated by SchemaCrawler 17.12.2 generated on 2026-08-12 15:34:00 + SchemaCrawler_Diagram generated by SchemaCrawler 17.12.2 generated on 2026-08-27 21:08:38 allocationtoken_a08ccbef public."AllocationToken" [table] token text not null domain_name text redemption_domain_repo_id text token_type text diff --git a/db/src/main/resources/sql/er_diagram/full_er_diagram.html b/db/src/main/resources/sql/er_diagram/full_er_diagram.html index 4d6e2f15cbb..476274fce5d 100644 --- a/db/src/main/resources/sql/er_diagram/full_er_diagram.html +++ b/db/src/main/resources/sql/er_diagram/full_er_diagram.html @@ -261,11 +261,11 @@

System Information

generated on - 2026-08-12 15:33:59 + 2026-08-27 21:08:36 last flyway file - V228__hosthistory_repo_id_mod_time_idx.sql + V230__registrar_drop_xap_enabled_default.sql @@ -273,7 +273,7 @@

System Information

 

- SchemaCrawler_Diagram generated by SchemaCrawler 17.12.2 generated on 2026-08-12 15:33:59 + SchemaCrawler_Diagram generated by SchemaCrawler 17.12.2 generated on 2026-08-27 21:08:36 allocationtoken_a08ccbef public."AllocationToken" [table] token text not null update_timestamp timestamptz allowed_registrar_ids _text allowed_tlds _text creation_time timestamptz not null discount_fraction float8(17, 17) not null discount_premiums bool not null discount_years int4 not null domain_name text redemption_domain_repo_id text token_status_transitions hstore token_type text redemption_domain_history_id int8 renewal_price_behavior text not null registration_behavior text not null allowed_epp_actions _text renewal_price_amount numeric(19, 2) renewal_price_currency text discount_price_amount numeric(19, 2) discount_price_currency text @@ -6863,11 +6863,6 @@

Tables

expiry_access_period_enabled bool not null - - - - default false - @@ -8850,11 +8845,6 @@

Tables

expiry_access_period_transitions hstore not null - - - - default '"1970-01-01T00:00:00.000Z"=>"DISABLED"'::hstore - diff --git a/db/src/main/resources/sql/flyway.txt b/db/src/main/resources/sql/flyway.txt index 880a57c13fb..5f24ecb326b 100644 --- a/db/src/main/resources/sql/flyway.txt +++ b/db/src/main/resources/sql/flyway.txt @@ -226,3 +226,5 @@ V225__user_registry_lock_email_address_index.sql V226__tld_domain_name_index.sql V227__domainhistory_repo_id_mod_time_idx.sql V228__hosthistory_repo_id_mod_time_idx.sql +V229__tld_drop_xap_transitions_default.sql +V230__registrar_drop_xap_enabled_default.sql diff --git a/db/src/main/resources/sql/flyway/V229__tld_drop_xap_transitions_default.sql b/db/src/main/resources/sql/flyway/V229__tld_drop_xap_transitions_default.sql new file mode 100644 index 00000000000..30945fdae06 --- /dev/null +++ b/db/src/main/resources/sql/flyway/V229__tld_drop_xap_transitions_default.sql @@ -0,0 +1,16 @@ +-- Copyright 2026 The Nomulus Authors. All Rights Reserved. +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. + +ALTER TABLE "Tld" + ALTER COLUMN expiry_access_period_transitions DROP DEFAULT; diff --git a/db/src/main/resources/sql/flyway/V230__registrar_drop_xap_enabled_default.sql b/db/src/main/resources/sql/flyway/V230__registrar_drop_xap_enabled_default.sql new file mode 100644 index 00000000000..3dfa8c73168 --- /dev/null +++ b/db/src/main/resources/sql/flyway/V230__registrar_drop_xap_enabled_default.sql @@ -0,0 +1,16 @@ +-- Copyright 2026 The Nomulus Authors. All Rights Reserved. +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. + +ALTER TABLE "Registrar" + ALTER COLUMN expiry_access_period_enabled DROP DEFAULT; diff --git a/db/src/main/resources/sql/schema/nomulus.golden.sql b/db/src/main/resources/sql/schema/nomulus.golden.sql index b953ac9760e..2a73e40cbbc 100644 --- a/db/src/main/resources/sql/schema/nomulus.golden.sql +++ b/db/src/main/resources/sql/schema/nomulus.golden.sql @@ -2,8 +2,8 @@ -- PostgreSQL database dump -- --- Dumped from database version 17.10 --- Dumped by pg_dump version 17.10 +-- Dumped from database version 17.4 +-- Dumped by pg_dump version 17.4 SET statement_timeout = 0; SET lock_timeout = 0; @@ -856,7 +856,7 @@ CREATE TABLE public."Registrar" ( last_expiring_cert_notification_sent_date timestamp with time zone, last_expiring_failover_cert_notification_sent_date timestamp with time zone, last_poc_verification_date timestamp with time zone, - expiry_access_period_enabled boolean DEFAULT false NOT NULL + expiry_access_period_enabled boolean NOT NULL ); @@ -1206,7 +1206,7 @@ CREATE TABLE public."Tld" ( breakglass_mode boolean DEFAULT false NOT NULL, bsa_enroll_start_time timestamp with time zone, create_billing_cost_transitions public.hstore NOT NULL, - expiry_access_period_transitions public.hstore DEFAULT '"1970-01-01T00:00:00.000Z"=>"DISABLED"'::public.hstore NOT NULL + expiry_access_period_transitions public.hstore NOT NULL );