Refactor Slack UDFs to use webhook secret names and improve error handling

- Updated UDF definitions to replace WEBHOOK_URL and BOT_TOKEN with WEBHOOK_SECRET_NAME for enhanced security.
- Improved error messages for required parameters in the SQL logic.
- Standardized comments for clarity and consistency across UDFs.
- Ensured proper handling of user context for accessing secrets in the vault.
This commit is contained in:
Jensen Yap 2025-08-05 22:20:40 +09:00
parent 629dfe077d
commit f1f3e48efd
2 changed files with 34 additions and 46 deletions

View File

@ -6,31 +6,29 @@
{# Slack Webhook Messages #}
- name: {{ schema_name }}.webhook_send
signature:
- [WEBHOOK_URL, STRING, Slack webhook URL]
- [WEBHOOK_SECRET_NAME, STRING, "Name of webhook secret in vault (e.g., 'alerts', 'notifications')"]
- [PAYLOAD, OBJECT, Complete Slack message payload according to Slack API spec]
return_type:
- "OBJECT"
options: |
COMMENT = $$Send a message to Slack via webhook [API docs: Webhooks](https://api.slack.com/messaging/webhooks)$$
COMMENT = 'Send a message to Slack via webhook [API docs: Webhooks](https://api.slack.com/messaging/webhooks)'
sql: |
SELECT slack_utils.post_webhook(
WEBHOOK_URL,
SELECT {{ utils_schema_name }}.post_webhook(
WEBHOOK_SECRET_NAME,
PAYLOAD
) as response
{# Slack Web API Messages #}
- name: {{ schema_name }}.post_message
signature:
- [BOT_TOKEN, STRING, Slack bot token (xoxb-...)]
- [CHANNEL, STRING, Slack channel ID or name]
- [PAYLOAD, OBJECT, Message payload according to Slack chat.postMessage API spec]
return_type:
- "OBJECT"
options: |
COMMENT = $$Send a message to Slack via Web API [API docs: chat.postMessage](https://api.slack.com/methods/chat.postMessage)$$
COMMENT = 'Send a message to Slack via Web API [API docs: chat.postMessage](https://api.slack.com/methods/chat.postMessage)'
sql: |
SELECT slack_utils.post_message(
BOT_TOKEN,
SELECT {{ utils_schema_name }}.post_message(
CHANNEL,
PAYLOAD
) as response
@ -38,17 +36,15 @@
- name: {{ schema_name }}.post_reply
signature:
- [BOT_TOKEN, STRING, Slack bot token (xoxb-...)]
- [CHANNEL, STRING, Slack channel ID or name]
- [THREAD_TS, STRING, Parent message timestamp for threading]
- [PAYLOAD, OBJECT, Message payload according to Slack chat.postMessage API spec]
return_type:
- "OBJECT"
options: |
COMMENT = $$Send a threaded reply to Slack via Web API [API docs: chat.postMessage](https://api.slack.com/methods/chat.postMessage)$$
COMMENT = 'Send a threaded reply to Slack via Web API [API docs: chat.postMessage](https://api.slack.com/methods/chat.postMessage)'
sql: |
SELECT slack_utils.post_reply(
BOT_TOKEN,
SELECT {{ utils_schema_name }}.post_reply(
CHANNEL,
THREAD_TS,
PAYLOAD

View File

@ -1,36 +1,35 @@
{% macro config_slack_utils_udfs(schema_name = "slack_utils", utils_schema_name = "slack_utils") -%}
{#
This macro is used to generate API calls to Slack API endpoints
#}
#}
- name: {{ schema_name }}.post_webhook
signature:
- [WEBHOOK_URL, STRING, Slack webhook URL]
- [WEBHOOK_SECRET_NAME, STRING, "Name of webhook secret in vault (e.g., 'alerts', 'notifications')"]
- [PAYLOAD, OBJECT, Complete Slack message payload according to Slack API spec]
return_type:
- "OBJECT"
options: |
COMMENT = $$Send a message to Slack via webhook. User provides complete payload according to Slack webhook API spec.$$
COMMENT = $$Send a message to Slack via webhook. User provides secret name for webhook URL stored in vault.$$
sql: |
SELECT CASE
WHEN WEBHOOK_URL IS NULL OR WEBHOOK_URL = '' THEN
OBJECT_CONSTRUCT('ok', false, 'error', 'webhook_url is required')
WHEN NOT STARTSWITH(WEBHOOK_URL, 'https://hooks.slack.com/') THEN
OBJECT_CONSTRUCT('ok', false, 'error', 'Invalid webhook URL format')
SELECT CASE
WHEN WEBHOOK_SECRET_NAME IS NULL OR WEBHOOK_SECRET_NAME = '' THEN
OBJECT_CONSTRUCT('ok', false, 'error', 'webhook_secret_name is required')
WHEN PAYLOAD IS NULL THEN
OBJECT_CONSTRUCT('ok', false, 'error', 'payload is required')
ELSE
live.udf_api(
'POST',
WEBHOOK_URL,
'{WEBHOOK_URL}',
OBJECT_CONSTRUCT('Content-Type', 'application/json'),
PAYLOAD
PAYLOAD,
IFF(_utils.udf_whoami() <> CURRENT_USER(),
'_FSC_SYS/SLACK/' || WEBHOOK_SECRET_NAME,
'Vault/prod/livequery/slack/' || WEBHOOK_SECRET_NAME)
)
END as response
- name: {{ schema_name }}.post_message
signature:
- [BOT_TOKEN, STRING, Slack bot token (xoxb-...)]
- [CHANNEL, STRING, Slack channel ID or name]
- [PAYLOAD, OBJECT, Message payload according to Slack chat.postMessage API spec]
return_type:
@ -38,11 +37,7 @@
options: |
COMMENT = $$Send a message to Slack via Web API chat.postMessage. User provides complete payload according to Slack API spec.$$
sql: |
SELECT CASE
WHEN BOT_TOKEN IS NULL OR BOT_TOKEN = '' THEN
OBJECT_CONSTRUCT('ok', false, 'error', 'bot_token is required')
WHEN NOT STARTSWITH(BOT_TOKEN, 'xoxb-') THEN
OBJECT_CONSTRUCT('ok', false, 'error', 'Invalid bot token format')
SELECT CASE
WHEN CHANNEL IS NULL OR CHANNEL = '' THEN
OBJECT_CONSTRUCT('ok', false, 'error', 'channel is required')
WHEN PAYLOAD IS NULL THEN
@ -52,16 +47,16 @@
'POST',
'https://slack.com/api/chat.postMessage',
OBJECT_CONSTRUCT(
'Authorization', 'Bearer ' || BOT_TOKEN,
'Authorization', 'Bearer {BOT_TOKEN}',
'Content-Type', 'application/json'
),
OBJECT_INSERT(PAYLOAD, 'channel', CHANNEL)
OBJECT_INSERT(PAYLOAD, 'channel', CHANNEL),
IFF(_utils.udf_whoami() <> CURRENT_USER(), '_FSC_SYS/SLACK', 'Vault/prod/livequery/slack')
)
END as response
- name: {{ schema_name }}.post_reply
- name: {{ schema_name }}.post_reply
signature:
- [BOT_TOKEN, STRING, Slack bot token (xoxb-...)]
- [CHANNEL, STRING, Slack channel ID or name]
- [THREAD_TS, STRING, Parent message timestamp for threading]
- [PAYLOAD, OBJECT, Message payload according to Slack chat.postMessage API spec]
@ -70,11 +65,7 @@
options: |
COMMENT = $$Send a threaded reply to Slack via Web API. User provides complete payload according to Slack API spec.$$
sql: |
SELECT CASE
WHEN BOT_TOKEN IS NULL OR BOT_TOKEN = '' THEN
OBJECT_CONSTRUCT('ok', false, 'error', 'bot_token is required')
WHEN NOT STARTSWITH(BOT_TOKEN, 'xoxb-') THEN
OBJECT_CONSTRUCT('ok', false, 'error', 'Invalid bot token format')
SELECT CASE
WHEN CHANNEL IS NULL OR CHANNEL = '' THEN
OBJECT_CONSTRUCT('ok', false, 'error', 'channel is required')
WHEN THREAD_TS IS NULL OR THREAD_TS = '' THEN
@ -86,13 +77,14 @@
'POST',
'https://slack.com/api/chat.postMessage',
OBJECT_CONSTRUCT(
'Authorization', 'Bearer ' || BOT_TOKEN,
'Authorization', 'Bearer {BOT_TOKEN}',
'Content-Type', 'application/json'
),
OBJECT_INSERT(
OBJECT_INSERT(PAYLOAD, 'channel', CHANNEL),
'thread_ts', THREAD_TS
)
),
IFF(_utils.udf_whoami() <> CURRENT_USER(), '_FSC_SYS/SLACK', 'Vault/prod/livequery/slack')
)
END as response
@ -104,11 +96,11 @@
options: |
COMMENT = $$Validate if a string is a proper Slack webhook URL format.$$
sql: |
SELECT WEBHOOK_URL IS NOT NULL
SELECT WEBHOOK_URL IS NOT NULL
AND STARTSWITH(WEBHOOK_URL, 'https://hooks.slack.com/services/')
AND LENGTH(WEBHOOK_URL) > 50
- name: {{ schema_name }}.validate_bot_token
- name: {{ schema_name }}.validate_bot_token
signature:
- [BOT_TOKEN, STRING, Bot token to validate]
return_type:
@ -116,19 +108,19 @@
options: |
COMMENT = $$Validate if a string is a proper Slack bot token format.$$
sql: |
SELECT BOT_TOKEN IS NOT NULL
SELECT BOT_TOKEN IS NOT NULL
AND STARTSWITH(BOT_TOKEN, 'xoxb-')
AND LENGTH(BOT_TOKEN) > 20
- name: {{ schema_name }}.validate_channel
signature:
- [CHANNEL, STRING, Channel ID or name to validate]
- [CHANNEL, STRING, Channel ID or name to validate]
return_type:
- "BOOLEAN"
options: |
COMMENT = $$Validate if a string is a proper Slack channel ID or name format.$$
sql: |
SELECT CHANNEL IS NOT NULL
SELECT CHANNEL IS NOT NULL
AND LENGTH(CHANNEL) > 0
AND (
STARTSWITH(CHANNEL, 'C') OR -- Channel ID
@ -137,4 +129,4 @@
STARTSWITH(CHANNEL, '#') -- Channel name
)
{% endmacro %}
{% endmacro %}