Chat and change management#
manent integrates with the tools where releases are discussed and approved:
- notifications in Slack and Microsoft Teams: deploy started and outcome, approval requests and decisions;
- approvals from Slack, with Approve and Reject buttons that respect the same permissions as the API;
- change tickets in ServiceNow or Jira: opened when the deploy starts and closed with its outcome, optionally waiting for the change to be approved before running.
Everything is configured in manent.yml under integrations; change management is enabled per environment in the governance rules. Like callbacks, every delivery is a DBOS step: a deploy resumed after a crash does not lose or duplicate messages, and a failed notification never fails the deploy.
integrations:
public_url: https://manent.example.com # links to the web interface in messages and tickets
language: en # en (default) or it
slack:
bot_token_ref: "vault:secret/data/manent/slack#bot_token"
signing_secret_ref: "vault:secret/data/manent/slack#signing_secret"
identities:
U024BE7LH: {subject: "oidc:alice", groups: [cab]}
# email_identity: "oidc:{email}"
notifications:
- name: prod
applications: ["*"]
environments: [prod]
slack: {channel: C0123456789}
- name: cab
applications: ["*"]
environments: ["prod*"]
events: [approval]
teams: {webhook_ref: "vault:secret/data/manent/teams#cab_webhook"}
change:
provider: servicenow
servicenow:
url: https://acme.service-now.com
username: manent
password_ref: "vault:secret/data/manent/servicenow#password"
fields: {assignment_group: "Release Management", cmdb_ci: "{application}"}
governance:
rules:
- name: prod
applications: ["*"]
environments: [prod]
approvals: {required: 1}
change: {approval: true, timeout: 72h}
Notifications#
Each entry in integrations.notifications is a destination for a set of applications and environments (patterns with *). A deploy is sent to all the destinations that match it.
| Key | Description |
|---|---|
name |
Lower case, digits and -. It appears in the DBOS step names (notify:<name>:<event>). |
applications, environments |
Required, "*" for all. |
events |
deployment (start and outcome) and/or approval (request and outcome). Default both. |
dry_run |
true to also notify dry-runs (default no). |
slack.channel |
Channel ID or name, with the bot token: the start message is updated with the outcome, and approval requests have buttons. |
slack.webhook_ref |
Instead of the channel: secret with the URL of an incoming webhook. One message per event, no buttons. |
teams.webhook_ref |
Secret with the URL of a Teams webhook: a flow of the Workflows app ("Post to a channel when a webhook request is received") or a channel webhook. Messages are Adaptive Cards. |
Messages report application, environment, version, who requested the deploy, the change ticket and, for failures, the error and the outcome of the automatic rollback. With public_url they link to the deploy page in the web interface.
The destinations of a deploy are chosen when it is enqueued and saved with the request, like the plan: changing integrations.notifications does not alter deploys already enqueued or recurring schedules already created. A destination removed from the configuration simply stops receiving messages.
Slack app#
- Create an app at api.slack.com/apps with the bot scope
chat:write(andusers:read.emailif you useemail_identity), install it in the workspace and invite the bot to the channels. - Save the Bot User OAuth Token (
xoxb-…) and the Signing Secret in the secret store and reference them inbot_token_refandsigning_secret_ref. - For approvals, enable Interactivity and set the Request URL to
https://<manent>/integrations/slack/interactions. The address must be reachable from Slack.
Approvals from chat#
When a deploy needs approvals, the request reaches the destinations with approval events.
Slack. The message has Approve and Reject buttons. A click reaches /integrations/slack/interactions, which:
- verifies Slack's signature (
X-Slack-Signature, HMAC with the signing secret) and rejects requests older than 5 minutes; - finds the user's manent identity: first in
slack.identities(Slack user ID →subjectandgroups), otherwise, withemail_identity, from the email in the Slack profile (oidc:{email}becomesoidc:alice@example.com); - records the decision as that identity, through the same permission checks as the API: the
deployment.approvepermission on the application and environment, and the ban on approving your own deploy; - replies to the user with a message only they can see: decision recorded, or why it was refused.
The channel message is updated when the approval ends (approved, rejected or expired): the buttons disappear and the decisions are listed. A user not linked to an identity cannot decide anything.
The mapping is part of the security
Whoever is linked to oidc:alice in slack.identities approves as Alice. Keep the list in the configuration managed by the operators, and prefer email_identity only if the emails in Slack are those of your identity provider. Without the signing secret the endpoint is not registered.
Teams. Teams webhooks cannot receive clicks: the card has a Review in manent button that opens the deploy in the web interface, where the user logs in and decides with the same rules. Interactive buttons in Teams would need a bot registered in Azure.
Change management#
With change in a governance rule, every real deploy of those applications and environments (not dry-runs) has a change ticket:
- Opening. When the deploy starts, the
change:openstep looks for the deploy's ticket and creates it if it does not exist, then moves it to implementation. The ticket is found by the deploy ID (correlation_idin ServiceNow, themanent-<id>label in Jira), so retries and recoveries never create a second one. Without a ticket the deploy does not start. - Closing. At the end the
change:closestep records the outcome (and the rollback, if any) and closes the ticket. An error at this point is logged: the deploy has already finished.
The ticket number and link appear in the deploy status (change), in the CLI, in the web interface and in the chat messages.
Waiting for the change approval#
With change: {approval: true} the deploy also waits for the change to be approved in the ITSM system:
- the ticket is opened when the deploy is requested, in the approval workflow, which takes no worker slots;
- manent reads its state at growing intervals, from
integrations.change.poll_interval(default 1 minute) up to 5 minutes; - the deploy starts when both conditions are met: the manent approvals required by
approvals(if any) and the approved change. A change rejected or cancelled in the ITSM rejects the deploy, with a decision named after the ticket (servicenow:CHG0031337); - the wait expires after
change.timeout(default 72 hours) orapprovals.timeout, whichever is longer.
A change already approved when it is created (a pre-approved standard change, for example) does not make the deploy wait.
governance.rules[].change |
Default | Description |
|---|---|---|
approval |
false |
Wait for the change approval in the ITSM system. |
timeout |
72h |
Maximum wait. |
ServiceNow#
The Table API on change_request, with basic authentication (username, password_ref) or an OAuth token (token_ref).
integrations.change.servicenow |
Default | Description |
|---|---|---|
url |
Instance address. | |
table |
change_request |
Table of the changes. |
fields |
Extra fields of the ticket (type, assignment_group, cmdb_ci, category…). Values accept {application}, {environment}, {version}, {artifact}, {deployment}, {requested_by}. correlation_id and correlation_display are set by manent and refused here. |
|
start_state |
-1 (Implement) |
State set when the deploy starts; "" to leave it unchanged. |
close_states |
["0", "3"] (Review, Closed) |
States set in order at the end. |
close_codes |
success: successful, failure: unsuccessful |
close_code for each outcome; close_notes describes it. |
The approval is read from the approval field (approved, rejected); a cancelled change (state 4) counts as rejected. If your state model does not allow the transitions, adapt start_state and close_states: a refused start is logged and does not block the deploy.
The manent user needs permission to read, create and update records of the table (for example the itil role, or a dedicated role with ACLs on change_request).
Jira#
The REST API v2, on Jira Cloud (username with the email and an API token in token_ref) or Jira Data Center (only token_ref, a personal access token).
integrations.change.jira |
Description |
|---|---|
url, project, issue_type |
Where to create the issue (for example project CHG, type Change). |
fields |
Extra fields, with JSON values and the same placeholders as ServiceNow (for example components: [{name: "{application}"}]). labels (a list of strings) are added to manent's manent and manent-<id>; project and issuetype are refused: use project and issue_type. |
approved_statuses, rejected_statuses |
Statuses that approve or reject the change. Required with approval: true. |
transitions |
Transition names: start (deploy started), success and failure (end). Missing transitions are skipped. |
At the end manent adds a comment with the outcome and applies the transition. Jira Service Management approvals are read through the issue status: the approval step of the workflow moves the issue to one of the approved_statuses.
Reliability#
- Notifications and change operations are DBOS steps with retries (
callbacks.max_retriesfor notifications, 3 for changes). 4xx errors from the ITSM (except 408 and 429) are permanent and not retried. - Destinations and change rules are fixed in the request: a configuration change during a recovery does not change the sequence of steps of running workflows.
- Webhook URLs and tokens are read from the secret store at every use and never appear in logs, outputs or messages.
- Redirects are not followed, so credentials never reach another host.