diff --git a/CHANGELOG.md b/CHANGELOG.md index ff0e78ba..a1cbb4dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,11 @@ * [#597](https://github.com/slack-ruby/slack-ruby-client/pull/597): Add AgentsSessions and AppsManagedPermissions endpoint modules for agents.sessions and apps.managedPermissions methods - [@slack-ruby-ci-bot](https://github.com/apps/slack-ruby-ci-bot). * [#597](https://github.com/slack-ruby/slack-ruby-client/pull/597): Increase conversations.invite users limit from 100 to 1000 - [@slack-ruby-ci-bot](https://github.com/apps/slack-ruby-ci-bot). * [#597](https://github.com/slack-ruby/slack-ruby-client/pull/597): Add new Slack API error codes - [@slack-ruby-ci-bot](https://github.com/apps/slack-ruby-ci-bot). +* [#600](https://github.com/slack-ruby/slack-ruby-client/pull/600): Add channel_ids argument to admin.apps.permissions.add and admin.apps.permissions.remove, and channel_ids/channel_restriction_mode to admin.apps.permissions.set - [@slack-ruby-ci-bot](https://github.com/apps/slack-ruby-ci-bot). +* [#600](https://github.com/slack-ruby/slack-ruby-client/pull/600): Add oauth.v2.beginShortTokenRotation and oauth.v2.completeShortTokenRotation methods - [@slack-ruby-ci-bot](https://github.com/apps/slack-ruby-ci-bot). +* [#600](https://github.com/slack-ruby/slack-ruby-client/pull/600): Add session_status argument to chat.stopStream - [@slack-ruby-ci-bot](https://github.com/apps/slack-ruby-ci-bot). +* [#600](https://github.com/slack-ruby/slack-ruby-client/pull/600): Add include_list argument to slackLists.items.list - [@slack-ruby-ci-bot](https://github.com/apps/slack-ruby-ci-bot). +* [#600](https://github.com/slack-ruby/slack-ruby-client/pull/600): Add new error codes including channel_restriction_requires_app_access, channel_restrictions_not_available, rotation_not_found, token_too_long, user_is_external_guest, and user_not_authenticated - [@slack-ruby-ci-bot](https://github.com/apps/slack-ruby-ci-bot). * Your contribution here. ### 3.2.0 (2026/07/05) diff --git a/bin/commands/admin_apps_permissions.rb b/bin/commands/admin_apps_permissions.rb index ada87300..8924b044 100644 --- a/bin/commands/admin_apps_permissions.rb +++ b/bin/commands/admin_apps_permissions.rb @@ -12,6 +12,7 @@ class App c.flag 'app_id', desc: 'Encoded ID of the app.' c.flag 'user_ids', desc: 'List of user IDs to allow for named_entities visibility.' c.flag 'usergroup_ids', desc: 'List of encoded usergroup IDs.' + c.flag 'channel_ids', desc: "List of encoded channel IDs to add to the channel restriction list. Interpretation depends on the app's channel_restriction_mode, which is configured via the admin.apps.permissions.set method." c.action do |_global_options, options, _args| puts JSON.dump(@client.admin_apps_permissions_add(options)) end @@ -32,6 +33,7 @@ class App c.flag 'app_id', desc: 'Encoded ID of the app.' c.flag 'user_ids', desc: 'List of user IDs whose named_entities access will be revoked.' c.flag 'usergroup_ids', desc: 'List of encoded usergroup IDs.' + c.flag 'channel_ids', desc: "List of encoded channel IDs to remove from the channel restriction list. Interpretation depends on the app's channel_restriction_mode, which is configured via the admin.apps.permissions.set method." c.action do |_global_options, options, _args| puts JSON.dump(@client.admin_apps_permissions_remove(options)) end @@ -44,6 +46,8 @@ class App c.flag 'permission_type', desc: 'The type of permission that defines who can access the app.' c.flag 'user_ids', desc: 'List of user IDs to allow for named_entities visibility.' c.flag 'usergroup_ids', desc: 'List of encoded usergroup IDs.' + c.flag 'channel_restriction_mode', desc: 'The mode that defines where the app can be used in channels.' + c.flag 'channel_ids', desc: 'List of encoded channel IDs for channel restrictions. Semantics depend on channel_restriction_mode: allowlist for specific_channels, exclusion list for all_channels_except.' c.action do |_global_options, options, _args| puts JSON.dump(@client.admin_apps_permissions_set(options)) end diff --git a/bin/commands/chat.rb b/bin/commands/chat.rb index f07b8739..7e07b23d 100644 --- a/bin/commands/chat.rb +++ b/bin/commands/chat.rb @@ -146,7 +146,7 @@ class App g.long_desc %( Starts a new streaming conversation. ) g.command 'startStream' do |c| c.flag 'channel', desc: 'An encoded ID that represents a channel, thread, or DM.' - c.flag 'chunks', desc: 'Array of streaming chunks.' + c.flag 'chunks', desc: 'Array of streaming chunks. Can include markdown text chunk objects, task update chunk objects, plan update chunks, or blocks chunks.' c.flag 'markdown_text', desc: 'Accepts message text formatted in markdown. Limit this field to 12,000 characters.' c.flag 'thread_ts', desc: "Provide another message's ts value to reply to. Omit it to stream a top-level message instead of a thread reply; this is only supported in channels where the whole channel is one session, such as Slack Code, and returns invalid_thread_ts elsewhere. Passing '0' is equivalent to omitting it." c.flag 'recipient_user_id', desc: 'The encoded ID of the user to receive the streaming text. Required when streaming to channels.' @@ -164,11 +164,12 @@ class App g.long_desc %( Stops a streaming conversation. ) g.command 'stopStream' do |c| c.flag 'channel', desc: 'An encoded ID that represents a channel, private group, or DM.' - c.flag 'chunks', desc: 'Array of streaming chunks.' + c.flag 'chunks', desc: 'Array of streaming chunks. Can include markdown text chunk objects, task update chunk objects, plan update chunks, or blocks chunks.' c.flag 'ts', desc: 'The timestamp of the streaming message.' c.flag 'markdown_text', desc: 'Accepts message text formatted in markdown. Limit this field to 12,000 characters.' c.flag 'blocks', desc: 'A list of blocks that will be rendered at the bottom of the finalized message.' c.flag 'metadata', desc: 'JSON object with event_type and event_payload fields, presented as a URL-encoded string. Metadata you post to Slack is accessible to any app or user who is a member of that workspace.' + c.flag 'session_status', desc: 'The session status to set after stopping the stream.' c.action do |_global_options, options, _args| puts JSON.dump(@client.chat_stopStream(options)) end diff --git a/bin/commands/oauth_v2.rb b/bin/commands/oauth_v2.rb index e6659ac5..bab7d7fa 100644 --- a/bin/commands/oauth_v2.rb +++ b/bin/commands/oauth_v2.rb @@ -22,6 +22,27 @@ class App end end + g.desc 'Call this to rotate the secret on an old API token with a short secret. Must be paired with a call to oauth.v2.completeShortTokenRotation to confirm the change.' + g.long_desc %( Call this to rotate the secret on an old API token with a short secret. Must be paired with a call to oauth.v2.completeShortTokenRotation to confirm the change. ) + g.command 'beginShortTokenRotation' do |c| + c.flag 'client_id', desc: 'Issued when you created your application. Must be the app the token being rotated was issued to.' + c.flag 'client_secret', desc: 'Issued when you created your application.' + c.action do |_global_options, options, _args| + puts JSON.dump(@client.oauth_v2_beginShortTokenRotation(options)) + end + end + + g.desc 'Call this to finish rotating the secret on an old API token with a short secret. Must be paired with a call to oauth.v2.beginShortTokenRotation to start the process.' + g.long_desc %( Call this to finish rotating the secret on an old API token with a short secret. Must be paired with a call to oauth.v2.beginShortTokenRotation to start the process. ) + g.command 'completeShortTokenRotation' do |c| + c.flag 'client_id', desc: 'Issued when you created your application. Must be the app the token being rotated was issued to.' + c.flag 'client_secret', desc: 'Issued when you created your application.' + c.flag 'new_token', desc: 'The new xoxp token returned by oauth.v2.beginShortTokenRotation.' + c.action do |_global_options, options, _args| + puts JSON.dump(@client.oauth_v2_completeShortTokenRotation(options)) + end + end + g.desc 'Exchanges a legacy access token for a new expiring access token and refresh token' g.long_desc %( Exchanges a legacy access token for a new expiring access token and refresh token ) g.command 'exchange' do |c| diff --git a/bin/commands/slackLists_items.rb b/bin/commands/slackLists_items.rb index edfb6da6..3c1ddf78 100644 --- a/bin/commands/slackLists_items.rb +++ b/bin/commands/slackLists_items.rb @@ -56,6 +56,7 @@ class App c.flag 'limit', desc: 'The maximum number of records to return.' c.flag 'cursor', desc: 'Next cursor for pagination.' c.flag 'archived', desc: 'Boolean indicating whether archived items or normal items should be returned.' + c.flag 'include_list', desc: 'Set to true to also return the parent list object, including its title, column schema, and total row count. Defaults to false to keep the response small.' c.action do |_global_options, options, _args| puts JSON.dump(@client.slackLists_items_list(options)) end diff --git a/lib/slack/web/api/endpoints/admin_apps_permissions.rb b/lib/slack/web/api/endpoints/admin_apps_permissions.rb index e048a381..d9cb4cc4 100644 --- a/lib/slack/web/api/endpoints/admin_apps_permissions.rb +++ b/lib/slack/web/api/endpoints/admin_apps_permissions.rb @@ -15,6 +15,8 @@ module AdminAppsPermissions # List of user IDs to allow for named_entities visibility. # @option options [array] :usergroup_ids # List of encoded usergroup IDs. + # @option options [array] :channel_ids + # List of encoded channel IDs to add to the channel restriction list. Interpretation depends on the app's channel_restriction_mode, which is configured via the admin.apps.permissions.set method. # @see https://api.slack.com/methods/admin.apps.permissions.add # @see https://github.com/slack-ruby/slack-api-ref/blob/master/methods/admin.apps.permissions/admin.apps.permissions.add.json def admin_apps_permissions_add(options = {}) @@ -43,6 +45,8 @@ def admin_apps_permissions_list(options = {}) # List of user IDs whose named_entities access will be revoked. # @option options [array] :usergroup_ids # List of encoded usergroup IDs. + # @option options [array] :channel_ids + # List of encoded channel IDs to remove from the channel restriction list. Interpretation depends on the app's channel_restriction_mode, which is configured via the admin.apps.permissions.set method. # @see https://api.slack.com/methods/admin.apps.permissions.remove # @see https://github.com/slack-ruby/slack-api-ref/blob/master/methods/admin.apps.permissions/admin.apps.permissions.remove.json def admin_apps_permissions_remove(options = {}) @@ -61,6 +65,10 @@ def admin_apps_permissions_remove(options = {}) # List of user IDs to allow for named_entities visibility. # @option options [array] :usergroup_ids # List of encoded usergroup IDs. + # @option options [enum] :channel_restriction_mode + # The mode that defines where the app can be used in channels. + # @option options [array] :channel_ids + # List of encoded channel IDs for channel restrictions. Semantics depend on channel_restriction_mode: allowlist for specific_channels, exclusion list for all_channels_except. # @see https://api.slack.com/methods/admin.apps.permissions.set # @see https://github.com/slack-ruby/slack-api-ref/blob/master/methods/admin.apps.permissions/admin.apps.permissions.set.json def admin_apps_permissions_set(options = {}) diff --git a/lib/slack/web/api/endpoints/chat.rb b/lib/slack/web/api/endpoints/chat.rb index 09ff451e..53a47afc 100644 --- a/lib/slack/web/api/endpoints/chat.rb +++ b/lib/slack/web/api/endpoints/chat.rb @@ -253,7 +253,7 @@ def chat_scheduleMessage(options = {}) # @option options [channel] :channel # An encoded ID that represents a channel, thread, or DM. # @option options [array] :chunks - # Array of streaming chunks. + # Array of streaming chunks. Can include markdown text chunk objects, task update chunk objects, plan update chunks, or blocks chunks. # @option options [string] :markdown_text # Accepts message text formatted in markdown. Limit this field to 12,000 characters. # @option options [string] :thread_ts @@ -284,7 +284,7 @@ def chat_startStream(options = {}) # @option options [channel] :channel # An encoded ID that represents a channel, private group, or DM. # @option options [array] :chunks - # Array of streaming chunks. + # Array of streaming chunks. Can include markdown text chunk objects, task update chunk objects, plan update chunks, or blocks chunks. # @option options [timestamp] :ts # The timestamp of the streaming message. # @option options [string] :markdown_text @@ -293,6 +293,8 @@ def chat_startStream(options = {}) # A list of blocks that will be rendered at the bottom of the finalized message. # @option options [string] :metadata # JSON object with event_type and event_payload fields, presented as a URL-encoded string. Metadata you post to Slack is accessible to any app or user who is a member of that workspace. + # @option options [enum] :session_status + # The session status to set after stopping the stream. # @see https://api.slack.com/methods/chat.stopStream # @see https://github.com/slack-ruby/slack-api-ref/blob/master/methods/chat/chat.stopStream.json def chat_stopStream(options = {}) diff --git a/lib/slack/web/api/endpoints/oauth_v2.rb b/lib/slack/web/api/endpoints/oauth_v2.rb index f4af0ce5..afbf5285 100644 --- a/lib/slack/web/api/endpoints/oauth_v2.rb +++ b/lib/slack/web/api/endpoints/oauth_v2.rb @@ -31,6 +31,39 @@ def oauth_v2_access(options = {}) post('oauth.v2.access', options) end + # + # Call this to rotate the secret on an old API token with a short secret. Must be paired with a call to oauth.v2.completeShortTokenRotation to confirm the change. + # + # @option options [string] :client_id + # Issued when you created your application. Must be the app the token being rotated was issued to. + # @option options [string] :client_secret + # Issued when you created your application. + # @see https://api.slack.com/methods/oauth.v2.beginShortTokenRotation + # @see https://github.com/slack-ruby/slack-api-ref/blob/master/methods/oauth.v2/oauth.v2.beginShortTokenRotation.json + def oauth_v2_beginShortTokenRotation(options = {}) + raise ArgumentError, 'Required arguments :client_id missing' if options[:client_id].nil? + raise ArgumentError, 'Required arguments :client_secret missing' if options[:client_secret].nil? + post('oauth.v2.beginShortTokenRotation', options) + end + + # + # Call this to finish rotating the secret on an old API token with a short secret. Must be paired with a call to oauth.v2.beginShortTokenRotation to start the process. + # + # @option options [string] :client_id + # Issued when you created your application. Must be the app the token being rotated was issued to. + # @option options [string] :client_secret + # Issued when you created your application. + # @option options [string] :new_token + # The new xoxp token returned by oauth.v2.beginShortTokenRotation. + # @see https://api.slack.com/methods/oauth.v2.completeShortTokenRotation + # @see https://github.com/slack-ruby/slack-api-ref/blob/master/methods/oauth.v2/oauth.v2.completeShortTokenRotation.json + def oauth_v2_completeShortTokenRotation(options = {}) + raise ArgumentError, 'Required arguments :client_id missing' if options[:client_id].nil? + raise ArgumentError, 'Required arguments :client_secret missing' if options[:client_secret].nil? + raise ArgumentError, 'Required arguments :new_token missing' if options[:new_token].nil? + post('oauth.v2.completeShortTokenRotation', options) + end + # # Exchanges a legacy access token for a new expiring access token and refresh token # diff --git a/lib/slack/web/api/endpoints/slackLists_items.rb b/lib/slack/web/api/endpoints/slackLists_items.rb index c25d82ea..44b2e727 100644 --- a/lib/slack/web/api/endpoints/slackLists_items.rb +++ b/lib/slack/web/api/endpoints/slackLists_items.rb @@ -82,6 +82,8 @@ def slackLists_items_info(options = {}) # Next cursor for pagination. # @option options [boolean] :archived # Boolean indicating whether archived items or normal items should be returned. + # @option options [boolean] :include_list + # Set to true to also return the parent list object, including its title, column schema, and total row count. Defaults to false to keep the response small. # @see https://api.slack.com/methods/slackLists.items.list # @see https://github.com/slack-ruby/slack-api-ref/blob/master/methods/slackLists.items/slackLists.items.list.json def slackLists_items_list(options = {}) diff --git a/lib/slack/web/api/errors.rb b/lib/slack/web/api/errors.rb index 08aaf01e..386b3084 100644 --- a/lib/slack/web/api/errors.rb +++ b/lib/slack/web/api/errors.rb @@ -151,6 +151,8 @@ class ChannelNotArchived < SlackError; end class ChannelNotFound < SlackError; end class ChannelNotOrgWideShared < SlackError; end class ChannelOwnerRestriction < SlackError; end + class ChannelRestrictionRequiresAppAccess < SlackError; end + class ChannelRestrictionsNotAvailable < SlackError; end class ChannelSharedWithNonapprovedTeam < SlackError; end class ChannelTypeNotSupported < SlackError; end class ChannelsLimitExceeded < SlackError; end @@ -699,6 +701,7 @@ class RestrictedActionThreadOnlyChannel < SlackError; end class RestrictedPlanLevel < SlackError; end class RestrictedTooMany < SlackError; end class RetentionOverrideNotAllowed < SlackError; end + class RotationNotFound < SlackError; end class RowIdNotProvided < SlackError; end class RowNotFound < SlackError; end class RtmConnectRequired < SlackError; end @@ -754,6 +757,7 @@ class TokenExpired < SlackError; end class TokenNotFound < SlackError; end class TokenRevoked < SlackError; end class TokenRotationNotEnabled < SlackError; end + class TokenTooLong < SlackError; end class TooLarge < SlackError; end class TooLong < SlackError; end class TooManyAttachments < SlackError; end @@ -825,11 +829,13 @@ class UserEmailUnverified < SlackError; end class UserIsAlreadyDeleted < SlackError; end class UserIsBot < SlackError; end class UserIsDeactivated < SlackError; end + class UserIsExternalGuest < SlackError; end class UserIsNotAGuest < SlackError; end class UserIsNotGuest < SlackError; end class UserIsRestricted < SlackError; end class UserMustBeAdmin < SlackError; end class UserMustBeInWorkspace < SlackError; end + class UserNotAuthenticated < SlackError; end class UserNotFound < SlackError; end class UserNotInChannel < SlackError; end class UserNotVisible < SlackError; end @@ -994,6 +1000,8 @@ class WorkspaceNotEligible < SlackError; end 'channel_not_found' => ChannelNotFound, 'channel_not_org_wide_shared' => ChannelNotOrgWideShared, 'channel_owner_restriction' => ChannelOwnerRestriction, + 'channel_restriction_requires_app_access' => ChannelRestrictionRequiresAppAccess, + 'channel_restrictions_not_available' => ChannelRestrictionsNotAvailable, 'channel_shared_with_nonapproved_team' => ChannelSharedWithNonapprovedTeam, 'channel_type_not_supported' => ChannelTypeNotSupported, 'channels_limit_exceeded' => ChannelsLimitExceeded, @@ -1542,6 +1550,7 @@ class WorkspaceNotEligible < SlackError; end 'restricted_plan_level' => RestrictedPlanLevel, 'restricted_too_many' => RestrictedTooMany, 'retention_override_not_allowed' => RetentionOverrideNotAllowed, + 'rotation_not_found' => RotationNotFound, 'row_id_not_provided' => RowIdNotProvided, 'row_not_found' => RowNotFound, 'rtm_connect_required' => RtmConnectRequired, @@ -1597,6 +1606,7 @@ class WorkspaceNotEligible < SlackError; end 'token_not_found' => TokenNotFound, 'token_revoked' => TokenRevoked, 'token_rotation_not_enabled' => TokenRotationNotEnabled, + 'token_too_long' => TokenTooLong, 'too_large' => TooLarge, 'too_long' => TooLong, 'too_many_attachments' => TooManyAttachments, @@ -1668,11 +1678,13 @@ class WorkspaceNotEligible < SlackError; end 'user_is_already_deleted' => UserIsAlreadyDeleted, 'user_is_bot' => UserIsBot, 'user_is_deactivated' => UserIsDeactivated, + 'user_is_external_guest' => UserIsExternalGuest, 'user_is_not_a_guest' => UserIsNotAGuest, 'user_is_not_guest' => UserIsNotGuest, 'user_is_restricted' => UserIsRestricted, 'user_must_be_admin' => UserMustBeAdmin, 'user_must_be_in_workspace' => UserMustBeInWorkspace, + 'user_not_authenticated' => UserNotAuthenticated, 'user_not_found' => UserNotFound, 'user_not_in_channel' => UserNotInChannel, 'user_not_visible' => UserNotVisible, diff --git a/lib/slack/web/api/slack-api-ref b/lib/slack/web/api/slack-api-ref index d980b887..4f0934e3 160000 --- a/lib/slack/web/api/slack-api-ref +++ b/lib/slack/web/api/slack-api-ref @@ -1 +1 @@ -Subproject commit d980b887f601ac588c33f9b682ea11404c3a5d8a +Subproject commit 4f0934e301e9a9a15883ea54fbf8a22efb8e8fc9 diff --git a/spec/slack/web/api/endpoints/oauth_v2_spec.rb b/spec/slack/web/api/endpoints/oauth_v2_spec.rb index 8d7916f8..c3b977f2 100644 --- a/spec/slack/web/api/endpoints/oauth_v2_spec.rb +++ b/spec/slack/web/api/endpoints/oauth_v2_spec.rb @@ -5,6 +5,25 @@ RSpec.describe Slack::Web::Api::Endpoints::OauthV2 do let(:client) { Slack::Web::Client.new } + context 'oauth.v2_beginShortTokenRotation' do + it 'requires client_id' do + expect { client.oauth_v2_beginShortTokenRotation(client_secret: %q[e1b9e11dfcd19c1982d5de12921e17e8c]) }.to raise_error ArgumentError, /Required arguments :client_id missing/ + end + it 'requires client_secret' do + expect { client.oauth_v2_beginShortTokenRotation(client_id: %q[4123121235.9872358710]) }.to raise_error ArgumentError, /Required arguments :client_secret missing/ + end + end + context 'oauth.v2_completeShortTokenRotation' do + it 'requires client_id' do + expect { client.oauth_v2_completeShortTokenRotation(client_secret: %q[e1b9e11dfcd19c1982d5de12921e17e8c], new_token: %q[xoxp-12345-67890-1928471-qemwiiwglagjacakvqbvbfkmvbsvsuzn]) }.to raise_error ArgumentError, /Required arguments :client_id missing/ + end + it 'requires client_secret' do + expect { client.oauth_v2_completeShortTokenRotation(client_id: %q[4123121235.9872358710], new_token: %q[xoxp-12345-67890-1928471-qemwiiwglagjacakvqbvbfkmvbsvsuzn]) }.to raise_error ArgumentError, /Required arguments :client_secret missing/ + end + it 'requires new_token' do + expect { client.oauth_v2_completeShortTokenRotation(client_id: %q[4123121235.9872358710], client_secret: %q[e1b9e11dfcd19c1982d5de12921e17e8c]) }.to raise_error ArgumentError, /Required arguments :new_token missing/ + end + end context 'oauth.v2_exchange' do it 'requires client_id' do expect { client.oauth_v2_exchange(client_secret: %q[e1b9e11dfcd19c1982d5de12921e17e8c]) }.to raise_error ArgumentError, /Required arguments :client_id missing/