<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>com.mulesoft.connectors</groupId>
        <artifactId>mule4-connectors-parent</artifactId>
        <version>1.0.7</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>mule-redis-connector</artifactId>
    <version>5.8.0</version>
    <packaging>mule-extension</packaging>
    <name>Redis Connector - Mule 4</name>

    <properties>
        <licensePath>LICENSE.md</licensePath>
        <devkit.studio.package.skip>false</devkit.studio.package.skip>
        <project.structure.validation.version>1.0.6</project.structure.validation.version>
        <idea.annotations.version>12.0</idea.annotations.version>
        <harmcrest.version>1.4-atlassian-1</harmcrest.version>
        <munit.input.directory>src/test/munit</munit.input.directory>
        <munit.output.directory>${basedir}/target/test-mule/munit</munit.output.directory>
        <mavenResourcesVersion>3.5.0</mavenResourcesVersion>
        <!-- runtime version to run -->
        <runtimeProduct>MULE_EE</runtimeProduct>
        <jedis.version>7.5.3</jedis.version>
        <jdeps.multiRelease>base</jdeps.multiRelease>
        <mule.objectstore.connector.version>1.3.1</mule.objectstore.connector.version>
        <mule.connector.commons.version>2.1.2</mule.connector.commons.version>
        <!-- Used in MTF tests -->
        <certstore.name>redis</certstore.name>
        <clustered.certstore.name>redis-cluster</clustered.certstore.name>
        <sentinel.certstore.name>redis-sentinel-redis8</sentinel.certstore.name>
        <keystore.extension>${keystore.extension}</keystore.extension>
        <truststore.extension>${truststore.extension}</truststore.extension>
        <!-- Redis Docker (-Pdocker): filters src/test/docker/redis-test-credentials.properties and docker-compose.yml.
             Ports are reserved dynamically via build-helper-maven-plugin in the docker profile (generate-test-resources).
             Defaults below are only used when the docker profile is inactive or when ports are overridden explicitly.

             redis.docker.advertised.ip is the IP the test JVM (and Redis cluster slot/sentinel responses)
             must advertise. On a developer box, 127.0.0.1 is correct because mvn and the Redis containers
             share the same loopback. In SFCI the mvn JVM runs in a sibling build container, so it must
             reach Redis on the build host's IP — overridden via the build-agent-ip profile when the
             BUILD_AGENT_IP_ADDR env var is set. -->
        <redis.docker.advertised.ip>127.0.0.1</redis.docker.advertised.ip>
        <redis.docker.host>${redis.docker.advertised.ip}</redis.docker.host>
        <redis.docker.port>6379</redis.docker.port>
        <redis.docker.connectionTimeout>60000</redis.docker.connectionTimeout>
        <redis.docker.clusterHosts>${redis.docker.advertised.ip}</redis.docker.clusterHosts>
        <redis.docker.clusterHosts.port>7003</redis.docker.clusterHosts.port>
        <redis.docker.clusterHosts.port2>7004</redis.docker.clusterHosts.port2>
        <redis.docker.clusterHosts.port3>7005</redis.docker.clusterHosts.port3>
        <redis.docker.clusterConnectionTimeout>60000</redis.docker.clusterConnectionTimeout>
        <redis.docker.sentinel.host>${redis.docker.advertised.ip}</redis.docker.sentinel.host>
        <redis.docker.sentinel.host.port>26379</redis.docker.sentinel.host.port>
        <redis.docker.sentinel.master.port>6381</redis.docker.sentinel.master.port>
        <redis.docker.sentinel.masterName>mymaster</redis.docker.sentinel.masterName>
        <redis.docker.password>default</redis.docker.password>
        <!-- ACL MUnit suites (src/test/munit/acl/**) are skipped by default and re-included only
             under the docker profile (which sets this to empty). -->
        <munit.acl.exclude>acl/**</munit.acl.exclude>
        <!-- ACL test users provisioned by docker-compose on every Redis service.
             aclUser=full perms (happy path), aclReadOnly=read-only (NOPERM-on-write tests),
             aclOffUser=disabled (off-user connect-failure tests). Defaults below are used when
             the docker profile is inactive; the compose file and redis-test-credentials.properties
             are resource-filtered with these values. -->
        <redis.docker.acl.user>aclTestUser</redis.docker.acl.user>
        <redis.docker.acl.password>aclTestPass</redis.docker.acl.password>
        <redis.docker.acl.readonly.user>aclReadOnly</redis.docker.acl.readonly.user>
        <redis.docker.acl.readonly.password>aclReadOnlyPass</redis.docker.acl.readonly.password>
        <redis.docker.acl.off.user>aclOffUser</redis.docker.acl.off.user>
        <redis.docker.acl.off.password>aclOffPass</redis.docker.acl.off.password>
        <!-- Sentinel-channel ACL user (distinct identity for the connector->sentinel session). -->
        <redis.docker.acl.sentinel.user>aclSentinelUser</redis.docker.acl.sentinel.user>
        <redis.docker.acl.sentinel.password>aclSentinelPass</redis.docker.acl.sentinel.password>
        <redis.docker.host.redis7>localhost</redis.docker.host.redis7>
        <redis.docker.port.redis7>6382</redis.docker.port.redis7>
        <redis.docker.clusterHosts.redis7>127.0.0.1:7000</redis.docker.clusterHosts.redis7>
        <redis.docker.sentinel.host.redis7>127.0.0.1:26380</redis.docker.sentinel.host.redis7>
        <redis.docker.sentinel.masterName.redis7>mymaster</redis.docker.sentinel.masterName.redis7>
        <!-- TLS connection coordinates. Host follows the same advertised-IP
             indirection as non-TLS services so the build-agent-ip profile
             swaps in BUILD_AGENT_IP_ADDR in SFCI. Ports listed here are
             defaults used outside the docker profile; in docker profile they
             are overridden dynamically by build-helper (see reserve-redis-ports).
             ${X}:${Y} composition is intentionally NOT done in this <properties>
             block — that would freeze the host:port string at model-eval time
             and shadow the runtime port override. The host:port form is built
             inside the resource-filtered Config.xml / docker-compose.yml. -->
        <redis.docker.tls.host>${redis.docker.advertised.ip}</redis.docker.tls.host>
        <redis.docker.tls.host.port>6384</redis.docker.tls.host.port>
        <redis.docker.tls.sentinel.master.port>6386</redis.docker.tls.sentinel.master.port>
        <redis.docker.tls.sentinel.host.port>26389</redis.docker.tls.sentinel.host.port>
        <redis.docker.tls.clusterHosts>${redis.docker.advertised.ip}</redis.docker.tls.clusterHosts>
        <redis.docker.tls.clusterHosts.port>7100</redis.docker.tls.clusterHosts.port>
        <redis.docker.tls.clusterHosts.port2>7101</redis.docker.tls.clusterHosts.port2>
        <redis.docker.tls.clusterHosts.port3>7102</redis.docker.tls.clusterHosts.port3>
        <redis.docker.tls.host.redis7>localhost</redis.docker.tls.host.redis7>
        <redis.docker.tls.host.redis7.port>6385</redis.docker.tls.host.redis7.port>
        <redis.docker.tls.clusterHosts.redis7>127.0.0.1:7103</redis.docker.tls.clusterHosts.redis7>
        <config.tls.sentinel.host.redis8>${redis.docker.advertised.ip}</config.tls.sentinel.host.redis8>
        <config.tls.sentinel.masterName.redis8>mymaster</config.tls.sentinel.masterName.redis8>
        <config.tls.sentinel.master.password.redis8>default</config.tls.sentinel.master.password.redis8>
        <config.tls.sentinel.password.redis8>default</config.tls.sentinel.password.redis8>
        <config.tls.sentinel.truststore.password.redis8>default</config.tls.sentinel.truststore.password.redis8>
        <config.tls.sentinel.keystore.key.password.redis8>default</config.tls.sentinel.keystore.key.password.redis8>
        <config.tls.sentinel.keystore.password.redis8>default</config.tls.sentinel.keystore.password.redis8>
        <redis.docker.host.redis8>localhost</redis.docker.host.redis8>
        <redis.docker.port.redis8>6380</redis.docker.port.redis8>
        <redis.docker.connectionTimeout.redis8>60000</redis.docker.connectionTimeout.redis8>
        <redis.docker.tls.clustered.fips>127.0.0.1:6382</redis.docker.tls.clustered.fips>
        <redis.docker.tls.clustered.nor.fips.clusterHosts>127.0.0.1:6382</redis.docker.tls.clustered.nor.fips.clusterHosts>
        <!-- Host path used by Docker bind mounts (e.g. TLS cert directory).
             Defaults to ${project.basedir}, which is correct on a developer
             box where Maven and the Docker daemon share the same filesystem.
             In SFCI/CIX, Maven runs inside a sibling build container where
             ${project.basedir} resolves to /cix/src/... — a path the host
             Docker daemon cannot see, so the bind mount silently maps an
             empty directory and TLS Redis fails to find /certs/ca.crt.
             The build-workspace profile below overrides this with the host
             workspace path (BUILD_WORKSPACE) when running under CI. -->
        <redis.docker.workspace.path>${project.basedir}</redis.docker.workspace.path>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.mulesoft.connectors</groupId>
            <artifactId>mule-connector-commons</artifactId>
            <version>${mule.connector.commons.version}</version>
        </dependency>
        <dependency>
            <groupId>org.mule.connectors</groupId>
            <artifactId>mule-objectstore-connector</artifactId>
            <version>${mule.objectstore.connector.version}</version>
            <scope>test</scope>
            <classifier>mule-plugin</classifier>
        </dependency>

        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>${jedis.version}</version>
            <type>jar</type>
            <exclusions>
                <exclusion>
                    <groupId>com.google.code.gson</groupId>
                    <artifactId>gson</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- Testing Dependencies -->

        <dependency>
            <groupId>com.github.kstyrc</groupId>
            <artifactId>embedded-redis</artifactId>
            <version>0.6</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest-core</artifactId>
            <version>${harmcrest.version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest-library</artifactId>
            <version>${harmcrest.version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.mule.sdk</groupId>
            <artifactId>mule-sdk-api</artifactId>
            <version>${mule.sdk.api.version}</version>
        </dependency>
        <!-- Override mule-extensions-api to align with AST processor version (ETS migration) -->
        <dependency>
            <groupId>org.mule.runtime</groupId>
            <artifactId>mule-extensions-api</artifactId>
            <version>${mule.extensions.api.version}</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-jar-plugin</artifactId>
                    <configuration>
                        <archive>
                            <manifest>
                                <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
                                <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
                            </manifest>
                            <manifestEntries>
                                <Build-Date>${maven.build.timestamp}</Build-Date>
                                <Target-Java-Release-Version>${java.release.version}</Target-Java-Release-Version>
                            </manifestEntries>
                        </archive>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-install-plugin</artifactId>
                <version>2.5.2</version>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-deploy-plugin</artifactId>
                <version>2.8.2</version>
            </plugin>
            <plugin>
                <artifactId>maven-source-plugin</artifactId>
                <version>2.4</version>
                <executions>
                    <execution>
                        <id>attach-sources</id>
                        <phase>none</phase>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <artifactId>maven-resources-plugin</artifactId>
                <version>${mavenResourcesVersion}</version>
                <executions>
                    <execution>
                        <id>copy-munit-resources</id>
                        <phase>process-test-resources</phase>
                        <goals>
                            <goal>copy-resources</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${basedir}/target/test-mule/munit</outputDirectory>
                            <resources>
                                <resource>
                                    <directory>src/test/munit</directory>
                                    <filtering>true</filtering>
                                    <!-- ACL suites require docker-provisioned ACL users. They are excluded by
                                         default (e.g. the SFCI real-server path, where we cannot provision ACL
                                         users) and re-included only under the docker profile, which overrides
                                         munit.acl.exclude to empty. -->
                                    <excludes>
                                        <exclude>${munit.acl.exclude}</exclude>
                                    </excludes>
                                </resource>
                            </resources>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>com.mulesoft.munit</groupId>
                <artifactId>munit-extensions-maven-plugin</artifactId>
                <version>${munit.extensions.maven.plugin.version}</version>
                <executions>
                    <execution>
                        <phase>integration-test</phase>
                        <goals>
                            <goal>test</goal>
                        </goals>
                    </execution>
                </executions>
                <dependencies>
                    <!-- MUnit Dependencies -->
                    <dependency>
                        <groupId>com.mulesoft.munit</groupId>
                        <artifactId>munit-runner</artifactId>
                        <version>${munit.version}</version>
                        <classifier>mule-plugin</classifier>
                    </dependency>
                    <dependency>
                        <groupId>com.mulesoft.munit</groupId>
                        <artifactId>munit-tools</artifactId>
                        <version>${munit.version}</version>
                        <classifier>mule-plugin</classifier>
                    </dependency>
                </dependencies>
                <configuration>
                    <argLines>
                        <argLine>-javaagent:${settings.localRepository}/org/jacoco/org.jacoco.agent/${jacoco.version}/org.jacoco.agent-${jacoco.version}-runtime.jar=destfile=${session.executionRootDirectory}/target/jacoco-munit.exec</argLine>
                    </argLines>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.jacoco</groupId>
                <artifactId>jacoco-maven-plugin</artifactId>
                <version>${jacoco.version}</version>
                <configuration>
                    <destFile>${session.executionRootDirectory}/target/jacoco-java.exec</destFile>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>prepare-agent</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>merge</id>
                        <phase>verify</phase>
                        <goals>
                            <goal>merge</goal>
                        </goals>
                        <configuration>
                            <destFile>${session.executionRootDirectory}/target/jacoco.exec</destFile>
                            <fileSets>
                                <fileSet>
                                    <directory>${project.build.directory}</directory>
                                    <includes>
                                        <include>*.exec</include>
                                    </includes>
                                </fileSet>
                            </fileSets>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>3.11.0</version>
                <executions>
                    <execution>
                        <id>connector-analyze</id>
                        <phase>prepare-package</phase>
                        <goals>
                            <goal>analyze-only</goal>
                        </goals>
                        <configuration>
                            <multiRelease>${jdeps.multiRelease}</multiRelease>
                            <failOnWarning>true</failOnWarning>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

    <scm>
        <connection>scm:git:git://github.com/mulesoft/mule4-redis-connector.git</connection>
        <developerConnection>scm:git:git@github.com:mulesoft/mule4-redis-connector.git</developerConnection>
        <url>https://github.com/mulesoft/mule4-redis-connector</url>
        <tag>HEAD</tag>
    </scm>
    <repositories>
        <repository>
            <id>mule-releases</id>
            <name>Nexus Public Releases</name>
            <url>https://repository-master.mulesoft.org/nexus/content/repositories/releases/</url>
        </repository>
    </repositories>
    <profiles>
        <profile>
            <!-- Activated only in SFCI / CI where BUILD_AGENT_IP_ADDR is exported.
                 Overrides the default 127.0.0.1 advertised IP so the test JVM (running in a
                 sibling build container) and Redis cluster/sentinel slot responses point at
                 the build host's reachable IP instead of the build container's loopback. -->
            <id>build-agent-ip</id>
            <activation>
                <property>
                    <name>env.BUILD_AGENT_IP_ADDR</name>
                </property>
            </activation>
            <properties>
                <redis.docker.advertised.ip>${env.BUILD_AGENT_IP_ADDR}</redis.docker.advertised.ip>
            </properties>
        </profile>
        <profile>
            <!-- Activated only in SFCI / CI where BUILD_WORKSPACE is exported by
                 strata. Maven runs inside a build container that bind-mounts the
                 host workspace at /cix/src, but the Docker daemon doing the
                 compose bind mount lives on the host and only sees the original
                 host path. BUILD_WORKSPACE carries that host path, so we use it
                 for any Docker volume mount source originating from the project
                 tree (e.g. the TLS certs directory). -->
            <id>build-workspace</id>
            <activation>
                <property>
                    <name>env.BUILD_WORKSPACE</name>
                </property>
            </activation>
            <properties>
                <redis.docker.workspace.path>${env.BUILD_WORKSPACE}</redis.docker.workspace.path>
            </properties>
        </profile>
        <profile>
            <id>default-config</id>
            <activation>
                <property>
                    <name>!mule.security.model</name> <!-- if mule.security.model does not exist -->
                </property>
            </activation>
            <properties>
                <keystore.extension>jks</keystore.extension>
                <truststore.extension>ts</truststore.extension>
                <tls.enabledProtocols>default</tls.enabledProtocols>
            </properties>
        </profile>

        <profile>
            <id>fips140-2-config</id>
            <activation>
                <property>
                    <name>mule.security.model</name>
                    <value>fips140-2</value>
                </property>
            </activation>
            <properties>
                <keystore.extension>bcfks</keystore.extension>
                <truststore.extension>truststore.bcfks</truststore.extension>
                <tls.enabledProtocols>TLSv1.2</tls.enabledProtocols>
            </properties>
        </profile>

        <profile>
            <id>fips140-3-config</id>
            <activation>
                <property>
                    <name>mule.security.model</name>
                    <value>fips140-3</value>
                </property>
            </activation>
            <properties>
                <keystore.extension>bcfks</keystore.extension>
                <truststore.extension>truststore.bcfks</truststore.extension>
                <tls.enabledProtocols>default</tls.enabledProtocols>
            </properties>
        </profile>

        <profile>
            <id>docker</id>
            <activation>
                <os>
                    <family>unix</family>
                </os>
            </activation>
            <properties>
                <!-- Re-include ACL MUnit suites: docker provisions the ACL users they need. -->
                <munit.acl.exclude/>
            </properties>
            <build>
                <testResources>
                    <testResource>
                        <directory>src/test/resources</directory>
                        <filtering>true</filtering>
                        <excludes>
                            <exclude>redis-test-credentials.properties</exclude>
                        </excludes>
                    </testResource>
                    <testResource>
                        <directory>src/test/docker</directory>
                        <filtering>true</filtering>
                        <targetPath>.</targetPath>
                        <includes>
                            <include>redis-test-credentials.properties</include>
                            <include>docker-compose.yml</include>
                        </includes>
                    </testResource>
                </testResources>
                <plugins>
                    <!-- Reserve free TCP ports before resource filtering and before docker compose up.
                         Each portName becomes a Maven property with the reserved port number. -->
                    <plugin>
                        <groupId>org.codehaus.mojo</groupId>
                        <artifactId>build-helper-maven-plugin</artifactId>
                        <version>3.6.1</version>
                        <executions>
                            <!-- Cluster client ports live in a band whose +10000 bus ports
                                 cannot overlap the other reserved services. Redis Cluster
                                 always binds the bus at client_port+10000 (not configurable).
                                 PR-280 #4: 4.11.6 redis-cluster stayed unhealthy for 3
                                 compose-up attempts while 5 sibling matrix legs passed —
                                 a concurrent stack's reserved sentinel/standalone port had
                                 landed on this stack's bus. -->
                            <execution>
                                <id>reserve-redis-cluster-ports</id>
                                <phase>validate</phase>
                                <goals>
                                    <goal>reserve-network-port</goal>
                                </goals>
                                <configuration>
                                    <minPortNumber>20000</minPortNumber>
                                    <maxPortNumber>24999</maxPortNumber>
                                    <randomPort>true</randomPort>
                                    <portNames>
                                        <portName>redis.docker.clusterHosts.port</portName>
                                        <portName>redis.docker.clusterHosts.port2</portName>
                                        <portName>redis.docker.clusterHosts.port3</portName>
                                        <portName>redis.docker.tls.clusterHosts.port</portName>
                                        <portName>redis.docker.tls.clusterHosts.port2</portName>
                                        <portName>redis.docker.tls.clusterHosts.port3</portName>
                                    </portNames>
                                </configuration>
                            </execution>
                            <execution>
                                <id>reserve-redis-ports</id>
                                <!-- Bound to validate (first lifecycle phase) so ports are reserved
                                     before any resource filtering in the parent POM runs.
                                     Floor 36000 sits above cluster-bus (30000-34999). Cap 55000
                                     is leftover from the single-range era; bus overflow is now
                                     prevented by the cluster-port execution above. -->
                                <phase>validate</phase>
                                <goals>
                                    <goal>reserve-network-port</goal>
                                </goals>
                                <configuration>
                                    <minPortNumber>36000</minPortNumber>
                                    <maxPortNumber>55000</maxPortNumber>
                                    <randomPort>true</randomPort>
                                    <portNames>
                                        <portName>redis.docker.port</portName>
                                        <portName>redis.docker.sentinel.host.port</portName>
                                        <portName>redis.docker.sentinel.master.port</portName>
                                        <!-- TLS ports (Redis 8.2.4). Reserved dynamically so parallel
                                             SFCI builds on the same agent never collide on 6384 / 6386
                                             / 26389. Resource filtering of Config.xml and
                                             docker-compose.yml picks up the build-helper runtime value
                                             even though the same names have static defaults in
                                             <properties> for non-docker builds. -->
                                        <portName>redis.docker.tls.host.port</portName>
                                        <portName>redis.docker.tls.sentinel.master.port</portName>
                                        <portName>redis.docker.tls.sentinel.host.port</portName>
                                        <!-- Not actually used as a port; reserved to obtain a unique
                                             integer for the compose project name. Must NOT have a
                                             static default in <properties>, otherwise exec-maven-plugin
                                             would resolve it to the default at plugin-evaluation time
                                             instead of the build-helper-assigned value (the model
                                             default shadows runtime overrides for plugin params, even
                                             though resource filtering picks up the runtime value). -->
                                        <portName>redis.compose.suffix</portName>
                                    </portNames>
                                </configuration>
                            </execution>
                        </executions>
                    </plugin>
                    <!-- Docker Compose lifecycle -->
                    <plugin>
                        <groupId>org.codehaus.mojo</groupId>
                        <artifactId>exec-maven-plugin</artifactId>
                        <version>3.6.3</version>
                        <executions>
                            <!-- Generate TLS certs and JKS/BCFKS keystores before docker-compose-up
                                 so the TLS Redis containers can read /certs/{ca.crt,redis.crt,redis.key}
                                 from the bind-mounted src/test/docker/tls directory. The script is
                                 idempotent (no-op if ca.crt already exists) and uses openssl + keytool
                                 only — both present on the SFCI build image. Plugin executions in the
                                 same phase run in declaration order, so this MUST stay above the
                                 docker-compose-up execution. Invoked via bash so we don't depend on
                                 the executable bit being preserved through git/checkout. -->
                            <execution>
                                <id>generate-tls-certs</id>
                                <phase>pre-integration-test</phase>
                                <goals>
                                    <goal>exec</goal>
                                </goals>
                                <configuration>
                                    <!-- Skip when tests are skipped: the only consumer of the
                                         TLS keystores is MUnit, so a -DskipTests build (e.g. the
                                         compile-build-validation Jenkins stage) has no need to
                                         provision Redis test infrastructure and should not fail
                                         on docker compose pulling images / starting containers. -->
                                    <skip>${skipTests}</skip>
                                    <executable>bash</executable>
                                    <arguments>
                                        <argument>${project.basedir}/src/test/docker/tls/generate-tls-certs.sh</argument>
                                    </arguments>
                                </configuration>
                            </execution>
                            <execution>
                                <id>docker-compose-up</id>
                                <phase>pre-integration-test</phase>
                                <goals>
                                    <goal>exec</goal>
                                </goals>
                                <configuration>
                                    <skip>${skipTests}</skip>
                                    <!-- Wrapper (not raw `docker compose up`) tears down a leftover
                                         stack from a previous Maven in this workspace and re-checks
                                         published host ports before up. Needed because SFCI FIPS can
                                         overlap two verifies in /cix/fips_workspace_* and host-network
                                         cluster ephemeral ports collide with sentinel publish
                                         (PR-280: 0.0.0.0:47076 bind: address already in use). -->
                                    <executable>bash</executable>
                                    <arguments>
                                        <argument>${project.basedir}/src/test/docker/compose-up.sh</argument>
                                        <argument>${project.build.testOutputDirectory}/docker-compose.yml</argument>
                                        <!-- Project name (long-form project-name flag) makes
                                             containers/networks/volumes unique per build, so multiple
                                             Mule runtimes running in parallel on the same Jenkins agent
                                             don't collide. The suffix is redis.compose.suffix (no static
                                             default), reserved by build-helper above; using a property
                                             with a static default (e.g. redis.docker.port) would resolve
                                             to the default here. -->
                                        <argument>redis-${redis.compose.suffix}</argument>
                                        <!-- 240s (raised from 120s): the pr-head matrix runs ~6 runtime
                                             cells in parallel on one agent, each starting 6 Redis containers
                                             (~36 total). Under that contention the TLS cluster occasionally
                                             takes longer than 120s to reach cluster_state:ok, so the compose
                                             wait reports the container unhealthy and the cell fails. Bootstrap
                                             is ~3s uncontended, so a healthy run still returns immediately;
                                             the higher ceiling only absorbs CI load spikes. -->
                                        <argument>240</argument>
                                        <argument>${project.build.directory}</argument>
                                    </arguments>
                                </configuration>
                            </execution>
                            <execution>
                                <id>copy-tls-keystores</id>
                                <phase>pre-integration-test</phase>
                                <goals>
                                    <goal>exec</goal>
                                </goals>
                                <configuration>
                                    <skip>${skipTests}</skip>
                                    <executable>sh</executable>
                                    <arguments>
                                        <argument>-c</argument>
                                        <argument>cp ${project.basedir}/src/test/docker/tls/*.ts ${project.basedir}/src/test/docker/tls/*.jks ${project.basedir}/src/test/docker/tls/*.bcfks ${project.build.testOutputDirectory}/ 2>/dev/null || true</argument>
                                    </arguments>
                                </configuration>
                            </execution>
                            <execution>
                                <id>docker-compose-down</id>
                                <phase>post-integration-test</phase>
                                <goals>
                                    <goal>exec</goal>
                                </goals>
                                <configuration>
                                    <skip>${skipTests}</skip>
                                    <executable>docker</executable>
                                    <arguments>
                                        <argument>compose</argument>
                                        <argument>--project-name</argument>
                                        <argument>redis-${redis.compose.suffix}</argument>
                                        <argument>-f</argument>
                                        <argument>${project.build.testOutputDirectory}/docker-compose.yml</argument>
                                        <argument>down</argument>
                                        <argument>-v</argument>
                                    </arguments>
                                </configuration>
                            </execution>
                        </executions>
                    </plugin>
                </plugins>
            </build>
        </profile>
    </profiles>
</project>
