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
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 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:
name
is the usernamepassword
is a base64 encoded password for the user- Optional:
displayName
is a friendly name to use for sending messages as. If not set, will usename
instead - Optional:
userEmoji
is 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