Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ product overview.

## Unreleased

- Fix Slack Settings rejecting the MCP, Skills and You pages with `invalid_arguments` when
their multi-select pickers contain options.

- Require a human approval card before managed Composio joins, invites or creates Slack channels,
including in Auto/Admin mode and through batched actions, both identities and host runtimes.
Refuse opaque connector code/API executors that could bypass membership approval; use
Expand Down
3 changes: 3 additions & 0 deletions FEATURES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# ChannelGate — Features

- Slack Settings renders populated Cloud MCP and skill pickers on the MCP, Skills and You pages
without a native Slack `invalid_arguments` error; selection still saves immediately.

## Slack channel membership approvals

- Managed Composio Slack join, invitation and channel-creation actions require a one-use human
Expand Down
11 changes: 11 additions & 0 deletions TEST-PLAN.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# ChannelGate — Test Plan

## Slack Settings picker rendering (2026-10-15)

- [x] Regression: the existing all-page/all-role/inline-form Block Kit validation includes a
compatibility guard for the deployed modal's live `unsupported element: multiselect`
rejection of actions-block placement (current Slack docs also list actions as supported).
Cloud MCP, channel skills and personal skills
use section accessories, retaining action IDs, block IDs, options and initial selections.
- [ ] Native retest on the deployed fix: open MCP, Skills and You with populated catalogs;
verify each page renders, selection saves and the same modal repaints. Resume the existing
Settings navigation/template live cases. Automated rendering checks alone do not close them.

## Slack channel membership approvals (2026-10-15)

- [x] Automated: `test/composio-approval.test.js`, `test/mcp-socket-server.test.js`,
Expand Down
8 changes: 4 additions & 4 deletions src/slack/channel-settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -818,10 +818,10 @@ function cloudRows(snapshot) {
continue;
}
const initial = options.filter((entry) => (data.selected || []).includes(entry.value));
blocks.push({ type: "actions", block_id: `cg_cloud_${engine}`, elements: [{
blocks.push({ type: "section", block_id: `cg_cloud_${engine}`, text: mrkdwn("Select servers"), accessory: {
type: "multi_static_select", action_id: `${CHANNEL_SETTINGS_CLOUD_SELECT_PREFIX}${engine}`, placeholder: plain("Add a server…"), options,
...(initial.length ? { initial_options: initial } : {}),
}] });
} });
if (data.inherited?.length) blocks.push(context(`Always on from the organization: ${data.inherited.map(inlineCode).join(" ")}`));
}
return blocks;
Expand Down Expand Up @@ -902,10 +902,10 @@ function skillPicker(actionId, data = {}, placeholder) {
const options = (data.options || []).slice(0, 100).map((entry) => option(entry.label || entry.key, entry.key, entry.description || ""));
const initial = options.filter((entry) => (data.selected || []).includes(entry.value));
if (!options.length) return [context("_No skills available in the catalog._")];
return [{ type: "actions", block_id: `${actionId}_row`, elements: [{
return [{ type: "section", block_id: `${actionId}_row`, text: mrkdwn("Select skills"), accessory: {
type: "multi_static_select", action_id: actionId, placeholder: plain(placeholder), options,
...(initial.length ? { initial_options: initial } : {}),
}] }, ...((data.options || []).length > 100 ? [context(`Showing 100 of ${data.options.length} skills; the admin UI lists them all.`)] : [])];
} }, ...((data.options || []).length > 100 ? [context(`Showing 100 of ${data.options.length} skills; the admin UI lists them all.`)] : [])];
}

function skillsPage(snapshot, state) {
Expand Down
6 changes: 5 additions & 1 deletion test/slack-settings-redesign.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,10 @@ function blockKitProblems(view) {
if (block.type === "context" && block.elements.length > 10) problems.push(`${where} more than 10 context elements`);
const elements = [...(block.accessory ? [block.accessory] : []), ...(block.type === "actions" ? block.elements : []), ...(block.type === "input" ? [block.element] : [])];
if (block.type === "actions" && block.elements.length > 25) problems.push(`${where} more than 25 elements`);
// The deployed Slack modal rejected this placement with `unsupported element: multiselect`,
// despite current docs also listing actions blocks. Guard that observed compatibility case;
// section accessories support the same immediate block_actions callbacks.
if (block.type === "actions" && block.elements.some((element) => element.type.startsWith("multi_"))) problems.push(`${where} unsupported multiselect placement`);
const actionIds = new Set();
for (const element of elements) {
if (element.action_id) {
Expand All @@ -276,7 +280,7 @@ function blockKitProblems(view) {
return problems;
}

test("every page, in every role and with every inline form open, is valid Block Kit", () => {
test("every page, in every role and with every inline form open, passes Block Kit and deployed modal compatibility checks", () => {
const masked = (last4) => ({ configured: true, last4 });
const long = "X".repeat(64);
const snapshot = {
Expand Down
Loading