This service enables sending messages into the HMRC Digital workspace on Slack.
The service provides 2 ways to send messages:
POST /notification # (sync) uses legacy incoming webhooks (DEPRECATED: Will be removed on 01/09/2025 – use /v2/notification)
POST /v2/notification # (async) uses a queue and PlatOps Bot (recommended)
GET /v2/:msgId/status # retrieve status of queued message
Both endpoints require a channelLookup in order to identify the correct channel for the message to be posted to.
Can be one of:
github-repository - will attempt to find the channel for the team that owns the repository.
{
"by" : "github-repository",
"repositoryName" : "name-of-a-repo"
}service - will attempt to find the channel for the team that owns the service.
{
"by" : "service",
"serviceName" : "name-of-a-service"
}github-team - will attempt to find the channel for the GitHub team.
{
"by" : "github-team",
"teamName" : "name-of-a-github-team"
}slack-channel - will attempt to send the message to all channels in the array.
{
"by" : "slack-channel",
"slackChannels" : [
"channel1",
"channel2"
]
}teams-of-github-user - will attempt to send the message to the channel of the team the user belongs to.
{
"by" : "teams-of-github-user",
"githubUsername" : "a-github-username"
}teams-of-ldap-user - will attempt to send the message to the channel of the team the user belongs to.
{
"by" : "teams-of-ldap-user",
"ldapUsername" : "an-ldap-username"
}
⚠️ This endpoint is deprecated and will be removed on 01/09/2025. Please usePOST /v2/notificationinstead.
This endpoint uses Basic Auth for access control. If you want to use it please contact team PlatOps.
The list of users that are able to use the service is predefined by an array in the config:
auth {
authorizedServices = [
{
name = test
password = "dGVzdA=="
displayName = "My Bot"
userEmoji = ":male-mechanic:"
}
]
}
Where:
nameis the usernamepasswordis a base64 encoded password for the user- Optional:
displayNameis a friendly name to use for sending messages as. If not set, will usenameinstead - Optional:
userEmojiis the icon to use for when sending messages for this user
Please note that omitting -n will result in a new line character as a part of the base64 encoded string. Where this is unintentional, the password from the basic auth header will not match resulting in a 401 auth failed response.
echo -n "password" | base64
If you would like to add a new user that is able to send Slack notifications then you will need to submit a PR to the following repos:
- https://github.com/hmrc/app-config-platapps-labs/blob/master/slack-notifications.yaml#L73-L74
- https://github.com/hmrc/app-config-platapps-live/blob/master/slack-notifications.yaml#L75-L76
Remember to base64 and then encrypt the passwords (as described in the configs above)
Once we receive the PR we will review, before redeploying the app.
N.B. This only applies to users within the HMRC organisation on github
Sends Slack messages to all teams contributing to a repo as shown in The Catalogue. If a repository defines owners explicitly in the 'repository.yaml' file, Slack message will be sent only to those teams (relevant mostly for shared repos like app-config-*).
Here attachments should be structured as defined in the Slack documentation
Note: channelLookup can be replaced with any of the ones mentioned above, depending on the use case.
POST /slack-notifications/notification
body:
{
"channelLookup" : {
"by" : "github-repository",
"repositoryName" : "name-of-a-repo"
},
"messageDetails" : {
"text" : "message to be posted",
"attachments" : [ // optional
{ "text" : "some-attachment" }
]
}
}
Assuming basic auth credentials for user: foo, pass: bar, i.e.: user:bar (Base64 encoded) = Zm9vOmJhcg==
curl -X POST -H 'Content-type: application/json' -H 'Authorization: Basic Zm9vOmJhcg==' \
--data '{"channelLookup" : { "by" : "github-repository", "repositoryName" : "foo" }, "messageDetails" : { "text" : "Testing if slack-notifications work" } }' \
localhost:8866/slack-notifications/notification
Response will typically have 200 status code and the following details:
{
"successfullySentTo" : [
"channel1",
"channel2"
],
"errors" : [
{
"code" : "error_code_1",
"message" : "Details of a problem"
},
{
"code" : "error_code_2",
"message" : "Details of another problem"
}
],
"exclusions" : [
{
"code" : "exclusion_code",
"message" : "Details of why slack message was not sent"
}
]
}
# error/exclusion codes are stable, messages may change
This endpoint is asynchronous and utilises work-item-repo in order to queue messages for sending at a steady rate of 1 message per channel per second. This is to comply with Slack's rate limit
You can optionally provide a callbackChannel (without the # prefix), where you will be notified if any of the messages you've tried to send end up failing - this is an alternative to querying the /v2/:msgId/status endpoint.
This endpoint uses internal-auth for access control. If you want to use it then you will need to fork internal-auth-config and raise a PR adding your service to the list of grantees for the slack-notifications resource type.
Queues a Slack message to be sent to the channel specified using the chat.postMessage endpoint and returns a msgId
Here text is the text that will be displayed in the desktop notification, think of this like alt text for an image. It will not be displayed in the main body of the message when blocks are present, however it will be used as fallback when blocks fail to render.
blocks can be designed using the Slack Block Kit Builder
attachments can be modelled in the same way, however they are considered legacy - See docs
POST /slack-notifications/v2/notification
headers: Authorization: <internal-auth-token>
body:
{
"channelLookup": {
"by": "slack-channel",
"slackChannels": [
"channel1"
]
},
"displayName": "Example", # username associated with the message
"emoji": ":robot_face:", # acts as the profile picture
"text": "Example message", # plain text, used as fallback message if blocks/attachments can't be rendered
"blocks": [
...
],
"attachments": [
...
],
"callbackChannel": "team-platops-alerts" # optional
}
If the message is queued successfully then you will receive a 202 Accepted with the following body:
{
"msgId": "9013ba0f-68c9-49a1-b508-d7b16159c531"
}This msgId can be used to call:
GET /v2/:msgId/status
There are two statuses, complete and pending:
{
"msgId": "9013ba0f-68c9-49a1-b508-d7b16159c531",
"status": "pending"
}{
"msgId": "9013ba0f-68c9-49a1-b508-d7b16159c531",
"status": "complete",
"result": {
"successfullySentTo" : [
"channel1"
],
"errors" : [],
"exclusions" : []
}
}result shares the same structure as the response for POST /notification
If your message is unable to be queued because of an issue with the channel lookup or a downstream outage you will not receive a msgId and instead just get a 500 Internal Server Error and a result e.g.
{
"successfullySentTo" : [],
"errors" : [
{
"code": "repository_not_found",
"message": "..."
}
],
"exclusions" : []
}| Error Code | Meaning |
|---|---|
| repository_not_found | A repository could not be found |
| teams_not_found_for_repository | The teams responsible for a repository could not be found |
| teams_not_found_for_github_username | No teams could be found for the given github username |
| slack_channel_not_found | The slack channel was not found |
| slack_error | A generic error wrapping an exception coming directly from Slack |
| Exclusion Code | Meaning |
|---|---|
| not_a_real_team | Team is not a real MDTP team with human members |
| not_a_real_github_user | Github user is not a real person, e.g. CI user |
Any URL can be checked against the allow listed domains stored in LinkUtils.scala.
This code is open source software licensed under the Apache 2.0 License