diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 721a6707..e5333445 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -59,9 +59,9 @@ jobs: if: matrix.jdk == '8' && github.event_name == 'pull_request' && github.ref != 'refs/heads/master' && github.ref != 'refs/heads/development' run: mvn checkstyle::check - - name: Deploy - if: matrix.jdk == '8' && github.event_name == 'push' && github.ref != 'refs/heads/master' && github.ref != 'refs/heads/development' - run: mvn --batch-mode deploy -P test +# - name: Deploy +# if: matrix.jdk == '8' && github.event_name == 'push' && github.ref != 'refs/heads/master' && github.ref != 'refs/heads/development' +# run: mvn --batch-mode deploy -P test - name: SonarQube Scan (Push) if: matrix.jdk == '11' && github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/development') diff --git a/CHANGES.txt b/CHANGES.txt index a99b79df..ceaef9e6 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,8 @@ +4.16.1 (Jul 21, 2025) +- Fixed vulnerabilities: + - Upgraded org.apache.commons-commons-lang3 to 3.18.0 + - Upgraded com.google.code.gson.gson to 2.13.1 + 4.16.0 (May 28, 2025) - Added support for rule-based segments. These segments determine membership at runtime by evaluating their configured rules against the user attributes provided to the SDK. - Added support for feature flag prerequisites. This allows customers to define dependency conditions between flags, which are evaluated before any allowlists or targeting rules. diff --git a/client/pom.xml b/client/pom.xml index d0ae4a78..b6337c14 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -5,9 +5,9 @@ io.split.client java-client-parent - 4.16.0 + 4.16.1 - 4.16.0 + 4.16.1 java-client jar Java Client @@ -19,12 +19,15 @@ - org.sonatype.plugins - nexus-staging-maven-plugin - 1.6.3 + org.sonatype.central + central-publishing-maven-plugin + 0.8.0 true - false + true + central + false + published @@ -173,7 +176,7 @@ com.google.code.gson gson - 2.9.0 + 2.13.1 org.yaml @@ -185,7 +188,7 @@ org.apache.commons commons-lang3 - 3.4 + 3.18.0 test diff --git a/client/src/main/java/io/split/client/events/EventsSender.java b/client/src/main/java/io/split/client/events/EventsSender.java index 2c023ef3..d83969dc 100644 --- a/client/src/main/java/io/split/client/events/EventsSender.java +++ b/client/src/main/java/io/split/client/events/EventsSender.java @@ -12,7 +12,7 @@ import java.net.URISyntaxException; import java.util.List; -import static com.google.gson.internal.$Gson$Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkNotNull; public class EventsSender { diff --git a/client/src/main/java/io/split/client/events/InMemoryEventsStorage.java b/client/src/main/java/io/split/client/events/InMemoryEventsStorage.java index fae0d070..a3463f0e 100644 --- a/client/src/main/java/io/split/client/events/InMemoryEventsStorage.java +++ b/client/src/main/java/io/split/client/events/InMemoryEventsStorage.java @@ -12,7 +12,7 @@ import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; -import static com.google.gson.internal.$Gson$Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkNotNull; public class InMemoryEventsStorage implements EventsStorage{ diff --git a/client/src/main/java/io/split/client/impressions/UniqueKeysTrackerImp.java b/client/src/main/java/io/split/client/impressions/UniqueKeysTrackerImp.java index bd2ff918..80b3703d 100644 --- a/client/src/main/java/io/split/client/impressions/UniqueKeysTrackerImp.java +++ b/client/src/main/java/io/split/client/impressions/UniqueKeysTrackerImp.java @@ -117,7 +117,7 @@ private void sendUniqueKeys(){ } try { if (uniqueKeysTracker.size() == 0) { - _log.warn("The Unique Keys Tracker is empty"); + _log.debug("The Unique Keys Tracker is empty"); return; } HashMap> uniqueKeysHashMap = popAll(); diff --git a/client/src/main/java/io/split/storages/memory/RuleBasedSegmentCacheInMemoryImp.java b/client/src/main/java/io/split/storages/memory/RuleBasedSegmentCacheInMemoryImp.java index 53730cf9..660811ca 100644 --- a/client/src/main/java/io/split/storages/memory/RuleBasedSegmentCacheInMemoryImp.java +++ b/client/src/main/java/io/split/storages/memory/RuleBasedSegmentCacheInMemoryImp.java @@ -104,6 +104,6 @@ public Set getSegments() { @Override public boolean contains(Set ruleBasedSegmentNames) { - return getSegments().containsAll(ruleBasedSegmentNames); + return _concurrentMap.keySet().containsAll(ruleBasedSegmentNames); } } \ No newline at end of file diff --git a/client/src/main/java/io/split/storages/pluggable/adapters/UserCustomRuleBasedSegmentAdapterConsumer.java b/client/src/main/java/io/split/storages/pluggable/adapters/UserCustomRuleBasedSegmentAdapterConsumer.java index 438b7bf8..b04e4976 100644 --- a/client/src/main/java/io/split/storages/pluggable/adapters/UserCustomRuleBasedSegmentAdapterConsumer.java +++ b/client/src/main/java/io/split/storages/pluggable/adapters/UserCustomRuleBasedSegmentAdapterConsumer.java @@ -96,7 +96,7 @@ private List stringsToParsedRuleBasedSegments(List ruleBasedSegmentNames) { - return getSegments().containsAll(ruleBasedSegmentNames); + return _userStorageWrapper.getKeysByPrefix(PrefixAdapter.buildGetAllRuleBasedSegment()).containsAll(ruleBasedSegmentNames); } } \ No newline at end of file diff --git a/client/src/test/java/io/split/storages/memory/RuleBasedSegmentCacheInMemoryImplTest.java b/client/src/test/java/io/split/storages/memory/RuleBasedSegmentCacheInMemoryImplTest.java index 32487bf5..492cc8ae 100644 --- a/client/src/test/java/io/split/storages/memory/RuleBasedSegmentCacheInMemoryImplTest.java +++ b/client/src/test/java/io/split/storages/memory/RuleBasedSegmentCacheInMemoryImplTest.java @@ -16,6 +16,8 @@ import com.google.common.collect.Lists; import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; import java.util.List; public class RuleBasedSegmentCacheInMemoryImplTest extends TestCase { @@ -31,6 +33,8 @@ public void testAddAndDeleteSegment(){ ruleBasedSegmentCache.update(Lists.newArrayList(parsedRuleBasedSegment), null, 123); assertEquals(123, ruleBasedSegmentCache.getChangeNumber()); assertEquals(parsedRuleBasedSegment, ruleBasedSegmentCache.get("sample_rule_based_segment")); + assertTrue(ruleBasedSegmentCache.contains(new HashSet<>(Arrays.asList("sample_rule_based_segment")))); + assertFalse(ruleBasedSegmentCache.contains(new HashSet<>(Arrays.asList("sample_rule_based_segment", "123")))); ruleBasedSegmentCache.update(null, Lists.newArrayList("sample_rule_based_segment"), 124); assertEquals(124, ruleBasedSegmentCache.getChangeNumber()); @@ -62,5 +66,7 @@ public void testMultipleSegment(){ ruleBasedSegmentCache.update(Lists.newArrayList(parsedRuleBasedSegment1, parsedRuleBasedSegment2), null, 123); assertEquals(Lists.newArrayList("another_rule_based_segment", "sample_rule_based_segment"), ruleBasedSegmentCache.ruleBasedSegmentNames()); assertEquals(Sets.newHashSet("segment2", "segment1", "employees"), ruleBasedSegmentCache.getSegments()); + assertTrue(ruleBasedSegmentCache.contains(new HashSet<>(Arrays.asList("sample_rule_based_segment", "another_rule_based_segment")))); + assertTrue(ruleBasedSegmentCache.contains(new HashSet<>(Arrays.asList("sample_rule_based_segment")))); } } \ No newline at end of file diff --git a/client/src/test/java/io/split/storages/pluggable/adapters/UserCustomRuleBasedSegmentAdapterConsumerTest.java b/client/src/test/java/io/split/storages/pluggable/adapters/UserCustomRuleBasedSegmentAdapterConsumerTest.java index f1f39a73..b9baee95 100644 --- a/client/src/test/java/io/split/storages/pluggable/adapters/UserCustomRuleBasedSegmentAdapterConsumerTest.java +++ b/client/src/test/java/io/split/storages/pluggable/adapters/UserCustomRuleBasedSegmentAdapterConsumerTest.java @@ -1,6 +1,7 @@ package io.split.storages.pluggable.adapters; import com.google.common.collect.Lists; +import com.google.common.collect.Maps; import io.split.client.dtos.*; import io.split.client.utils.Json; import io.split.engine.ConditionsTestUtil; @@ -16,10 +17,14 @@ import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.*; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicLong; import java.util.stream.Collectors; import java.util.stream.Stream; import static io.split.TestHelper.makeRuleBasedSegment; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; public class UserCustomRuleBasedSegmentAdapterConsumerTest { @@ -66,10 +71,16 @@ public void testGetChangeNumberWithGsonFailing() { public void testGetRuleBasedSegment() { RuleBasedSegmentParser ruleBasedSegmentParser = new RuleBasedSegmentParser(); RuleBasedSegment ruleBasedSegment = getRuleBasedSegment(RULE_BASED_SEGMENT_NAME); + ParsedRuleBasedSegment expected = ruleBasedSegmentParser.parse(ruleBasedSegment); + ConcurrentMap rbsCollection = Maps.newConcurrentMap(); + rbsCollection.put(RULE_BASED_SEGMENT_NAME, expected); Mockito.when(_userStorageWrapper.get(PrefixAdapter.buildRuleBasedSegmentKey(RULE_BASED_SEGMENT_NAME))).thenReturn(getRuleBasedSegmentAsJson(ruleBasedSegment)); + Mockito.when(_userStorageWrapper.getKeysByPrefix("SPLITIO.rbsegment*")).thenReturn(new HashSet<>(Arrays.asList(RULE_BASED_SEGMENT_NAME))); ParsedRuleBasedSegment result = _userCustomRuleBasedSegmentAdapterConsumer.get(RULE_BASED_SEGMENT_NAME); - ParsedRuleBasedSegment expected = ruleBasedSegmentParser.parse(ruleBasedSegment); Assert.assertEquals(expected, result); + assertTrue(_userCustomRuleBasedSegmentAdapterConsumer.contains(new HashSet<>(Arrays.asList(RULE_BASED_SEGMENT_NAME)))); + assertFalse(_userCustomRuleBasedSegmentAdapterConsumer.contains(new HashSet<>(Arrays.asList(RULE_BASED_SEGMENT_NAME, "123")))); + } @Test @@ -135,7 +146,7 @@ public void testGetSegments() { Mockito.when(_userStorageWrapper.getMany(Mockito.anyObject())). thenReturn(getManyExpected); HashSet segmentResult = (HashSet) _userCustomRuleBasedSegmentAdapterConsumer.getSegments(); - Assert.assertTrue(segmentResult.contains("employee")); + assertTrue(segmentResult.contains("employee")); } @Test diff --git a/okhttp-modules/pom.xml b/okhttp-modules/pom.xml index a8645f9c..7346518d 100644 --- a/okhttp-modules/pom.xml +++ b/okhttp-modules/pom.xml @@ -5,10 +5,10 @@ java-client-parent io.split.client - 4.16.0 + 4.16.1 4.0.0 - 4.16.0 + 4.16.1 okhttp-modules jar http-modules @@ -20,12 +20,15 @@ - org.sonatype.plugins - nexus-staging-maven-plugin - 1.6.3 + org.sonatype.central + central-publishing-maven-plugin + 0.8.0 true - false + true + central + false + published diff --git a/pluggable-storage/pom.xml b/pluggable-storage/pom.xml index 21b0bdac..5c304f98 100644 --- a/pluggable-storage/pom.xml +++ b/pluggable-storage/pom.xml @@ -6,7 +6,7 @@ java-client-parent io.split.client - 4.16.0 + 4.16.1 2.1.0 @@ -21,15 +21,15 @@ - org.sonatype.plugins - nexus-staging-maven-plugin - 1.6.3 + org.sonatype.central + central-publishing-maven-plugin + 0.8.0 true - ossrh - https://oss.sonatype.org/ - true - true + true + central + false + published diff --git a/pom.xml b/pom.xml index 7b21f1ec..9f91ded1 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 io.split.client java-client-parent - 4.16.0 + 4.16.1 @@ -47,31 +47,14 @@ scm:git@github.com:splitio/java-client.git git@github.com:splitio/java-client.git - - - ossrh - https://oss.sonatype.org/content/repositories/snapshots - - - ossrh - https://oss.sonatype.org/content/repositories/releases - - + ossrh https://oss.sonatype.org/content/repositories/releases - - maven-all-virtual - https://splitio.jfrog.io/artifactory/maven-all-virtual - - - maven-all-virtual - https://splitio.jfrog.io/artifactory/maven-all-virtual - UTF-8 @@ -154,16 +137,6 @@ test - - - maven-dev - https://splitio.jfrog.io/artifactory/maven-dev/ - - - maven-dev - https://splitio.jfrog.io/artifactory/maven-dev/ - - @@ -188,16 +161,7 @@ release - - - ossrh - https://oss.sonatype.org/content/repositories/snapshots - - - ossrh - https://oss.sonatype.org/content/repositories/releases - - + @@ -230,16 +194,16 @@ - + - org.sonatype.plugins - nexus-staging-maven-plugin - 1.6.3 + org.sonatype.central + central-publishing-maven-plugin + 0.8.0 true - ossrh - https://oss.sonatype.org/ - true + central + false + published diff --git a/redis-wrapper/pom.xml b/redis-wrapper/pom.xml index 301739ce..9ca70894 100644 --- a/redis-wrapper/pom.xml +++ b/redis-wrapper/pom.xml @@ -6,7 +6,7 @@ java-client-parent io.split.client - 4.16.0 + 4.16.1 redis-wrapper 3.1.1 @@ -43,15 +43,15 @@ - org.sonatype.plugins - nexus-staging-maven-plugin - 1.6.3 + org.sonatype.central + central-publishing-maven-plugin + 0.8.0 true - ossrh - https://oss.sonatype.org/ - true - true + true + central + false + published diff --git a/testing/pom.xml b/testing/pom.xml index 0fae6cdf..5f0aa0c5 100644 --- a/testing/pom.xml +++ b/testing/pom.xml @@ -5,7 +5,7 @@ io.split.client java-client-parent - 4.16.0 + 4.16.1 java-client-testing jar @@ -31,15 +31,15 @@ - org.sonatype.plugins - nexus-staging-maven-plugin - 1.6.3 + org.sonatype.central + central-publishing-maven-plugin + 0.8.0 true - ossrh - https://oss.sonatype.org/ - true - false + central + false + published + true diff --git a/update_maven_settings.sh b/update_maven_settings.sh new file mode 100755 index 00000000..8bea975f --- /dev/null +++ b/update_maven_settings.sh @@ -0,0 +1,161 @@ +#!/bin/bash + +# Script to update Maven settings.xml with Central Repository credentials using xmlstarlet + +# ANSI color codes +GREEN='\033[0;32m' +YELLOW='\033[0;33m' +BLUE='\033[0;34m' +RED='\033[0;31m' +NC='\033[0m' # No Color + +# Check if xmlstarlet is installed +if ! command -v xmlstarlet &> /dev/null; then + echo -e "${RED}Error: xmlstarlet is not installed.${NC}" + echo "Please install xmlstarlet first:" + echo " macOS: brew install xmlstarlet" + echo " Debian/Ubuntu: sudo apt-get install xmlstarlet" + echo " RHEL/CentOS/Fedora: sudo yum install xmlstarlet" + echo "Then run this script again." + exit 1 +fi + +# Default values +DEFAULT_SETTINGS_PATH="$HOME/.m2/settings.xml" +DEFAULT_SERVER_ID="central" + +echo -e "${BLUE}Maven Settings.xml Update Script${NC}" +echo "This script will update your Maven settings.xml with Central Repository credentials." +echo + +# Ask for settings.xml path or use default +read -p "Path to settings.xml [$DEFAULT_SETTINGS_PATH]: " SETTINGS_PATH +SETTINGS_PATH=${SETTINGS_PATH:-$DEFAULT_SETTINGS_PATH} + +# Variables to store existing values +EXISTING_USERNAME="" +EXISTING_PASSWORD="" + +# Extract existing values if settings.xml exists +if [ -f "$SETTINGS_PATH" ] && command -v xmlstarlet &> /dev/null; then + # Check if the file is valid XML + if xmlstarlet val "$SETTINGS_PATH" &> /dev/null; then + echo -e "${YELLOW}Reading existing settings from ${SETTINGS_PATH}...${NC}" + + # Extract existing server ID + DEFAULT_SERVER_ID=$(xmlstarlet sel -t -v "/settings/servers/server[1]/id" "$SETTINGS_PATH" 2>/dev/null || echo "$DEFAULT_SERVER_ID") + + # Extract existing username and password for the server + EXISTING_USERNAME=$(xmlstarlet sel -t -v "/settings/servers/server[id='$DEFAULT_SERVER_ID']/username" "$SETTINGS_PATH" 2>/dev/null || echo "") + EXISTING_PASSWORD=$(xmlstarlet sel -t -v "/settings/servers/server[id='$DEFAULT_SERVER_ID']/password" "$SETTINGS_PATH" 2>/dev/null || echo "") + fi +fi + +# Ask for server ID or use default/existing +read -p "Server ID [$DEFAULT_SERVER_ID]: " SERVER_ID +SERVER_ID=${SERVER_ID:-$DEFAULT_SERVER_ID} + +# Ask for username (show existing if available) +USERNAME_PROMPT="Username" +if [ -n "$EXISTING_USERNAME" ]; then + USERNAME_PROMPT="Username (current: $EXISTING_USERNAME)" +fi +read -p "$USERNAME_PROMPT: " USERNAME +USERNAME=${USERNAME:-$EXISTING_USERNAME} + +# Ask for password (indicate if existing) +PASSWORD_PROMPT="Password" +if [ -n "$EXISTING_PASSWORD" ]; then + PASSWORD_PROMPT="Password (leave empty to keep current)" +fi +read -s -p "$PASSWORD_PROMPT: " PASSWORD +echo +# Only use existing password if the user didn't enter a new one +if [ -z "$PASSWORD" ] && [ -n "$EXISTING_PASSWORD" ]; then + PASSWORD="$EXISTING_PASSWORD" +fi + +# Create .m2 directory if it doesn't exist +M2_DIR=$(dirname "$SETTINGS_PATH") +mkdir -p "$M2_DIR" + +# No GPG configuration needed + +# Function to create a new settings.xml file +create_new_settings() { + echo -e "${YELLOW}Creating new settings.xml file...${NC}" + cat > "$SETTINGS_PATH" << EOF + + + + + $SERVER_ID + $USERNAME + $PASSWORD + + + +EOF +} + +# Check if settings.xml exists +if [ -f "$SETTINGS_PATH" ]; then + echo -e "${YELLOW}Existing settings.xml found. Backing up to ${SETTINGS_PATH}.bak${NC}" + cp "$SETTINGS_PATH" "${SETTINGS_PATH}.bak" + + # Check if the file is valid XML + if ! xmlstarlet val "$SETTINGS_PATH" &> /dev/null; then + echo -e "${RED}Warning: The existing settings.xml is not valid XML.${NC}" + read -p "Do you want to create a new settings.xml file? (y/n): " CREATE_NEW + if [[ $CREATE_NEW =~ ^[Yy]$ ]]; then + create_new_settings + else + echo -e "${RED}Exiting without making changes.${NC}" + exit 1 + fi + else + # Check if servers element exists + if ! xmlstarlet sel -t -v "/settings/servers" "$SETTINGS_PATH" &> /dev/null; then + echo -e "${YELLOW}No servers section found. Adding servers section...${NC}" + xmlstarlet ed --inplace \ + -s "/settings" -t elem -n "servers" \ + -s "/settings/servers" -t elem -n "server" \ + -s "/settings/servers/server" -t elem -n "id" -v "$SERVER_ID" \ + -s "/settings/servers/server" -t elem -n "username" -v "$USERNAME" \ + -s "/settings/servers/server" -t elem -n "password" -v "$PASSWORD" \ + "$SETTINGS_PATH" + else + # Check if server with this ID already exists + if xmlstarlet sel -t -v "/settings/servers/server[id='$SERVER_ID']" "$SETTINGS_PATH" &> /dev/null; then + echo -e "${YELLOW}Server with ID '$SERVER_ID' already exists. Updating credentials...${NC}" + # Update existing server credentials + xmlstarlet ed --inplace \ + -u "/settings/servers/server[id='$SERVER_ID']/username" -v "$USERNAME" \ + -u "/settings/servers/server[id='$SERVER_ID']/password" -v "$PASSWORD" \ + "$SETTINGS_PATH" + else + echo -e "${YELLOW}Adding new server with ID '$SERVER_ID'...${NC}" + # Add new server to existing servers section + xmlstarlet ed --inplace \ + -s "/settings/servers" -t elem -n "server" \ + -s "/settings/servers/server[last()]" -t elem -n "id" -v "$SERVER_ID" \ + -s "/settings/servers/server[last()]" -t elem -n "username" -v "$USERNAME" \ + -s "/settings/servers/server[last()]" -t elem -n "password" -v "$PASSWORD" \ + "$SETTINGS_PATH" + fi + fi + fi +else + create_new_settings +fi + +# Make sure the file has the right permissions +chmod 600 "$SETTINGS_PATH" + +echo -e "${GREEN}Maven settings.xml updated successfully at $SETTINGS_PATH${NC}" +echo -e "${GREEN}Server ID: $SERVER_ID${NC}" +echo -e "${GREEN}Username: $USERNAME${NC}" +echo -e "${GREEN}Password: ********${NC}" +