diff --git a/golemcore/slack/plugin.yaml b/golemcore/slack/plugin.yaml
index 8797145..678865c 100644
--- a/golemcore/slack/plugin.yaml
+++ b/golemcore/slack/plugin.yaml
@@ -1,7 +1,7 @@
id: golemcore/slack
provider: golemcore
name: slack
-version: 1.0.3
+version: 1.0.4
pluginApiVersion: 1
engineVersion: ">=0.0.0 <1.0.0"
entrypoint: me.golemcore.plugins.golemcore.slack.SlackPluginBootstrap
diff --git a/golemcore/slack/pom.xml b/golemcore/slack/pom.xml
index ab9f7f2..69b20ec 100644
--- a/golemcore/slack/pom.xml
+++ b/golemcore/slack/pom.xml
@@ -9,7 +9,7 @@
../../pom.xml
- 1.0.3
+ 1.0.4
golemcore-slack-plugin
golemcore/slack
Slack Socket Mode channel plugin with interactive approvals for GolemCore
diff --git a/golemcore/slack/src/main/java/me/golemcore/plugins/golemcore/slack/SlackPluginConfig.java b/golemcore/slack/src/main/java/me/golemcore/plugins/golemcore/slack/SlackPluginConfig.java
index 6913d20..8d2c0de 100644
--- a/golemcore/slack/src/main/java/me/golemcore/plugins/golemcore/slack/SlackPluginConfig.java
+++ b/golemcore/slack/src/main/java/me/golemcore/plugins/golemcore/slack/SlackPluginConfig.java
@@ -7,11 +7,6 @@
import lombok.Data;
import lombok.NoArgsConstructor;
-import java.util.ArrayList;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Set;
-
@JsonIgnoreProperties(ignoreUnknown = true)
@Data
@NoArgsConstructor
@@ -28,12 +23,6 @@ public class SlackPluginConfig {
@Builder.Default
private Boolean replyInThread = true;
- @Builder.Default
- private List allowedUserIds = new ArrayList<>();
-
- @Builder.Default
- private List allowedChannelIds = new ArrayList<>();
-
public void normalize() {
if (enabled == null) {
enabled = false;
@@ -43,8 +32,6 @@ public void normalize() {
}
botToken = normalizeSecret(botToken);
appToken = normalizeSecret(appToken);
- allowedUserIds = normalizeIdentifiers(allowedUserIds);
- allowedChannelIds = normalizeIdentifiers(allowedChannelIds);
}
@JsonIgnore
@@ -60,21 +47,4 @@ private String normalizeSecret(String value) {
String normalized = value.trim();
return normalized.isBlank() ? null : normalized;
}
-
- private List normalizeIdentifiers(List values) {
- if (values == null || values.isEmpty()) {
- return List.of();
- }
- Set normalized = new LinkedHashSet<>();
- for (String value : values) {
- if (value == null) {
- continue;
- }
- String candidate = value.trim();
- if (!candidate.isBlank()) {
- normalized.add(candidate);
- }
- }
- return List.copyOf(normalized);
- }
}
diff --git a/golemcore/slack/src/main/java/me/golemcore/plugins/golemcore/slack/SlackPluginSettingsContributor.java b/golemcore/slack/src/main/java/me/golemcore/plugins/golemcore/slack/SlackPluginSettingsContributor.java
index 76ab8c9..84935fe 100644
--- a/golemcore/slack/src/main/java/me/golemcore/plugins/golemcore/slack/SlackPluginSettingsContributor.java
+++ b/golemcore/slack/src/main/java/me/golemcore/plugins/golemcore/slack/SlackPluginSettingsContributor.java
@@ -56,8 +56,6 @@ public PluginSettingsSection getSection(String sectionKey) {
values.put("botToken", "");
values.put("appToken", "");
values.put("replyInThread", Boolean.TRUE.equals(config.getReplyInThread()));
- values.put("allowedUserIds", String.join(", ", config.getAllowedUserIds()));
- values.put("allowedChannelIds", String.join(", ", config.getAllowedChannelIds()));
return PluginSettingsSection.builder()
.title("Slack")
@@ -92,21 +90,6 @@ public PluginSettingsSection getSection(String sectionKey) {
.label("Reply In Threads")
.description(
"Route channel mentions into one session per root thread and answer in that thread.")
- .build(),
- PluginSettingsField.builder()
- .key("allowedUserIds")
- .type("text")
- .label("Allowed User IDs")
- .description("Optional comma-separated Slack user ids. Leave blank to allow any user.")
- .placeholder("U01234567, U08999999")
- .build(),
- PluginSettingsField.builder()
- .key("allowedChannelIds")
- .type("text")
- .label("Allowed Channel IDs")
- .description(
- "Optional comma-separated Slack channel ids. Leave blank to allow any channel or DM.")
- .placeholder("C01234567, D08999999")
.build()))
.values(values)
.blocks(List.of(PluginSettingsBlock.builder()
@@ -141,9 +124,6 @@ public PluginSettingsSection saveSection(String sectionKey, Map
config.setAppToken(appToken);
}
- config.setAllowedUserIds(parseCsv(readString(values, "allowedUserIds", "")));
- config.setAllowedChannelIds(parseCsv(readString(values, "allowedChannelIds", "")));
-
configService.save(config);
eventPublisher.publishEvent(new SlackRestartEvent());
return getSection(sectionKey);
@@ -177,15 +157,4 @@ private String readString(Map values, String key, String default
Object value = values.get(key);
return value instanceof String text ? text : defaultValue;
}
-
- private List parseCsv(String raw) {
- if (raw == null || raw.isBlank()) {
- return List.of();
- }
- return java.util.Arrays.stream(raw.split(","))
- .map(String::trim)
- .filter(value -> !value.isBlank())
- .distinct()
- .toList();
- }
}
diff --git a/golemcore/slack/src/main/java/me/golemcore/plugins/golemcore/slack/adapter/inbound/slack/SlackAdapter.java b/golemcore/slack/src/main/java/me/golemcore/plugins/golemcore/slack/adapter/inbound/slack/SlackAdapter.java
index bc22061..1e508f0 100644
--- a/golemcore/slack/src/main/java/me/golemcore/plugins/golemcore/slack/adapter/inbound/slack/SlackAdapter.java
+++ b/golemcore/slack/src/main/java/me/golemcore/plugins/golemcore/slack/adapter/inbound/slack/SlackAdapter.java
@@ -180,8 +180,7 @@ public CompletableFuture sendProgressUpdate(String chatId, ProgressUpdate
@Override
public boolean isAuthorized(String senderId) {
- SlackPluginConfig config = configService.getConfig();
- return config.getAllowedUserIds().isEmpty() || config.getAllowedUserIds().contains(senderId);
+ return true;
}
@Override
@@ -214,14 +213,6 @@ private void handleInbound(SlackInboundEnvelope envelope) {
if (envelope == null) {
return;
}
- if (!isAuthorized(envelope.userId())) {
- log.warn("[Slack] Ignoring message from unauthorized user {}", envelope.userId());
- return;
- }
- if (!isChannelAllowed(envelope.channelId())) {
- log.warn("[Slack] Ignoring message from unauthorized channel {}", envelope.channelId());
- return;
- }
if (requiresExistingConversation(envelope) && !hasExistingConversation(envelope)) {
log.debug("[Slack] Ignoring thread reply without active conversation {}", envelope.rootThreadTs());
return;
@@ -239,15 +230,6 @@ private void handleAction(SlackActionEnvelope envelope) {
if (envelope == null) {
return;
}
- if (!isAuthorized(envelope.userId())) {
- log.warn("[Slack] Ignoring action from unauthorized user {}", envelope.userId());
- return;
- }
- if (!isChannelAllowed(envelope.channelId())) {
- log.warn("[Slack] Ignoring action from unauthorized channel {}", envelope.channelId());
- return;
- }
-
String actionId = envelope.actionId();
if (SlackActionIds.CONFIRM_APPROVE.equals(actionId) || SlackActionIds.CONFIRM_CANCEL.equals(actionId)) {
eventPublisher.publishEvent(new ConfirmationCallbackEvent(
@@ -266,11 +248,6 @@ private void handleAction(SlackActionEnvelope envelope) {
}
}
- private boolean isChannelAllowed(String channelId) {
- SlackPluginConfig config = configService.getConfig();
- return config.getAllowedChannelIds().isEmpty() || config.getAllowedChannelIds().contains(channelId);
- }
-
private Message buildInboundMessage(SlackInboundEnvelope envelope) {
SlackConversationTarget target = resolveConversationTarget(envelope);
diff --git a/golemcore/slack/src/test/java/me/golemcore/plugins/golemcore/slack/SlackPluginConfigServiceTest.java b/golemcore/slack/src/test/java/me/golemcore/plugins/golemcore/slack/SlackPluginConfigServiceTest.java
index 989da9d..990b9f0 100644
--- a/golemcore/slack/src/test/java/me/golemcore/plugins/golemcore/slack/SlackPluginConfigServiceTest.java
+++ b/golemcore/slack/src/test/java/me/golemcore/plugins/golemcore/slack/SlackPluginConfigServiceTest.java
@@ -5,6 +5,8 @@
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -18,6 +20,7 @@ class SlackPluginConfigServiceTest {
private PluginConfigurationService pluginConfigurationService;
private SlackPluginConfigService service;
+ private final ObjectMapper objectMapper = new ObjectMapper();
@BeforeEach
void setUp() {
@@ -37,12 +40,13 @@ void shouldIgnoreLegacyConfiguredFieldWhenReadingStoredPluginConfig() {
"allowedChannelIds", java.util.List.of("C123")));
SlackPluginConfig config = service.getConfig();
+ Map serialized = objectMapper.convertValue(config, Map.class);
assertEquals("xoxb-test", config.getBotToken());
assertEquals("xapp-test", config.getAppToken());
assertFalse(Boolean.TRUE.equals(config.getReplyInThread()));
- assertEquals(java.util.List.of("U123"), config.getAllowedUserIds());
- assertEquals(java.util.List.of("C123"), config.getAllowedChannelIds());
+ assertFalse(serialized.containsKey("allowedUserIds"));
+ assertFalse(serialized.containsKey("allowedChannelIds"));
}
@Test
@@ -52,8 +56,6 @@ void shouldPersistNormalizedPluginConfigWithoutComputedFields() {
.botToken(" xoxb-token ")
.appToken(" xapp-token ")
.replyInThread(null)
- .allowedUserIds(java.util.List.of(" U123 ", "", "U123"))
- .allowedChannelIds(java.util.List.of(" C123 ", "C123"))
.build();
service.save(config);
@@ -66,8 +68,8 @@ void shouldPersistNormalizedPluginConfigWithoutComputedFields() {
assertEquals("xapp-token", saved.get("appToken"));
assertEquals(true, saved.get("enabled"));
assertEquals(true, saved.get("replyInThread"));
- assertEquals(java.util.List.of("U123"), saved.get("allowedUserIds"));
- assertEquals(java.util.List.of("C123"), saved.get("allowedChannelIds"));
+ assertFalse(saved.containsKey("allowedUserIds"));
+ assertFalse(saved.containsKey("allowedChannelIds"));
assertFalse(saved.containsKey("configured"));
}
}
diff --git a/golemcore/slack/src/test/java/me/golemcore/plugins/golemcore/slack/SlackPluginConfigTest.java b/golemcore/slack/src/test/java/me/golemcore/plugins/golemcore/slack/SlackPluginConfigTest.java
index 2c9ca2d..ec0fc89 100644
--- a/golemcore/slack/src/test/java/me/golemcore/plugins/golemcore/slack/SlackPluginConfigTest.java
+++ b/golemcore/slack/src/test/java/me/golemcore/plugins/golemcore/slack/SlackPluginConfigTest.java
@@ -2,8 +2,6 @@
import org.junit.jupiter.api.Test;
-import java.util.List;
-
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -11,14 +9,12 @@
class SlackPluginConfigTest {
@Test
- void shouldNormalizeDefaultsAndIdentifiers() {
+ void shouldNormalizeDefaultsAndSecrets() {
SlackPluginConfig config = SlackPluginConfig.builder()
.enabled(null)
.replyInThread(null)
.botToken(" ")
.appToken(" xapp-token ")
- .allowedUserIds(List.of(" U123 ", "", "U123", "U999"))
- .allowedChannelIds(List.of(" C123 ", "C123", "D456"))
.build();
config.normalize();
@@ -27,7 +23,5 @@ void shouldNormalizeDefaultsAndIdentifiers() {
assertTrue(Boolean.TRUE.equals(config.getReplyInThread()));
assertNull(config.getBotToken());
assertEquals("xapp-token", config.getAppToken());
- assertEquals(List.of("U123", "U999"), config.getAllowedUserIds());
- assertEquals(List.of("C123", "D456"), config.getAllowedChannelIds());
}
}
diff --git a/golemcore/slack/src/test/java/me/golemcore/plugins/golemcore/slack/SlackPluginSettingsContributorTest.java b/golemcore/slack/src/test/java/me/golemcore/plugins/golemcore/slack/SlackPluginSettingsContributorTest.java
index 9ba26fc..caeed53 100644
--- a/golemcore/slack/src/test/java/me/golemcore/plugins/golemcore/slack/SlackPluginSettingsContributorTest.java
+++ b/golemcore/slack/src/test/java/me/golemcore/plugins/golemcore/slack/SlackPluginSettingsContributorTest.java
@@ -1,5 +1,6 @@
package me.golemcore.plugins.golemcore.slack;
+import com.fasterxml.jackson.databind.ObjectMapper;
import me.golemcore.plugin.api.extension.spi.PluginActionResult;
import me.golemcore.plugin.api.extension.spi.PluginSettingsSection;
import org.junit.jupiter.api.BeforeEach;
@@ -7,7 +8,6 @@
import org.mockito.ArgumentCaptor;
import org.springframework.context.ApplicationEventPublisher;
-import java.util.List;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -22,6 +22,7 @@ class SlackPluginSettingsContributorTest {
private ApplicationEventPublisher eventPublisher;
private SlackPluginSettingsContributor contributor;
private SlackPluginConfig config;
+ private final ObjectMapper objectMapper = new ObjectMapper();
@BeforeEach
void setUp() {
@@ -33,8 +34,6 @@ void setUp() {
.botToken("xoxb-existing")
.appToken("xapp-existing")
.replyInThread(true)
- .allowedUserIds(List.of("U123"))
- .allowedChannelIds(List.of("C123"))
.build();
when(configService.getConfig()).thenReturn(config);
}
@@ -45,8 +44,8 @@ void shouldExposeSectionWithBlankSecrets() {
assertEquals("", section.getValues().get("botToken"));
assertEquals("", section.getValues().get("appToken"));
- assertEquals("U123", section.getValues().get("allowedUserIds"));
- assertEquals("C123", section.getValues().get("allowedChannelIds"));
+ assertTrue(!section.getValues().containsKey("allowedUserIds"));
+ assertTrue(!section.getValues().containsKey("allowedChannelIds"));
}
@Test
@@ -55,19 +54,18 @@ void shouldPreserveSecretsWhenBlankValuesAreSaved() {
"enabled", false,
"botToken", "",
"appToken", "",
- "replyInThread", false,
- "allowedUserIds", "U777, U888",
- "allowedChannelIds", "D123, C999"));
+ "replyInThread", false));
ArgumentCaptor captor = ArgumentCaptor.forClass(SlackPluginConfig.class);
verify(configService).save(captor.capture());
SlackPluginConfig saved = captor.getValue();
+ Map serialized = objectMapper.convertValue(saved, Map.class);
assertEquals("xoxb-existing", saved.getBotToken());
assertEquals("xapp-existing", saved.getAppToken());
assertTrue(Boolean.FALSE.equals(saved.getEnabled()));
assertTrue(Boolean.FALSE.equals(saved.getReplyInThread()));
- assertEquals(List.of("U777", "U888"), saved.getAllowedUserIds());
- assertEquals(List.of("D123", "C999"), saved.getAllowedChannelIds());
+ assertTrue(!serialized.containsKey("allowedUserIds"));
+ assertTrue(!serialized.containsKey("allowedChannelIds"));
verify(eventPublisher).publishEvent(org.mockito.ArgumentMatchers.any(SlackRestartEvent.class));
}
diff --git a/golemcore/slack/src/test/java/me/golemcore/plugins/golemcore/slack/adapter/inbound/slack/SlackAdapterTest.java b/golemcore/slack/src/test/java/me/golemcore/plugins/golemcore/slack/adapter/inbound/slack/SlackAdapterTest.java
index d2ecc41..ac7d51e 100644
--- a/golemcore/slack/src/test/java/me/golemcore/plugins/golemcore/slack/adapter/inbound/slack/SlackAdapterTest.java
+++ b/golemcore/slack/src/test/java/me/golemcore/plugins/golemcore/slack/adapter/inbound/slack/SlackAdapterTest.java
@@ -1,5 +1,6 @@
package me.golemcore.plugins.golemcore.slack.adapter.inbound.slack;
+import com.fasterxml.jackson.databind.ObjectMapper;
import me.golemcore.plugin.api.extension.loop.AgentLoop;
import me.golemcore.plugin.api.extension.model.ConfirmationCallbackEvent;
import me.golemcore.plugin.api.extension.model.ContextAttributes;
@@ -48,6 +49,7 @@ class SlackAdapterTest {
private ApplicationEventPublisher eventPublisher;
private SlackAdapter adapter;
private SlackPluginConfig config;
+ private final ObjectMapper objectMapper = new ObjectMapper();
@BeforeEach
void setUp() {
@@ -103,7 +105,13 @@ void shouldPublishInboundThreadedMessage() {
@Test
void shouldIgnoreUnauthorizedUsers() {
- config.setAllowedUserIds(List.of("U111"));
+ config = objectMapper.convertValue(Map.of(
+ "enabled", true,
+ "botToken", "xoxb-test",
+ "appToken", "xapp-test",
+ "replyInThread", true,
+ "allowedUserIds", List.of("U111")), SlackPluginConfig.class);
+ when(configService.getConfig()).thenReturn(config);
adapter.start();
ArgumentCaptor> captor = ArgumentCaptor.forClass(Consumer.class);
@@ -119,7 +127,7 @@ void shouldIgnoreUnauthorizedUsers() {
true,
false));
- verify(eventPublisher, never()).publishEvent(any());
+ verify(eventPublisher).publishEvent(any(AgentLoop.InboundMessageEvent.class));
}
@Test
diff --git a/registry/golemcore/slack/index.yaml b/registry/golemcore/slack/index.yaml
index 0bfcc7c..7016a14 100644
--- a/registry/golemcore/slack/index.yaml
+++ b/registry/golemcore/slack/index.yaml
@@ -1,10 +1,11 @@
id: golemcore/slack
owner: golemcore
name: slack
-latest: 1.0.3
+latest: 1.0.4
versions:
- 1.0.0
- 1.0.1
- 1.0.2
- 1.0.3
+ - 1.0.4
source: "https://github.com/alexk-dev/golemcore-plugins/tree/main/golemcore/slack"
diff --git a/registry/golemcore/slack/versions/1.0.4.yaml b/registry/golemcore/slack/versions/1.0.4.yaml
new file mode 100644
index 0000000..e4b59f7
--- /dev/null
+++ b/registry/golemcore/slack/versions/1.0.4.yaml
@@ -0,0 +1,13 @@
+id: golemcore/slack
+version: 1.0.4
+pluginApiVersion: 1
+engineVersion: ">=0.0.0 <1.0.0"
+artifactUrl: "dist/golemcore/slack/1.0.4/golemcore-slack-plugin-1.0.4.jar"
+checksumSha256: "bd1d03fb07a9c8173a087acd64a2764fa5a3b903e7fcbbbc4468a830e84ee72f"
+publishedAt: "2026-03-22T17:22:33Z"
+sourceCommit: "57967fbeb9aee29b37e3cc60367c122611a84641"
+entrypoint: me.golemcore.plugins.golemcore.slack.SlackPluginBootstrap
+sourceUrl: "https://github.com/alexk-dev/golemcore-plugins/tree/main/golemcore/slack"
+license: "Apache-2.0"
+maintainers:
+ - alexk-dev