diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 46b8450..e86cde2 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,5 +1,5 @@ default: - image: gradle:8.9-jdk17 + image: gradle:8.10-jdk17 # Explicit version of the Mergerequests-Pipelines workflow, with the main branch # added. diff --git a/build.gradle b/build.gradle index 9a67111..3810727 100644 --- a/build.gradle +++ b/build.gradle @@ -44,7 +44,7 @@ dependencies { implementation "org.thymeleaf:thymeleaf:3.1.2.RELEASE" implementation "org.thymeleaf:thymeleaf-spring6:3.1.2.RELEASE" - implementation platform('io.sentry:sentry-bom:7.13.0') + implementation platform('io.sentry:sentry-bom:7.14.0') implementation 'io.sentry:sentry-spring-boot-starter' implementation 'io.sentry:sentry-logback' @@ -53,13 +53,13 @@ dependencies { implementation 'org.springdoc:springdoc-openapi-ui:1.8.0' runtimeOnly 'io.micrometer:micrometer-registry-prometheus' - implementation 'org.postgresql:postgresql:42.7.3' + implementation 'org.postgresql:postgresql:42.7.4' runtimeOnly 'org.springframework.boot:spring-boot-starter-tomcat' implementation 'com.google.code.gson:gson:2.11.0' implementation 'com.jamesmurty.utils:java-xmlbuilder:1.3' implementation 'commons-codec:commons-codec:1.17.1' - implementation 'commons-io:commons-io:2.16.1' + implementation 'commons-io:commons-io:2.17.0' implementation 'ch.qos.logback.contrib:logback-json-classic:0.1.5' implementation 'ch.qos.logback.contrib:logback-jackson:0.1.5' implementation 'net.logstash.logback:logstash-logback-encoder:8.0' @@ -73,7 +73,7 @@ dependencies { } testImplementation "org.wiremock:wiremock-jetty12:3.9.1" - testImplementation 'net.jqwik:jqwik:1.9.0' + testImplementation 'net.jqwik:jqwik:1.9.1' testImplementation "net.ripe.rpki:rpki-commons:$rpki_commons_version:tests" testImplementation 'org.assertj:assertj-core' diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle index 4bfc476..f514c7e 100644 --- a/buildSrc/build.gradle +++ b/buildSrc/build.gradle @@ -9,10 +9,10 @@ repositories { } dependencies { - implementation 'io.freefair.lombok:io.freefair.lombok.gradle.plugin:8.7.1' + implementation 'io.freefair.lombok:io.freefair.lombok.gradle.plugin:8.10' implementation('com.gorylenko.gradle-git-properties:com.gorylenko.gradle-git-properties.gradle.plugin:2.4.2') { exclude group: 'org.eclipse.jgit', module: 'org.eclipse.jgit' } - implementation 'org.eclipse.jgit:org.eclipse.jgit:6.10.0.202406032230-r' + implementation 'org.eclipse.jgit:org.eclipse.jgit:7.0.0.202409031743-r' implementation 'org.sonarqube:org.sonarqube.gradle.plugin:5.1.0.4882' } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e644113..a4b76b9 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 09523c0..df97d72 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index b740cf1..f5feea6 100755 --- a/gradlew +++ b/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -84,7 +86,8 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum diff --git a/gradlew.bat b/gradlew.bat index 7101f8e..9b42019 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## diff --git a/scripts/gitlab-deploy-check b/scripts/gitlab-deploy-check index dd14ffe..3d14605 100755 --- a/scripts/gitlab-deploy-check +++ b/scripts/gitlab-deploy-check @@ -130,6 +130,8 @@ const calculateDeploymentDurations = (timeline, mergeRequest) => { || ref === mergeRequest.source_branch || ref === `refs/merge-requests/${mergeRequest.iid}/merge`; }; + const matchesLastCommit = ({sha, parent_ids}) => + sha === mergeRequest.sha || (parent_ids.length > 1 && parent_ids.includes(mergeRequest.sha)); const mapPairs = (f) => (xs) => { if (xs.length === 0) { @@ -149,9 +151,10 @@ const calculateDeploymentDurations = (timeline, mergeRequest) => { return [Math.floor((end - start) / 1000), { iid: deployment.iid, ref: deployment.ref, - sha: deployment.sha, + sha: deployment.deployable.commit.id, started_at: deployment.deployable.started_at, finished_at: deployment.deployable.finished_at, + parent_ids: deployment.deployable.commit.parent_ids, }]; } ); @@ -162,7 +165,7 @@ const calculateDeploymentDurations = (timeline, mergeRequest) => { .filter(([_, refs]) => matchesMR(refs)) .reduce((acc, [duration]) => acc + duration, 0), last_commit: durations - .filter(([duration, refs]) => refs.sha === mergeRequest.sha) + .filter(([_, refs]) => matchesLastCommit(refs)) .reduce((acc, [duration]) => acc + duration, 0), }; }; @@ -186,14 +189,8 @@ const main = async (ctx) => { status: "success", })(); const timeline = [...deployments].sort(Calendar.compare((x) => x.finished_at)) - .reduce((acc, x) => acc.find(({id}) => id === x.id) != null ? acc : [...acc, x], []) - .reduce(({result, pastMerge}, x) => - pastMerge ? { result, pastMerge } : { - result: [...result, x], - pastMerge: Calendar.isAfter(x.finished_at, mergeRequest.merged_at) - }, - {result: [], pastMerge: false} - ).result; + .filter((x) => !Calendar.isAfter(x.deployable.created_at, mergeRequest.merged_at)) + .reduce((acc, x) => acc.find(({id}) => id === x.id) != null ? acc : [...acc, x], []); const durations = calculateDeploymentDurations(timeline, mergeRequest); const passesThreshold = durations.merge_request > ctx.stagingDuration; diff --git a/src/main/java/net/ripe/rpki/services/impl/jpa/JpaRoaConfigurationRepository.java b/src/main/java/net/ripe/rpki/services/impl/jpa/JpaRoaConfigurationRepository.java index 0680c67..3a45e93 100644 --- a/src/main/java/net/ripe/rpki/services/impl/jpa/JpaRoaConfigurationRepository.java +++ b/src/main/java/net/ripe/rpki/services/impl/jpa/JpaRoaConfigurationRepository.java @@ -97,7 +97,7 @@ public void applyDiff(RoaConfiguration configuration, diff.removed().forEach(r -> { String sql = """ WITH deleted AS ( - DELETE FROM roaconfiguration_prefixes + DELETE FROM roaconfiguration_prefixes rp WHERE roaconfiguration_id = :roaconfiguration_id AND asn = :asn AND prefix_type_id = :prefix_type_id @@ -106,8 +106,9 @@ WITH deleted AS ( AND maximum_length = :maximum_length RETURNING * ) - INSERT INTO deleted_roaconfiguration_prefixes - SELECT * FROM deleted + INSERT INTO deleted_roaconfiguration_prefixes(roaconfiguration_id, asn, prefix_type_id, prefix_start, prefix_end, maximum_length, deleted_at) + SELECT roaconfiguration_id, asn, prefix_type_id, prefix_start, prefix_end, maximum_length, NOW() + FROM deleted """; executeForPrefix(configuration, r, sql); }); @@ -124,16 +125,15 @@ INSERT INTO roaconfiguration_prefixes (roaconfiguration_id, asn, prefix_type_id, } private void executeForPrefix(RoaConfiguration configuration, RoaConfigurationPrefix dp, String sql) { - final IpRange prefix = dp.getPrefix(); - makeQuery(configuration, dp, sql, prefix).executeUpdate(); + makeQuery(configuration, dp, sql).executeUpdate(); } private Instant extractForPrefix(RoaConfiguration configuration, RoaConfigurationPrefix dp, String sql) { - final IpRange prefix = dp.getPrefix(); - return (Instant) makeQuery(configuration, dp, sql, prefix).getSingleResult(); + return (Instant) makeQuery(configuration, dp, sql).getSingleResult(); } - private Query makeQuery(RoaConfiguration configuration, RoaConfigurationPrefix dp, String sql, IpRange prefix) { + private Query makeQuery(RoaConfiguration configuration, RoaConfigurationPrefix dp, String sql) { + IpRange prefix = dp.getPrefix(); return createNativeQuery(sql) .setParameter("roaconfiguration_id", configuration.getId()) .setParameter("asn", dp.getAsn().longValue()) diff --git a/src/main/resources/db/migration/R__fix_deleted_at_roa_prefixe.sql b/src/main/resources/db/migration/R__fix_deleted_at_roa_prefixe.sql new file mode 100644 index 0000000..a5e2ed6 --- /dev/null +++ b/src/main/resources/db/migration/R__fix_deleted_at_roa_prefixe.sql @@ -0,0 +1,21 @@ +CREATE OR REPLACE FUNCTION force_roa_prefix_deleted_at() + RETURNS TRIGGER + LANGUAGE plpgsql AS +$$ +BEGIN + NEW.deleted_at := now(); + RETURN NEW; +END +$$; + +CREATE OR REPLACE TRIGGER delete_roa_prefix_before_insert + BEFORE INSERT ON deleted_roaconfiguration_prefixes + FOR EACH ROW + WHEN (NEW.deleted_at IS NULL) +EXECUTE FUNCTION force_roa_prefix_deleted_at(); + +DROP TRIGGER IF EXISTS delete_roa_prefix_before_insert ON deleted_roaconfiguration_prefixes; +DROP FUNCTION IF EXISTS force_roa_prefix_deleted_at(); + +-- TODO This migration is to be deleted after next deployment dropping the trigger workaround + diff --git a/src/test/java/net/ripe/rpki/domain/roa/RoaConfigurationMaintenanceServiceTest.java b/src/test/java/net/ripe/rpki/domain/roa/RoaConfigurationMaintenanceServiceTest.java index 4c1a93a..8790655 100644 --- a/src/test/java/net/ripe/rpki/domain/roa/RoaConfigurationMaintenanceServiceTest.java +++ b/src/test/java/net/ripe/rpki/domain/roa/RoaConfigurationMaintenanceServiceTest.java @@ -21,6 +21,7 @@ import javax.security.auth.x500.X500Principal; import jakarta.transaction.Transactional; +import org.springframework.test.annotation.Commit; import java.util.*; @@ -30,6 +31,7 @@ @Setter @Slf4j @Transactional +@Commit // don't rollback, we want all constrains to be checked public class RoaConfigurationMaintenanceServiceTest extends CertificationDomainTestCase { private static final long HOSTED_CA_ID = 8L; diff --git a/src/test/java/net/ripe/rpki/services/impl/handlers/UpdateRoaConfigurationCommandHandlerTest.java b/src/test/java/net/ripe/rpki/services/impl/handlers/UpdateRoaConfigurationCommandHandlerTest.java index daf500b..4d71766 100644 --- a/src/test/java/net/ripe/rpki/services/impl/handlers/UpdateRoaConfigurationCommandHandlerTest.java +++ b/src/test/java/net/ripe/rpki/services/impl/handlers/UpdateRoaConfigurationCommandHandlerTest.java @@ -17,6 +17,7 @@ import org.junit.Before; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.annotation.Commit; import java.util.Collections; import java.util.Optional; @@ -28,6 +29,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; @Transactional +@Commit // don't rollback, we want all constrains to be checked public class UpdateRoaConfigurationCommandHandlerTest extends CertificationDomainTestCase { private static final Asn ASN = Asn.parse("1234"); @@ -89,6 +91,7 @@ public void should_reject_if_etag_does_not_match_current_configuration() { } @Test(expected = PrivateAsnsUsedException.class) + @Commit // don't rollback, we want all constrains to be checked public void should_reject_new_additions_of_private_ASN() { subject.handle(new UpdateRoaConfigurationCommand( certificateAuthority.getVersionedId(), diff --git a/src/test/java/net/ripe/rpki/services/impl/jpa/JpaRoaConfigurationRepositoryTest.java b/src/test/java/net/ripe/rpki/services/impl/jpa/JpaRoaConfigurationRepositoryTest.java index fc79ca3..8191011 100644 --- a/src/test/java/net/ripe/rpki/services/impl/jpa/JpaRoaConfigurationRepositoryTest.java +++ b/src/test/java/net/ripe/rpki/services/impl/jpa/JpaRoaConfigurationRepositoryTest.java @@ -12,6 +12,7 @@ import org.springframework.beans.factory.annotation.Autowired; import jakarta.transaction.Transactional; +import org.springframework.test.annotation.Commit; import java.time.Instant; import java.util.Arrays; @@ -22,6 +23,7 @@ import static org.junit.Assert.assertNotNull; @Transactional +@Commit // don't rollback, we want all constrains to be checked public class JpaRoaConfigurationRepositoryTest extends CertificationDomainTestCase { @Autowired diff --git a/src/test/java/net/ripe/rpki/services/impl/jpa/JpaRoaEntityRepositoryTest.java b/src/test/java/net/ripe/rpki/services/impl/jpa/JpaRoaEntityRepositoryTest.java index 03869cb..008e6d4 100644 --- a/src/test/java/net/ripe/rpki/services/impl/jpa/JpaRoaEntityRepositoryTest.java +++ b/src/test/java/net/ripe/rpki/services/impl/jpa/JpaRoaEntityRepositoryTest.java @@ -3,6 +3,7 @@ import net.ripe.rpki.domain.*; import org.junit.Before; import org.junit.Test; +import org.springframework.test.annotation.Commit; import org.springframework.transaction.annotation.Transactional; import jakarta.inject.Inject; @@ -11,6 +12,7 @@ @Transactional +@Commit // don't rollback, we want all constrains to be checked public class JpaRoaEntityRepositoryTest extends CertificationDomainTestCase { @Inject