Skip to content

chad-ramey/slack-app-automation

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

22 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Slack App Request Automation

Automates Slack app install request intake for enterprise Slack workspaces. Automatically creates Jira Service Management tickets for every app request, posts a risk assessment based on OAuth scopes, and notifies requesters with ticket details.

Architecture

triggers/
  new_request_trigger.ts     — Real-time: fires on new USLACKBOT messages
  reaction_trigger.ts        — Retroactive: fires on :ticket: reaction
  app_requested_trigger.ts   — (parked: not supported by Deno platform)
workflows/
  new_request_workflow.ts    — Real-time: parse → ticket → risk comment → notify
  emoji_ticket_workflow.ts   — Retroactive: parse → ticket → risk comment → notify
  app_request_workflow.ts    — (parked: for app_requested event)
functions/
  parse_app_request.ts       — Parse app_requested event payload
  parse_channel_message.ts   — Fetch + parse Slackbot message (shared by both active paths)
  create_app_request_ticket.ts — Create Jira JSM ticket
  evaluate_risk.ts           — OAuth scope risk classification (121 scopes, 5 tiers)
  post_risk_comment.ts       — Post risk assessment as Jira comment
  known_apps.ts              — Known app database (internal/external classification)
  notify_requester.ts        — Threaded reply + requester ephemeral with ticket link
tests/
  parse_app_request_test.ts     — 5 tests for event payload parsing
  parse_channel_message_test.ts — 16 tests for Slackbot message parsing
  evaluate_risk_test.ts         — 17 tests for risk scoring
  known_apps_test.ts            — 13 tests for request type detection
manifest.ts                  — App manifest

Request Type Detection

Every request is classified using a hardcoded known apps database populated from your Slack admin export. Apps not in the database default to Internal New.

Type Detection Routing
Workflow Builder Message: "steps in Workflow Builder" Normal approval
Internal New Known app (internal) or not in map Normal approval
Internal Upgrade "previously approved" + internal app Normal approval
External New (Known) Known app (app_directory) Normal approval
External Upgrade "previously approved" + external app Normal approval

Classification is map-only. Slack's "not approved by Slack" flag and marketplace URLs appear on all new apps regardless of whether they are internal or external, so they are not reliable detection signals. Populate known_apps.ts with your org's app export to drive classification.

Intake Paths

Path 1 — Real-time (active): When a new USLACKBOT app request message appears in your app requests channel, the bot automatically parses it, creates a Jira ticket, posts a threaded reply, and sends an ephemeral confirmation to the requester.

Path 2 — Retroactive (active): React with :ticket: on any existing Slackbot app request message. The bot creates a Jira ticket and posts a threaded reply. Useful for backfilling requests that predate the bot and for testing.

Path 3 — Event-driven (parked): app_requested event trigger is not supported by Slack's hosted Deno platform. Code exists but the trigger cannot be created.

Prerequisites

  • Slack CLI (slack command)
  • deno-slack-sdk v2.15.1 (pinned in deno.jsonc)
  • Deno runtime (installed automatically by Slack CLI)
  • Jira Cloud with a JSM service desk project

Setup

1. Configure for your org

Update the hardcoded values in source before deploying:

Value Location What to set
JIRA_BASE_URL create_app_request_ticket.ts, post_risk_comment.ts Your Jira Cloud base URL
SERVICE_DESK_ID create_app_request_ticket.ts Your JSM service desk ID
REQUEST_TYPE_ID create_app_request_ticket.ts Your JSM request type ID
ALERT_CHANNEL_ID notify_requester.ts, create_app_request_ticket.ts, parse_channel_message.ts, parse_app_request.ts Channel ID for your app requests channel
channel_ids reaction_trigger.ts, new_request_trigger.ts Channel ID for your app requests channel

2. Populate the known apps database

functions/known_apps.ts contains a map of known Slack apps keyed by app ID with a source field: "internal" for apps built by your org, "app_directory" for third-party apps from Slack's App Directory.

Export your installed apps from Slack Admin, classify each entry, and populate the map. Apps not in the map default to Internal New at classification time.

3. Deploy

slack env add JIRA_API_EMAIL <service-account-email>
slack env add JIRA_API_TOKEN <api-token>
slack deploy

4. Create triggers

# Real-time — fires on new USLACKBOT messages in your app requests channel
slack trigger create --trigger-def triggers/new_request_trigger.ts

# Retroactive — fires on :ticket: reaction
slack trigger create --trigger-def triggers/reaction_trigger.ts

The bot must be a member of your app requests channel for both triggers to work. Invite it with /invite @Your Bot Name in the channel.

Environment Variables

slack env add JIRA_API_EMAIL <service-account-email>
slack env add JIRA_API_TOKEN <api-token>

All other configuration is hardcoded in source (see Setup above). Secrets never go in code — use slack env add exclusively.

Local Development

slack run

Jira Integration

Ticket creation uses the JSM servicedeskapi/request endpoint, not the standard /rest/api/3/issue endpoint. Using the standard API creates the ticket but leaves the Request Type field empty. The JSM endpoint requires the X-ExperimentalApi: opt-in header.

Field Value
Summary Slack App Request (Type) - {app_name} - requested by {user}
Reporter The Slack user who requested the app (via raiseOnBehalfOf)
Assignee None (goes to open queue)
API JSM POST /rest/servicedeskapi/request

If the requester's email is not a Jira customer, the ticket is created under the service account with an attribution note in the description.

To find your service desk ID and request type ID:

GET https://your-org.atlassian.net/rest/servicedeskapi/servicedesk
GET https://your-org.atlassian.net/rest/servicedeskapi/servicedesk/{id}/requesttype

Slackbot Message Formats

The bot parses two Slackbot message formats:

  1. Standard install: @user would like to install the app AppName on the workspace YourWorkspace
  2. Workflow Builder: @user would like to use AppName steps in Workflow Builder

Both workspace-level and organization-level requests are supported.

Risk Assessment

After creating a Jira ticket, the bot posts a risk assessment comment based on the app's requested OAuth scopes. 121 Slack OAuth scopes are classified across 5 tiers.

The comment includes:

  • Total risk score and overall tier
  • Scopes grouped by risk tier (Restricted, High, Medium, Low, Safe)
  • Human-readable description for each scope
  • Recommendation for reviewers

Risk tiers and thresholds:

Tier Score Action
Restricted 10/scope Any admin.* scope — requires security review
High Risk 5/scope Route to security review
Medium Risk 3/scope Manual review recommended
Low Risk 1/scope Auto-approve eligible (internal apps)
Safe 0/scope Auto-approve

Decision thresholds: Score 0–3 = Low risk, 4–10 = Medium risk, >10 = High risk, any Restricted scope = Restricted regardless of total score.

Duplicate Prevention

The emoji trigger checks the message thread before creating a ticket. If a threaded reply from the bot already exists, the workflow halts without creating a duplicate ticket.

Running Tests

deno task test

51 tests total (5 event parsing + 16 channel message parsing + 17 risk scoring + 13 request type detection).

Fast-Follows (Not Built Yet)

  • Auto-approve low-risk internal apps
  • Jira custom field population (risk score, flags as structured fields)
  • /app-request slash command + Block Kit modal
  • Periodic refresh of known apps database from Slack admin export
  • AI-powered recommendations (LLM analysis of scope combinations)

About

Deno/TypeScript Slack hosted app automating the full app install request lifecycle — 5-tier OAuth risk classification, JSM ticket creation, 51 tests

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages