feat: add SensitiveKeysMerger with case-insensitive union dedup
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,45 @@
|
|||||||
|
package com.cameleer3.server.core.admin;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merges global (enforced) sensitive keys with per-app additions.
|
||||||
|
* Union-only: per-app can add keys, never remove global keys.
|
||||||
|
* Case-insensitive deduplication, preserves first-seen casing.
|
||||||
|
*/
|
||||||
|
public final class SensitiveKeysMerger {
|
||||||
|
|
||||||
|
private SensitiveKeysMerger() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param global enforced global keys (null = not configured)
|
||||||
|
* @param perApp per-app additional keys (null = none)
|
||||||
|
* @return merged list, or null if both inputs are null
|
||||||
|
*/
|
||||||
|
public static List<String> merge(List<String> global, List<String> perApp) {
|
||||||
|
if (global == null && perApp == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
TreeSet<String> seen = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
|
||||||
|
List<String> result = new ArrayList<>();
|
||||||
|
|
||||||
|
if (global != null) {
|
||||||
|
for (String key : global) {
|
||||||
|
if (seen.add(key)) {
|
||||||
|
result.add(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (perApp != null) {
|
||||||
|
for (String key : perApp) {
|
||||||
|
if (seen.add(key)) {
|
||||||
|
result.add(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
package com.cameleer3.server.core.admin;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
class SensitiveKeysMergerTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void bothNull_returnsNull() {
|
||||||
|
assertNull(SensitiveKeysMerger.merge(null, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void globalOnly_returnsGlobal() {
|
||||||
|
List<String> result = SensitiveKeysMerger.merge(
|
||||||
|
List.of("Authorization", "Cookie"), null);
|
||||||
|
assertEquals(List.of("Authorization", "Cookie"), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void perAppOnly_returnsPerApp() {
|
||||||
|
List<String> result = SensitiveKeysMerger.merge(
|
||||||
|
null, List.of("X-Internal-*"));
|
||||||
|
assertEquals(List.of("X-Internal-*"), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void union_mergesWithoutDuplicates() {
|
||||||
|
List<String> result = SensitiveKeysMerger.merge(
|
||||||
|
List.of("Authorization", "Cookie"),
|
||||||
|
List.of("Cookie", "X-Custom"));
|
||||||
|
assertEquals(List.of("Authorization", "Cookie", "X-Custom"), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void caseInsensitiveDedup_preservesFirstCasing() {
|
||||||
|
List<String> result = SensitiveKeysMerger.merge(
|
||||||
|
List.of("Authorization"),
|
||||||
|
List.of("authorization", "AUTHORIZATION"));
|
||||||
|
assertEquals(List.of("Authorization"), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void emptyGlobal_returnsEmptyList() {
|
||||||
|
List<String> result = SensitiveKeysMerger.merge(List.of(), null);
|
||||||
|
assertEquals(List.of(), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void emptyGlobalWithPerApp_returnsPerApp() {
|
||||||
|
List<String> result = SensitiveKeysMerger.merge(
|
||||||
|
List.of(), List.of("X-Custom"));
|
||||||
|
assertEquals(List.of("X-Custom"), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void globPatterns_preserved() {
|
||||||
|
List<String> result = SensitiveKeysMerger.merge(
|
||||||
|
List.of("*password*", "*secret*"),
|
||||||
|
List.of("X-Internal-*"));
|
||||||
|
assertEquals(List.of("*password*", "*secret*", "X-Internal-*"), result);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user